mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
BIG-125: prevent items entries from send amount computed attribute.
This commit is contained in:
@@ -6,7 +6,6 @@ import { Formik, Form } from 'formik';
|
||||
import classNames from 'classnames';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import ExpenseFormHeader from './ExpenseFormHeader';
|
||||
import ExpenseFormBody from './ExpenseFormBody';
|
||||
@@ -25,8 +24,13 @@ import {
|
||||
CreateExpenseFormSchema,
|
||||
EditExpenseFormSchema,
|
||||
} from './ExpenseForm.schema';
|
||||
import { transformErrors, defaultExpense, transformToEditForm } from './utils';
|
||||
import { compose, orderingLinesIndexes } from 'utils';
|
||||
import {
|
||||
transformErrors,
|
||||
defaultExpense,
|
||||
transformToEditForm,
|
||||
transformFormValuesToRequest,
|
||||
} from './utils';
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Expense form.
|
||||
@@ -79,15 +83,10 @@ function ExpenseForm({
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Filter expense entries that has no amount or expense account.
|
||||
const categories = values.categories.filter(
|
||||
(category) => category.amount && category.expense_account_id,
|
||||
);
|
||||
|
||||
const form = {
|
||||
...values,
|
||||
...transformFormValuesToRequest(values),
|
||||
publish: submitPayload.publish,
|
||||
categories: R.compose(orderingLinesIndexes)(categories),
|
||||
};
|
||||
// Handle request success.
|
||||
const handleSuccess = (response) => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
transformToForm,
|
||||
repeatValue,
|
||||
ensureEntriesHasEmptyLine,
|
||||
orderingLinesIndexes
|
||||
} from 'utils';
|
||||
|
||||
const ERROR = {
|
||||
@@ -104,3 +105,25 @@ export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Filter expense entries that has no amount or expense account.
|
||||
*/
|
||||
export const filterNonZeroEntries = (categories) => {
|
||||
return categories.filter(
|
||||
(category) => category.amount && category.expense_account_id,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformes the form values to request body.
|
||||
*/
|
||||
export const transformFormValuesToRequest = (values) => {
|
||||
const categories = filterNonZeroEntries(values.categories);
|
||||
|
||||
return {
|
||||
...values,
|
||||
categories: R.compose(orderingLinesIndexes)(categories),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useMemo } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import * as R from 'ramda';
|
||||
import intl from 'react-intl-universal';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { isEmpty } from 'lodash';
|
||||
@@ -16,13 +15,14 @@ import BillItemsEntriesEditor from './BillItemsEntriesEditor';
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import { ERROR } from 'common/errors';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
import { compose, safeSumBy } from 'utils';
|
||||
import {
|
||||
defaultBill,
|
||||
filterNonZeroEntries,
|
||||
transformToEditForm,
|
||||
transformEntriesToSubmit,
|
||||
transformFormValuesToRequest,
|
||||
handleErrors,
|
||||
} from './utils';
|
||||
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||
|
||||
@@ -55,35 +55,12 @@ function BillForm({
|
||||
[bill, base_currency],
|
||||
);
|
||||
|
||||
// Transform response error to fields.
|
||||
const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERROR.BILL_NUMBER_EXISTS)) {
|
||||
setErrors({
|
||||
bill_number: intl.get('bill_number_exists'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
errors.some(
|
||||
(e) => e.type === ERROR.ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED,
|
||||
)
|
||||
) {
|
||||
setErrors(
|
||||
AppToaster.show({
|
||||
intent: Intent.DANGER,
|
||||
message: 'ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED',
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Handles form submit.
|
||||
const handleFormSubmit = (
|
||||
values,
|
||||
{ setSubmitting, setErrors, resetForm },
|
||||
) => {
|
||||
const entries = values.entries.filter(
|
||||
(item) => item.item_id && item.quantity,
|
||||
);
|
||||
const entries = filterNonZeroEntries(values.entries);
|
||||
const totalQuantity = safeSumBy(entries, 'quantity');
|
||||
|
||||
if (totalQuantity === 0) {
|
||||
@@ -95,9 +72,8 @@ function BillForm({
|
||||
return;
|
||||
}
|
||||
const form = {
|
||||
...values,
|
||||
...transformFormValuesToRequest(values),
|
||||
open: submitPayload.status,
|
||||
entries: transformEntriesToSubmit(entries),
|
||||
};
|
||||
// Handle the request success.
|
||||
const onSuccess = (response) => {
|
||||
|
||||
@@ -41,6 +41,12 @@ export const defaultBill = {
|
||||
entries: [...repeatValue(defaultBillEntry, MIN_LINES_NUMBER)],
|
||||
};
|
||||
|
||||
export const ERRORS = {
|
||||
// Bills
|
||||
BILL_NUMBER_EXISTS: 'BILL.NUMBER.EXISTS',
|
||||
ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED:
|
||||
'ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED',
|
||||
};
|
||||
/**
|
||||
* Transformes the bill to initial values of edit form.
|
||||
*/
|
||||
@@ -70,11 +76,33 @@ export const transformToEditForm = (bill) => {
|
||||
* Transformes bill entries to submit request.
|
||||
*/
|
||||
export const transformEntriesToSubmit = (entries) => {
|
||||
const transformBillEntry = R.curry(transformToForm)(R.__, defaultBillEntry);
|
||||
|
||||
const transformBillEntry = R.compose(
|
||||
R.omit(['amount']),
|
||||
R.curry(transformToForm)(R.__, defaultBillEntry),
|
||||
);
|
||||
return R.compose(orderingLinesIndexes, R.map(transformBillEntry))(entries);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters the givne non-zero entries.
|
||||
*/
|
||||
export const filterNonZeroEntries = (entries) => {
|
||||
return entries.filter((item) => item.item_id && item.quantity);
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes form values to request body.
|
||||
*/
|
||||
export const transformFormValuesToRequest = (values) => {
|
||||
const entries = filterNonZeroEntries(values.entries);
|
||||
|
||||
return {
|
||||
...values,
|
||||
entries: transformEntriesToSubmit(entries),
|
||||
open: false,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle delete errors.
|
||||
*/
|
||||
@@ -118,3 +146,24 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
// Transform response error to fields.
|
||||
export const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERRORS.BILL_NUMBER_EXISTS)) {
|
||||
setErrors({
|
||||
bill_number: intl.get('bill_number_exists'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
errors.some(
|
||||
(e) => e.type === ERRORS.ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED,
|
||||
)
|
||||
) {
|
||||
setErrors(
|
||||
AppToaster.show({
|
||||
intent: Intent.DANGER,
|
||||
message: 'ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED',
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import intl from 'react-intl-universal';
|
||||
import { omit, sumBy, isEmpty } from 'lodash';
|
||||
import { sumBy, isEmpty } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
@@ -23,10 +22,14 @@ import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
import { ERROR } from 'common/errors';
|
||||
import { compose, transactionNumber, orderingLinesIndexes } from 'utils';
|
||||
import { useEstimateFormContext } from './EstimateFormProvider';
|
||||
import { transformToEditForm, defaultEstimate } from './utils';
|
||||
import {
|
||||
transformToEditForm,
|
||||
defaultEstimate,
|
||||
transfromsFormValuesToRequest,
|
||||
handleErrors
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Estimate form.
|
||||
@@ -68,25 +71,9 @@ function EstimateForm({
|
||||
currency_code: base_currency,
|
||||
}),
|
||||
}),
|
||||
[estimate, estimateNumber, estimateIncrementMode],
|
||||
[estimate, estimateNumber, estimateIncrementMode, base_currency],
|
||||
);
|
||||
|
||||
// Transform response errors to fields.
|
||||
const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERROR.ESTIMATE_NUMBER_IS_NOT_UNQIUE)) {
|
||||
setErrors({
|
||||
estimate_number: intl.get('estimate_number_is_not_unqiue'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
errors.some((error) => error.type === ERROR.SALE_ESTIMATE_NO_IS_REQUIRED)
|
||||
) {
|
||||
setErrors({
|
||||
estimate_number: intl.get('estimate.field.error.estimate_number_required'),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handles form submit.
|
||||
const handleFormSubmit = (
|
||||
values,
|
||||
@@ -109,13 +96,10 @@ function EstimateForm({
|
||||
return;
|
||||
}
|
||||
const form = {
|
||||
...omit(values, ['estimate_number_manually', 'estimate_number']),
|
||||
...(values.estimate_number_manually && {
|
||||
estimate_number: values.estimate_number,
|
||||
}),
|
||||
...transfromsFormValuesToRequest(values),
|
||||
delivered: submitPayload.deliver,
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
|
||||
};
|
||||
// Handle the request success.
|
||||
const onSuccess = (response) => {
|
||||
AppToaster.show({
|
||||
message: intl.get(
|
||||
@@ -135,7 +119,7 @@ function EstimateForm({
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle the request error.
|
||||
const onError = ({
|
||||
response: {
|
||||
data: { errors },
|
||||
|
||||
@@ -2,6 +2,8 @@ import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import { omit } from 'lodash';
|
||||
import intl from 'react-intl-universal';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transactionNumber,
|
||||
@@ -37,6 +39,11 @@ export const defaultEstimate = {
|
||||
entries: [...repeatValue(defaultEstimateEntry, MIN_LINES_NUMBER)],
|
||||
};
|
||||
|
||||
const ERRORS = {
|
||||
ESTIMATE_NUMBER_IS_NOT_UNQIUE: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE',
|
||||
SALE_ESTIMATE_NO_IS_REQUIRED: 'SALE_ESTIMATE_NO_IS_REQUIRED',
|
||||
};
|
||||
|
||||
export const transformToEditForm = (estimate) => {
|
||||
const initialEntries = [
|
||||
...estimate.entries.map((estimate) => ({
|
||||
@@ -54,8 +61,8 @@ export const transformToEditForm = (estimate) => {
|
||||
|
||||
return {
|
||||
...transformToForm(estimate, defaultEstimate),
|
||||
entries
|
||||
}
|
||||
entries,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -106,3 +113,41 @@ export const ITEMS_FILTER_ROLES = JSON.stringify([
|
||||
comparator: 'equals',
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* Transform response errors to fields.
|
||||
* @param {*} errors
|
||||
* @param {*} param1
|
||||
*/
|
||||
export const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERRORS.ESTIMATE_NUMBER_IS_NOT_UNQIUE)) {
|
||||
setErrors({
|
||||
estimate_number: intl.get('estimate_number_is_not_unqiue'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
errors.some((error) => error.type === ERRORS.SALE_ESTIMATE_NO_IS_REQUIRED)
|
||||
) {
|
||||
setErrors({
|
||||
estimate_number: intl.get(
|
||||
'estimate.field.error.estimate_number_required',
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform the form values to request body.
|
||||
*/
|
||||
export const transfromsFormValuesToRequest = (values) => {
|
||||
const entries = values.entries.filter(
|
||||
(item) => item.item_id && item.quantity,
|
||||
);
|
||||
return {
|
||||
...omit(values, ['estimate_number_manually', 'estimate_number']),
|
||||
...(values.estimate_number_manually && {
|
||||
estimate_number: values.estimate_number,
|
||||
}),
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['amount']) })),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -25,7 +25,12 @@ import withCurrentOrganization from 'containers/Organization/withCurrentOrganiza
|
||||
import { AppToaster } from 'components';
|
||||
import { compose, orderingLinesIndexes, transactionNumber } from 'utils';
|
||||
import { useInvoiceFormContext } from './InvoiceFormProvider';
|
||||
import { transformToEditForm, defaultInvoice, transformErrors } from './utils';
|
||||
import {
|
||||
transformToEditForm,
|
||||
defaultInvoice,
|
||||
transformErrors,
|
||||
transformValueToRequest,
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Invoice form.
|
||||
@@ -72,7 +77,7 @@ function InvoiceForm({
|
||||
currency_code: base_currency,
|
||||
}),
|
||||
}),
|
||||
[invoice, newInvoice, invoiceNumber, invoiceIncrementMode],
|
||||
[invoice, newInvoice, invoiceNumber, invoiceIncrementMode, base_currency],
|
||||
);
|
||||
|
||||
// Handles form submit.
|
||||
@@ -93,15 +98,13 @@ function InvoiceForm({
|
||||
setSubmitting(false);
|
||||
return;
|
||||
}
|
||||
// Transformes the values of the form to request.
|
||||
const form = {
|
||||
...omit(values, ['invoice_no', 'invoice_no_manually']),
|
||||
...(values.invoice_no_manually && {
|
||||
invoice_no: values.invoice_no,
|
||||
}),
|
||||
...transformValueToRequest(values),
|
||||
delivered: submitPayload.deliver,
|
||||
from_estimate_id: estimateId,
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
|
||||
};
|
||||
|
||||
// Handle the request success.
|
||||
const onSuccess = () => {
|
||||
AppToaster.show({
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
compose,
|
||||
transformToForm,
|
||||
@@ -7,7 +9,6 @@ import {
|
||||
transactionNumber,
|
||||
} from 'utils';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
|
||||
import { defaultFastFieldShouldUpdate } from 'utils';
|
||||
import intl from 'react-intl-universal';
|
||||
@@ -146,3 +147,20 @@ export const ITEMS_FILTER_ROLES_QUERY = JSON.stringify([
|
||||
comparator: 'equals',
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* Transformes the form values to request body values.
|
||||
*/
|
||||
export function transformValueToRequest(values) {
|
||||
const entries = values.entries.filter(
|
||||
(item) => item.item_id && item.quantity,
|
||||
);
|
||||
return {
|
||||
...omit(values, ['invoice_no', 'invoice_no_manually']),
|
||||
...(values.invoice_no_manually && {
|
||||
invoice_no: values.invoice_no,
|
||||
}),
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['amount']) })),
|
||||
delivered: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ import React, { useMemo } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import { omit, sumBy, isEmpty } from 'lodash';
|
||||
import { sumBy, isEmpty } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { ERROR } from 'common/errors';
|
||||
import {
|
||||
EditReceiptFormSchema,
|
||||
CreateReceiptFormSchema,
|
||||
@@ -27,7 +26,12 @@ import withCurrentOrganization from 'containers/Organization/withCurrentOrganiza
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
import { compose, orderingLinesIndexes, transactionNumber } from 'utils';
|
||||
import { transformToEditForm, defaultReceipt } from './utils';
|
||||
import {
|
||||
transformToEditForm,
|
||||
defaultReceipt,
|
||||
handleErrors,
|
||||
transformFormValuesToRequest,
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Receipt form.
|
||||
@@ -76,20 +80,6 @@ function ReceiptForm({
|
||||
[receipt, preferredDepositAccount, nextReceiptNumber, receiptAutoIncrement],
|
||||
);
|
||||
|
||||
// Transform response error to fields.
|
||||
const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERROR.SALE_RECEIPT_NUMBER_NOT_UNIQUE)) {
|
||||
setErrors({
|
||||
receipt_number: intl.get('sale_receipt_number_not_unique'),
|
||||
});
|
||||
}
|
||||
if (errors.some((e) => e.type === ERROR.SALE_RECEIPT_NO_IS_REQUIRED)) {
|
||||
setErrors({
|
||||
receipt_number: intl.get('receipt.field.error.receipt_number_required'),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle the form submit.
|
||||
const handleFormSubmit = (
|
||||
values,
|
||||
@@ -109,13 +99,8 @@ function ReceiptForm({
|
||||
return;
|
||||
}
|
||||
const form = {
|
||||
...omit(values, ['receipt_number_manually', 'receipt_number']),
|
||||
...(values.receipt_number_manually && {
|
||||
receipt_number: values.receipt_number,
|
||||
currency_code: base_currency,
|
||||
}),
|
||||
...transformFormValuesToRequest(values),
|
||||
closed: submitPayload.status,
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
|
||||
};
|
||||
// Handle the request success.
|
||||
const onSuccess = (response) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import intl from 'react-intl-universal';
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transactionNumber,
|
||||
@@ -37,6 +39,11 @@ export const defaultReceipt = {
|
||||
entries: [...repeatValue(defaultReceiptEntry, MIN_LINES_NUMBER)],
|
||||
};
|
||||
|
||||
const ERRORS = {
|
||||
SALE_RECEIPT_NUMBER_NOT_UNIQUE: 'SALE_RECEIPT_NUMBER_NOT_UNIQUE',
|
||||
SALE_RECEIPT_NO_IS_REQUIRED: 'SALE_RECEIPT_NO_IS_REQUIRED',
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform to form in edit mode.
|
||||
*/
|
||||
@@ -99,3 +106,39 @@ export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform response error to fields.
|
||||
*/
|
||||
export const handleErrors = (errors, { setErrors }) => {
|
||||
if (errors.some((e) => e.type === ERRORS.SALE_RECEIPT_NUMBER_NOT_UNIQUE)) {
|
||||
setErrors({
|
||||
receipt_number: intl.get('sale_receipt_number_not_unique'),
|
||||
});
|
||||
}
|
||||
if (errors.some((e) => e.type === ERRORS.SALE_RECEIPT_NO_IS_REQUIRED)) {
|
||||
setErrors({
|
||||
receipt_number: intl.get('receipt.field.error.receipt_number_required'),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the form values to request body.
|
||||
* @param {*} values
|
||||
* @returns
|
||||
*/
|
||||
export const transformFormValuesToRequest = (values) => {
|
||||
const entries = values.entries.filter(
|
||||
(item) => item.item_id && item.quantity,
|
||||
);
|
||||
|
||||
return {
|
||||
...omit(values, ['receipt_number_manually', 'receipt_number']),
|
||||
...(values.receipt_number_manually && {
|
||||
receipt_number: values.receipt_number,
|
||||
}),
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['amount']) })),
|
||||
closed: false,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user