feat(design): fix issues in sidebar design.

feat(sales): reference number auto-increment optimizations.
fix(payments): payment receive/made statement.
This commit is contained in:
a.bouhuolia
2021-03-11 14:29:38 +02:00
parent 59f8010122
commit 30cd6c8a61
62 changed files with 921 additions and 378 deletions

View File

@@ -22,7 +22,7 @@ import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components';
import { ERROR } from 'common/errors';
import { compose, orderingLinesIndexes } from 'utils';
import { compose, transactionNumber, orderingLinesIndexes } from 'utils';
import { useEstimateFormContext } from './EstimateFormProvider';
import { transformToEditForm, defaultEstimate } from './utils';
@@ -33,6 +33,7 @@ function EstimateForm({
// #withSettings
estimateNextNumber,
estimateNumberPrefix,
estimateIncrementMode,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
@@ -44,24 +45,25 @@ function EstimateForm({
editEstimateMutate,
} = useEstimateFormContext();
const estimateNumber = estimateNumberPrefix
? `${estimateNumberPrefix}-${estimateNextNumber}`
: estimateNextNumber;
const estimateNumber = transactionNumber(
estimateNumberPrefix,
estimateNextNumber,
);
// Initial values in create and edit mode.
const initialValues = useMemo(
() => ({
...(!isEmpty(estimate)
? {
...transformToEditForm(estimate),
}
? { ...transformToEditForm(estimate) }
: {
...defaultEstimate,
estimate_number: estimateNumber,
...(estimateIncrementMode) && ({
estimate_number: estimateNumber,
}),
entries: orderingLinesIndexes(defaultEstimate.entries),
}),
}),
[estimate, estimateNumber],
[estimate, estimateNumber, estimateIncrementMode],
);
// Transform response errors to fields.
@@ -98,7 +100,10 @@ function EstimateForm({
return;
}
const form = {
...values,
...omit(values, ['estimate_number_manually', 'estimate_number']),
...(values.estimate_number_manually) && ({
estimate_number: values.estimate_number,
}),
delivered: submitPayload.deliver,
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
};
@@ -134,7 +139,6 @@ function EstimateForm({
}
setSubmitting(false);
};
if (!isNewMode) {
editEstimateMutate([estimate.id, form]).then(onSuccess).catch(onError);
} else {
@@ -174,5 +178,6 @@ export default compose(
withSettings(({ estimatesSettings }) => ({
estimateNextNumber: estimatesSettings?.nextNumber,
estimateNumberPrefix: estimatesSettings?.numberPrefix,
estimateIncrementMode: estimatesSettings?.autoIncrement,
})),
)(EstimateForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import { transactionNumber } from 'utils';
/**
* Estimate form dialogs.
@@ -10,11 +9,9 @@ export default function EstimateFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleEstimateNumberFormConfirm = (values) => {
setFieldValue(
'estimate_number',
transactionNumber(values.number_prefix, values.next_number),
);
const handleEstimateNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('estimate_number', incrementNumber || '');
setFieldValue('estimate_number_manually', manually);
};
return (

View File

@@ -8,7 +8,13 @@ import {
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
import { FastField, ErrorMessage } from 'formik';
import { momentFormatter, compose, tansformDateValue } from 'utils';
import {
momentFormatter,
compose,
tansformDateValue,
inputIntent,
handleDateChange,
} from 'utils';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import {
@@ -19,8 +25,9 @@ import {
} from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { inputIntent, handleDateChange } from 'utils';
import { useObserveEstimateNoSettings } from './utils';
import { useEstimateFormContext } from './EstimateFormProvider';
/**
@@ -29,6 +36,11 @@ import { useEstimateFormContext } from './EstimateFormProvider';
function EstimateFormHeader({
// #withDialogActions
openDialog,
// #withSettings
estimateAutoIncrement,
estimateNumberPrefix,
estimateNextNumber,
}) {
const { customers } = useEstimateFormContext();
@@ -36,6 +48,22 @@ function EstimateFormHeader({
openDialog('estimate-number-form', {});
};
const handleEstimateNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && estimateAutoIncrement) {
openDialog('estimate-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs estimate number settings with the form.
useObserveEstimateNoSettings(estimateNumberPrefix, estimateNextNumber);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -131,7 +159,9 @@ function EstimateFormHeader({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handleEstimateNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -169,4 +199,9 @@ function EstimateFormHeader({
export default compose(
withDialogActions,
withSettings(({ estimatesSettings }) => ({
estimateNextNumber: estimatesSettings?.nextNumber,
estimateNumberPrefix: estimatesSettings?.numberPrefix,
estimateAutoIncrement: estimatesSettings?.autoIncrement,
})),
)(EstimateFormHeader);

View File

@@ -4,7 +4,7 @@ import {
useEstimate,
useCustomers,
useItems,
useSettings,
useSettingsEstimates,
useCreateEstimate,
useEditEstimate
} from 'hooks/query';
@@ -32,7 +32,7 @@ function EstimateFormProvider({ estimateId, ...props }) {
} = useCustomers({ page_size: 10000 });
// Handle fetch settings.
useSettings();
useSettingsEstimates();
// Form submit payload.
const [submitPayload, setSubmitPayload] = React.useState({});

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { repeatValue, transformToForm } from 'utils';
import { transactionNumber, repeatValue, transformToForm } from 'utils';
export const MIN_LINES_NUMBER = 4;
@@ -35,4 +37,16 @@ export const transformToEditForm = (estimate) => ({
Math.max(MIN_LINES_NUMBER - estimate.entries.length, 0),
),
],
});
});
/**
* Syncs estimate number of the settings with the context form.
*/
export const useObserveEstimateNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const estimateNo = transactionNumber(prefix, nextNumber);
setFieldValue('estimate_number', estimateNo);
}, [setFieldValue, prefix, nextNumber]);
}

View File

@@ -33,6 +33,7 @@ function InvoiceForm({
// #withSettings
invoiceNextNumber,
invoiceNumberPrefix,
invoiceIncrementMode,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
@@ -53,7 +54,6 @@ function InvoiceForm({
invoiceNumberPrefix,
invoiceNextNumber,
);
// Form initial values.
const initialValues = useMemo(
() => ({
@@ -61,12 +61,14 @@ function InvoiceForm({
? transformToEditForm(invoice)
: {
...defaultInvoice,
invoice_no: invoiceNumber,
...(invoiceIncrementMode) && ({
invoice_no: invoiceNumber,
}),
entries: orderingLinesIndexes(defaultInvoice.entries),
...newInvoice,
}),
}),
[invoice, newInvoice,invoiceNumber],
[invoice, newInvoice, invoiceNumber, invoiceIncrementMode],
);
// Handles form submit.
@@ -88,7 +90,10 @@ function InvoiceForm({
return;
}
const form = {
...values,
...omit(values, ['invoice_no', 'invoice_no_manually']),
...(values.invoice_no_manually) && ({
invoice_no: values.invoice_no,
}),
delivered: submitPayload.deliver,
from_estimate_id: estimateId,
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
@@ -127,7 +132,6 @@ function InvoiceForm({
}
setSubmitting(false);
};
if (!isEmpty(invoice)) {
editInvoiceMutate([invoice.id, form]).then(onSuccess).catch(onError);
} else {
@@ -144,7 +148,6 @@ function InvoiceForm({
)}
>
<Formik
enableReinitialize={true}
validationSchema={
isNewMode ? CreateInvoiceFormSchema : EditInvoiceFormSchema
}
@@ -169,5 +172,6 @@ export default compose(
withSettings(({ invoiceSettings }) => ({
invoiceNextNumber: invoiceSettings?.nextNumber,
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
invoiceIncrementMode: invoiceSettings?.incrementMode,
})),
)(InvoiceForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
import { useFormikContext } from 'formik';
import { transactionNumber } from 'utils';
/**
* Invoice form dialogs.
@@ -10,15 +9,11 @@ export default function InvoiceFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleInvoiceNumberFormConfirm = (values) => {
debugger;
console.log(values, 'XX');
setFieldValue(
'invoice_no',
transactionNumber(values.number_prefix, values.next_number),
);
const handleInvoiceNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('invoice_no', incrementNumber || '');
setFieldValue('invoice_no_manually', manually);
};
return (
<>
<InvoiceNumberDialog

View File

@@ -6,10 +6,11 @@ import {
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik';
import { FastField, Field, ErrorMessage } from 'formik';
import { FormattedMessage as T } from 'react-intl';
import { momentFormatter, compose, tansformDateValue } from 'utils';
import classNames from 'classnames';
import { useObserveInvoiceNoSettings } from './utils';
import { CLASSES } from 'common/classes';
import {
ContactSelecetList,
@@ -17,8 +18,8 @@ import {
Icon,
InputPrependButton,
} from 'components';
import { useInvoiceFormContext } from './InvoiceFormProvider';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { inputIntent, handleDateChange } from 'utils';
@@ -28,15 +29,40 @@ import { inputIntent, handleDateChange } from 'utils';
function InvoiceFormHeaderFields({
// #withDialogActions
openDialog,
// #withSettings
invoiceAutoIncrement,
invoiceNumberPrefix,
invoiceNextNumber,
}) {
// Invoice form context.
const { customers } = useInvoiceFormContext();
// Handle invoice number changing.
const handleInvoiceNumberChange = () => {
openDialog('invoice-number-form', {});
openDialog('invoice-number-form');
};
// Handle invoice no. field blur.
const handleInvoiceNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && invoiceAutoIncrement) {
openDialog('invoice-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs invoice number settings with form.
useObserveInvoiceNoSettings(
invoiceNumberPrefix,
invoiceNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -45,7 +71,11 @@ function InvoiceFormHeaderFields({
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames('form-group--customer-name', 'form-group--select-list', CLASSES.FILL)}
className={classNames(
'form-group--customer-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
@@ -115,7 +145,7 @@ function InvoiceFormHeaderFields({
</FastField>
{/* ----------- Invoice number ----------- */}
<FastField name={'invoice_no'}>
<Field name={'invoice_no'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'invoice_no'} />}
@@ -127,7 +157,9 @@ function InvoiceFormHeaderFields({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handleInvoiceNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -143,7 +175,7 @@ function InvoiceFormHeaderFields({
</ControlGroup>
</FormGroup>
)}
</FastField>
</Field>
{/* ----------- Reference ----------- */}
<FastField name={'reference'}>
@@ -165,4 +197,9 @@ function InvoiceFormHeaderFields({
export default compose(
withDialogActions,
withSettings(({ invoiceSettings }) => ({
invoiceAutoIncrement: invoiceSettings?.autoIncrement,
invoiceNextNumber: invoiceSettings?.nextNumber,
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
})),
)(InvoiceFormHeaderFields);

View File

@@ -26,6 +26,7 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
enabled: !!invoiceId,
});
// Fetches the estimate by the given id.
const {
data: estimate,
isFetching: isEstimateFetching,

View File

@@ -1,10 +1,19 @@
import React from 'react';
import moment from 'moment';
import { compose, transformToForm, repeatValue } from 'utils';
import { isEmpty } from 'lodash';
import {
compose,
transformToForm,
repeatValue,
transactionNumber,
} from 'utils';
import { updateItemsEntriesTotal } from 'containers/Entries/utils';
import { ERROR } from 'common/errors';
import { useFormikContext } from 'formik';
import { Intent } from '@blueprintjs/core';
import { orderingLinesIndexes } from 'utils';
import { formatMessage } from 'services/intl';
import { ERROR } from 'common/errors';
import { AppToaster } from 'components';
export const MIN_LINES_NUMBER = 4;
@@ -27,6 +36,7 @@ export const defaultInvoice = {
due_date: moment().format('YYYY-MM-DD'),
delivered: '',
invoice_no: '',
invoice_no_manually: false,
reference_no: '',
invoice_message: '',
terms_conditions: '',
@@ -72,4 +82,24 @@ export const transformErrors = (errors, { setErrors }) => {
intent: Intent.DANGER,
});
}
if (
errors.some((error) => error.type === ERROR.SALE_INVOICE_NO_IS_REQUIRED)
) {
setErrors({
invoice_no:
'Invoice number is required, use auto-increment mode or enter manually.',
});
}
};
/**
* Syncs invoice no. settings with form.
*/
export const useObserveInvoiceNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const invoiceNo = transactionNumber(prefix, nextNumber);
setFieldValue('invoice_no', invoiceNo);
}, [setFieldValue, prefix, nextNumber]);
};

View File

@@ -186,7 +186,7 @@ export function useInvoicesTableColumns() {
{
id: 'invoice_no',
Header: formatMessage({ id: 'invoice_no__' }),
accessor: (row) => (row.invoice_no ? `#${row.invoice_no}` : null),
accessor: 'invoice_no',
width: 100,
className: 'invoice_no',
},

View File

@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { Formik, Form } from 'formik';
import { useIntl } from 'react-intl';
import { sumBy, pick, isEmpty } from 'lodash';
import { omit, sumBy, pick, isEmpty } from 'lodash';
import { Intent } from '@blueprintjs/core';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
@@ -23,13 +23,10 @@ import {
CreatePaymentReceiveFormSchema,
} from './PaymentReceiveForm.schema';
import { AppToaster } from 'components';
import { compose } from 'utils';
import { transactionNumber, compose } from 'utils';
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import {
defaultPaymentReceive,
transformToEditForm,
} from './utils';
import { defaultPaymentReceive, transformToEditForm } from './utils';
/**
* Payment Receive form.
@@ -38,6 +35,7 @@ function PaymentReceiveForm({
// #withSettings
paymentReceiveNextNumber,
paymentReceiveNumberPrefix,
paymentReceiveAutoIncrement,
}) {
const history = useHistory();
const { formatMessage } = useIntl();
@@ -54,10 +52,10 @@ function PaymentReceiveForm({
} = usePaymentReceiveFormContext();
// Payment receive number.
const paymentReceiveNumber = paymentReceiveNumberPrefix
? `${paymentReceiveNumberPrefix}-${paymentReceiveNextNumber}`
: paymentReceiveNextNumber;
const nextPaymentNumber = transactionNumber(
paymentReceiveNumberPrefix,
paymentReceiveNextNumber
);
// Form initial values.
const initialValues = useMemo(
() => ({
@@ -65,10 +63,17 @@ function PaymentReceiveForm({
? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage)
: {
...defaultPaymentReceive,
payment_receive_no: paymentReceiveNumber,
...(paymentReceiveAutoIncrement && {
payment_receive_no: nextPaymentNumber,
}),
}),
}),
[paymentReceiveEditPage, paymentReceiveNumber, paymentEntriesEditPage],
[
paymentReceiveEditPage,
nextPaymentNumber,
paymentEntriesEditPage,
paymentReceiveAutoIncrement,
],
);
// Handle form submit.
@@ -98,7 +103,13 @@ function PaymentReceiveForm({
setSubmitting(false);
return;
}
const form = { ...values, entries };
const form = {
...omit(values, ['payment_receive_no_manually', 'payment_receive_no']),
...(values.payment_receive_no_manually) && ({
payment_receive_no: values.payment_receive_no,
}),
entries
};
// Handle request response success.
const onSaved = (response) => {
@@ -120,7 +131,11 @@ function PaymentReceiveForm({
}
};
// Handle request response errors.
const onError = ({ response: { data: { errors } } }) => {
const onError = ({
response: {
data: { errors },
},
}) => {
const getError = (errorType) => errors.find((e) => e.type === errorType);
if (getError('PAYMENT_RECEIVE_NO_EXISTS')) {
@@ -179,5 +194,6 @@ export default compose(
withSettings(({ paymentReceiveSettings }) => ({
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
})),
)(PaymentReceiveForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberDialog';
import { transactionNumber } from 'utils';
/**
* Payment receive form dialogs.
@@ -9,11 +8,9 @@ import { transactionNumber } from 'utils';
export default function PaymentReceiveFormDialogs() {
const { setFieldValue } = useFormikContext();
const handleUpdatePaymentNumber = (values) => {
setFieldValue(
'payment_receive_no',
transactionNumber(values.number_prefix, values.next_number),
);
const handleUpdatePaymentNumber = ({ incrementNumber, manually }) => {
setFieldValue('payment_receive_no', incrementNumber);
setFieldValue('payment_receive_no_manually', manually)
};
return (

View File

@@ -1,7 +1,7 @@
import React, { createContext, useContext } from 'react';
import { DashboardInsider } from 'components';
import {
useSettings,
useSettingsPaymentReceives,
usePaymentReceiveEditPage,
useAccounts,
useCustomers,
@@ -34,7 +34,7 @@ function PaymentReceiveFormProvider({ paymentReceiveId, ...props }) {
const { data: accounts, isFetching: isAccountsFetching } = useAccounts();
// Fetch payment made settings.
const fetchSettings = useSettings();
const fetchSettings = useSettingsPaymentReceives();
// Fetches customers list.
const {

View File

@@ -36,7 +36,11 @@ import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { amountPaymentEntries, fullAmountPaymentEntries } from './utils';
import {
useObservePaymentNoSettings,
amountPaymentEntries,
fullAmountPaymentEntries,
} from './utils';
import { toSafeInteger } from 'lodash';
/**
@@ -47,6 +51,11 @@ function PaymentReceiveHeaderFields({
// #withDialogActions
openDialog,
// #withSettings
paymentReceiveAutoIncrement,
paymentReceiveNumberPrefix,
paymentReceiveNextNumber,
}) {
// Payment receive form context.
const { customers, accounts, isNewMode } = usePaymentReceiveFormContext();
@@ -63,7 +72,6 @@ function PaymentReceiveHeaderFields({
const totalDueAmount = useMemo(() => safeSumBy(entries, 'due_amount'), [
entries,
]);
// Handle receive full-amount link click.
const handleReceiveFullAmountClick = () => {
const newEntries = fullAmountPaymentEntries(entries);
@@ -72,18 +80,36 @@ function PaymentReceiveHeaderFields({
setFieldValue('entries', newEntries);
setFieldValue('full_amount', fullAmount);
};
// Handles the full-amount field blur.
const onFullAmountBlur = (value) => {
const newEntries = amountPaymentEntries(toSafeInteger(value), entries);
setFieldValue('entries', newEntries);
};
// Handle click open payment receive number dialog.
const handleClickOpenDialog = () => {
openDialog('payment-receive-number-form');
};
// Handle payment number field blur.
const handlePaymentNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && paymentReceiveAutoIncrement) {
openDialog('payment-receive-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs payment receive number from settings to the form.
useObservePaymentNoSettings(
paymentReceiveNumberPrefix,
paymentReceiveNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------------- Customer name ------------- */}
@@ -194,7 +220,9 @@ function PaymentReceiveHeaderFields({
<InputGroup
intent={inputIntent({ error, touched })}
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handlePaymentNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -263,8 +291,11 @@ function PaymentReceiveHeaderFields({
}
export default compose(
withSettings(({ organizationSettings }) => ({
withSettings(({ organizationSettings, paymentReceiveSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency,
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
})),
withDialogActions,
)(PaymentReceiveHeaderFields);

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { transformToForm, safeSumBy } from 'utils';
import { transactionNumber, transformToForm, safeSumBy } from 'utils';
// Default payment receive entry.
export const defaultPaymentReceiveEntry = {
@@ -18,7 +20,7 @@ export const defaultPaymentReceive = {
payment_date: moment(new Date()).format('YYYY-MM-DD'),
reference_no: '',
payment_receive_no: '',
description: '',
statement: '',
full_amount: '',
entries: [],
};
@@ -81,4 +83,16 @@ export const fullAmountPaymentEntries = (entries) => {
...item,
payment_amount: item.due_amount,
}));
}
}
/**
* Syncs payment receive number settings with form.
*/
export const useObservePaymentNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const invoiceNo = transactionNumber(prefix, nextNumber);
setFieldValue('payment_receive_no', invoiceNo);
}, [setFieldValue, prefix, nextNumber]);
};

View File

@@ -10,7 +10,7 @@ import { CLASSES } from 'common/classes';
import { ERROR } from 'common/errors';
import {
EditReceiptFormSchema,
CreateReceiptFormSchema,
CreateReceiptFormSchema,
} from './ReceiptForm.schema';
import { useReceiptFormContext } from './ReceiptFormProvider';
@@ -25,13 +25,8 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components';
import {
compose,
orderingLinesIndexes,
transactionNumber,
} from 'utils';
import { transformToEditForm, defaultReceipt } from './utils'
import { compose, orderingLinesIndexes, transactionNumber } from 'utils';
import { transformToEditForm, defaultReceipt } from './utils';
/**
* Receipt form.
@@ -40,6 +35,7 @@ function ReceiptForm({
// #withSettings
receiptNextNumber,
receiptNumberPrefix,
receiptAutoIncrement,
preferredDepositAccount,
}) {
const { formatMessage } = useIntl();
@@ -47,16 +43,15 @@ function ReceiptForm({
// Receipt form context.
const {
receiptId,
receipt,
editReceiptMutate,
createReceiptMutate,
submitPayload,
isNewMode
isNewMode,
} = useReceiptFormContext();
// The next receipt number.
const receiptNumber = transactionNumber(
const nextReceiptNumber = transactionNumber(
receiptNumberPrefix,
receiptNextNumber,
);
@@ -67,12 +62,14 @@ function ReceiptForm({
? transformToEditForm(receipt)
: {
...defaultReceipt,
receipt_number: receiptNumber,
...(receiptAutoIncrement && {
receipt_number: nextReceiptNumber,
}),
deposit_account_id: parseInt(preferredDepositAccount),
entries: orderingLinesIndexes(defaultReceipt.entries),
}),
}),
[receipt, preferredDepositAccount, receiptNumber],
[receipt, preferredDepositAccount, nextReceiptNumber, receiptAutoIncrement],
);
// Transform response error to fields.
@@ -107,9 +104,12 @@ function ReceiptForm({
return;
}
const form = {
...values,
...omit(values, ['receipt_number_manually', 'receipt_number']),
...(values.receipt_number_manually) && ({
receipt_number: values.receipt_number,
}),
closed: submitPayload.status,
entries: entries.map((entry) => ({ ...omit(entry, ['total']), })),
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
};
// Handle the request success.
const onSuccess = (response) => {
@@ -135,13 +135,16 @@ function ReceiptForm({
};
// Handle the request error.
const onError = ({response:{data:{errors}}}) => {
if(errors){
const onError = ({
response: {
data: { errors },
},
}) => {
if (errors) {
handleErrors(errors, { setErrors });
}
setSubmitting(false);
};
if (!isNewMode) {
editReceiptMutate([receipt.id, form]).then(onSuccess).catch(onError);
} else {
@@ -182,6 +185,7 @@ export default compose(
withSettings(({ receiptSettings }) => ({
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
receiptAutoIncrement: receiptSettings?.autoIncrement,
preferredDepositAccount: receiptSettings?.preferredDepositAccount,
})),
)(ReceiptForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import { transactionNumber } from 'utils';
/**
* Receipt form dialogs.
@@ -10,11 +9,9 @@ export default function ReceiptFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the receipt number form submit confirm.
const handleReceiptNumberFormConfirm = (values) => {
setFieldValue(
'receipt_number',
transactionNumber(values.number_prefix, values.next_number),
);
const handleReceiptNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('receipt_number', incrementNumber || '');
setFieldValue('receipt_number_manually', manually);
};
return (

View File

@@ -5,12 +5,10 @@ import {
Position,
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames';
import { FastField, ErrorMessage } from 'formik';
import { CLASSES } from 'common/classes';
import {
AccountsSelectList,
@@ -19,17 +17,17 @@ import {
Icon,
InputPrependButton,
} from 'components';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
import {
momentFormatter,
compose,
tansformDateValue,
saveInvoke,
handleDateChange,
inputIntent,
} from 'utils';
import { useReceiptFormContext } from './ReceiptFormProvider';
import { useObserveReceiptNoSettings } from './utils';
/**
* Receipt form header fields.
@@ -40,6 +38,11 @@ function ReceiptFormHeader({
// #ownProps
onReceiptNumberChanged,
// #withSettings
receiptAutoIncrement,
receiptNextNumber,
receiptNumberPrefix,
}) {
const { accounts, customers } = useReceiptFormContext();
@@ -47,10 +50,25 @@ function ReceiptFormHeader({
openDialog('receipt-number-form', {});
}, [openDialog]);
const handleReceiptNumberChanged = (event) => {
saveInvoke(onReceiptNumberChanged, event.currentTarget.value);
const handleReceiptNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && receiptAutoIncrement) {
openDialog('receipt-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Synsc receipt number settings with the form.
useObserveReceiptNoSettings(
receiptNumberPrefix,
receiptNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -129,7 +147,7 @@ function ReceiptFormHeader({
{/* ----------- Receipt number ----------- */}
<FastField name={'receipt_number'}>
{({ field, meta: { error, touched } }) => (
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'receipt'} />}
inline={true}
@@ -141,8 +159,9 @@ function ReceiptFormHeader({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
onBlur={handleReceiptNumberChanged}
value={field.value}
asyncControl={true}
onBlur={handleReceiptNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -183,4 +202,9 @@ function ReceiptFormHeader({
export default compose(
withDialogActions,
withSettings(({ receiptSettings }) => ({
receiptAutoIncrement: receiptSettings?.autoIncrement,
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
})),
)(ReceiptFormHeader);

View File

@@ -3,7 +3,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import {
useReceipt,
useAccounts,
useSettings,
useSettingsReceipts,
useCustomers,
useItems,
useCreateReceipt,
@@ -39,7 +39,7 @@ function ReceiptFormProvider({ receiptId, ...props }) {
} = useItems({ page_size: 10000 });
// Fetch receipt settings.
const { isLoading: isSettingLoading } = useSettings();
const { isLoading: isSettingLoading } = useSettingsReceipts();
const { mutateAsync: createReceiptMutate } = useCreateReceipt();
const { mutateAsync: editReceiptMutate } = useEditReceipt();

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { repeatValue, transformToForm } from 'utils';
import { transactionNumber, repeatValue, transformToForm } from 'utils';
export const MIN_LINES_NUMBER = 4;
@@ -39,3 +41,13 @@ export const transformToEditForm = (receipt) => ({
),
],
});
export const useObserveReceiptNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const receiptNo = transactionNumber(prefix, nextNumber);
setFieldValue('receipt_number', receiptNo);
}, [setFieldValue, prefix, nextNumber]);
}

View File

@@ -114,8 +114,7 @@ export function useReceiptsTableColumns() {
{
id: 'receipt_number',
Header: formatMessage({ id: 'receipt_number' }),
accessor: (row) =>
row.receipt_number ? `#${row.receipt_number}` : null,
accessor: 'receipt_number',
width: 140,
className: 'receipt_number',
},
@@ -138,7 +137,7 @@ export function useReceiptsTableColumns() {
Header: formatMessage({ id: 'status' }),
accessor: StatusAccessor,
width: 140,
className: 'amount',
className: 'status',
},
{
id: 'reference_no',