mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
fix: BIG-148 items entries ordered by index.
This commit is contained in:
@@ -50,7 +50,6 @@ function InventoryAdjustmentFloatingActions({
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
disabled={isSubmitting}
|
|
||||||
loading={isSubmitting && !submitPayload.publish}
|
loading={isSubmitting && !submitPayload.publish}
|
||||||
style={{ minWidth: '75px' }}
|
style={{ minWidth: '75px' }}
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -61,7 +60,6 @@ function InventoryAdjustmentFloatingActions({
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
disabled={isSubmitting}
|
|
||||||
loading={isSubmitting && submitPayload.publish}
|
loading={isSubmitting && submitPayload.publish}
|
||||||
style={{ minWidth: '75px' }}
|
style={{ minWidth: '75px' }}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -14,19 +14,12 @@ const PaymentMadeDetailContext = React.createContext();
|
|||||||
*/
|
*/
|
||||||
function PaymentMadeDetailProvider({ paymentMadeId, ...props }) {
|
function PaymentMadeDetailProvider({ paymentMadeId, ...props }) {
|
||||||
// Handle fetch specific payment made details.
|
// Handle fetch specific payment made details.
|
||||||
const { data: paymentMade, isLoading: isPaymentMadeLoading } =
|
const { data: paymentMade, isLoading: isPaymentMadeLoading } = usePaymentMade(
|
||||||
usePaymentMade(paymentMadeId, {
|
paymentMadeId,
|
||||||
|
{
|
||||||
enabled: !!paymentMadeId,
|
enabled: !!paymentMadeId,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
// Handle fetch specific payment made details.
|
|
||||||
const {
|
|
||||||
data: { entries: paymentEntries },
|
|
||||||
isLoading: isPaymentLoading,
|
|
||||||
} = usePaymentMadeEditPage(paymentMadeId, {
|
|
||||||
enabled: !!paymentMadeId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle fetch transaction by reference.
|
// Handle fetch transaction by reference.
|
||||||
const {
|
const {
|
||||||
data: { transactions },
|
data: { transactions },
|
||||||
@@ -44,11 +37,9 @@ function PaymentMadeDetailProvider({ paymentMadeId, ...props }) {
|
|||||||
transactions,
|
transactions,
|
||||||
paymentMadeId,
|
paymentMadeId,
|
||||||
paymentMade,
|
paymentMade,
|
||||||
paymentEntries,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loading =
|
const loading = isTransactionLoading || isPaymentMadeLoading;
|
||||||
isTransactionLoading || isPaymentMadeLoading || isPaymentLoading;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerLoading loading={loading}>
|
<DrawerLoading loading={loading}>
|
||||||
|
|||||||
@@ -12,18 +12,17 @@ import PaymentDrawerCls from './PaymentMadeDrawer.module.scss';
|
|||||||
* Payment made read-only details table.
|
* Payment made read-only details table.
|
||||||
*/
|
*/
|
||||||
export default function PaymentMadeDetailTable() {
|
export default function PaymentMadeDetailTable() {
|
||||||
|
|
||||||
// Retrieve payment made entries columns.
|
// Retrieve payment made entries columns.
|
||||||
const columns = usePaymentMadeEntriesColumns();
|
const columns = usePaymentMadeEntriesColumns();
|
||||||
|
|
||||||
// Payment made details context.
|
// Payment made details context.
|
||||||
const { paymentEntries } = usePaymentMadeDetailContext();
|
const { paymentMade } = usePaymentMadeDetailContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(PaymentDrawerCls.detail_panel_table)}>
|
<div className={clsx(PaymentDrawerCls.detail_panel_table)}>
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={paymentEntries}
|
data={paymentMade.entries}
|
||||||
className={'table-constrant'}
|
className={'table-constrant'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import { useEditableItemsEntriesColumns } from './components';
|
|||||||
import {
|
import {
|
||||||
saveInvoke,
|
saveInvoke,
|
||||||
compose,
|
compose,
|
||||||
updateTableCell,
|
|
||||||
updateMinEntriesLines,
|
updateMinEntriesLines,
|
||||||
updateAutoAddNewLine,
|
|
||||||
updateRemoveLineByIndex,
|
updateRemoveLineByIndex,
|
||||||
} from 'utils';
|
} from 'utils';
|
||||||
import { updateItemsEntriesTotal, useFetchItemRow } from './utils';
|
import {
|
||||||
import { updateTableRow } from '../../utils';
|
useFetchItemRow,
|
||||||
|
composeRowsOnNewRow,
|
||||||
|
composeRowsOnEditCell,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Items entries table.
|
* Items entries table.
|
||||||
@@ -50,10 +51,7 @@ function ItemsEntriesTable({
|
|||||||
itemType,
|
itemType,
|
||||||
notifyNewRow: (newRow, rowIndex) => {
|
notifyNewRow: (newRow, rowIndex) => {
|
||||||
// Update the rate, description and quantity data of the row.
|
// Update the rate, description and quantity data of the row.
|
||||||
const newRows = compose(
|
const newRows = composeRowsOnNewRow(rowIndex, newRow, rows);
|
||||||
updateItemsEntriesTotal,
|
|
||||||
updateTableRow(rowIndex, newRow),
|
|
||||||
)(rows);
|
|
||||||
|
|
||||||
setRows(newRows);
|
setRows(newRows);
|
||||||
onUpdateData(newRows);
|
onUpdateData(newRows);
|
||||||
@@ -66,11 +64,8 @@ function ItemsEntriesTable({
|
|||||||
if (columnId === 'item_id') {
|
if (columnId === 'item_id') {
|
||||||
setItemRow({ rowIndex, columnId, itemId: value });
|
setItemRow({ rowIndex, columnId, itemId: value });
|
||||||
}
|
}
|
||||||
const newRows = compose(
|
const composeEditCell = composeRowsOnEditCell(rowIndex, columnId);
|
||||||
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
const newRows = composeEditCell(value, defaultEntry, rows);
|
||||||
updateItemsEntriesTotal,
|
|
||||||
updateTableCell(rowIndex, columnId, value),
|
|
||||||
)(rows);
|
|
||||||
|
|
||||||
setRows(newRows);
|
setRows(newRows);
|
||||||
onUpdateData(newRows);
|
onUpdateData(newRows);
|
||||||
|
|||||||
@@ -3,7 +3,15 @@ import * as R from 'ramda';
|
|||||||
import { sumBy, isEmpty, last } from 'lodash';
|
import { sumBy, isEmpty, last } from 'lodash';
|
||||||
|
|
||||||
import { useItem } from 'hooks/query';
|
import { useItem } from 'hooks/query';
|
||||||
import { toSafeNumber, saveInvoke } from 'utils';
|
import {
|
||||||
|
toSafeNumber,
|
||||||
|
saveInvoke,
|
||||||
|
compose,
|
||||||
|
updateTableCell,
|
||||||
|
updateAutoAddNewLine,
|
||||||
|
orderingLinesIndexes,
|
||||||
|
updateTableRow,
|
||||||
|
} from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve item entry total from the given rate, quantity and discount.
|
* Retrieve item entry total from the given rate, quantity and discount.
|
||||||
@@ -131,3 +139,28 @@ export function useFetchItemRow({ landedCost, itemType, notifyNewRow }) {
|
|||||||
cellsLoading,
|
cellsLoading,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose table rows when edit specific row index of table rows.
|
||||||
|
*/
|
||||||
|
export const composeRowsOnEditCell = R.curry(
|
||||||
|
(rowIndex, columnId, value, defaultEntry, rows) => {
|
||||||
|
return compose(
|
||||||
|
orderingLinesIndexes,
|
||||||
|
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
||||||
|
updateItemsEntriesTotal,
|
||||||
|
updateTableCell(rowIndex, columnId, value),
|
||||||
|
)(rows);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose table rows when insert a new row to table rows.
|
||||||
|
*/
|
||||||
|
export const composeRowsOnNewRow = R.curry((rowIndex, newRow, rows) => {
|
||||||
|
return compose(
|
||||||
|
orderingLinesIndexes,
|
||||||
|
updateItemsEntriesTotal,
|
||||||
|
updateTableRow(rowIndex, newRow),
|
||||||
|
)(rows);
|
||||||
|
});
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export function useGeneralLedgerTableColumns() {
|
|||||||
return row.date;
|
return row.date;
|
||||||
},
|
},
|
||||||
className: 'date',
|
className: 'date',
|
||||||
|
textOverview: true,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ import ItemFormBody from './ItemFormBody';
|
|||||||
import ItemFormFloatingActions from './ItemFormFloatingActions';
|
import ItemFormFloatingActions from './ItemFormFloatingActions';
|
||||||
import ItemFormInventorySection from './ItemFormInventorySection';
|
import ItemFormInventorySection from './ItemFormInventorySection';
|
||||||
|
|
||||||
import { useItemFormInitialValues } from './utils';
|
import {
|
||||||
|
transformSubmitRequestErrors,
|
||||||
|
useItemFormInitialValues,
|
||||||
|
} from './utils';
|
||||||
import { EditItemFormSchema, CreateItemFormSchema } from './ItemForm.schema';
|
import { EditItemFormSchema, CreateItemFormSchema } from './ItemForm.schema';
|
||||||
|
|
||||||
import { useItemFormContext } from './ItemFormProvider';
|
import { useItemFormContext } from './ItemFormProvider';
|
||||||
@@ -40,27 +43,6 @@ export default function ItemForm() {
|
|||||||
// Initial values in create and edit mode.
|
// Initial values in create and edit mode.
|
||||||
const initialValues = useItemFormInitialValues(item);
|
const initialValues = useItemFormInitialValues(item);
|
||||||
|
|
||||||
// Transform API errors.
|
|
||||||
const transformApiErrors = (error) => {
|
|
||||||
const {
|
|
||||||
response: {
|
|
||||||
data: { errors },
|
|
||||||
},
|
|
||||||
} = error;
|
|
||||||
const fields = {};
|
|
||||||
|
|
||||||
if (errors.find((e) => e.type === 'ITEM.NAME.ALREADY.EXISTS')) {
|
|
||||||
fields.name = intl.get('the_name_used_before');
|
|
||||||
}
|
|
||||||
if (errors.find((e) => e.type === 'INVENTORY_ACCOUNT_CANNOT_MODIFIED')) {
|
|
||||||
AppToaster.show({
|
|
||||||
message: intl.get('cannot_change_item_inventory_account'),
|
|
||||||
intent: Intent.DANGER,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handles the form submit.
|
// Handles the form submit.
|
||||||
const handleFormSubmit = (
|
const handleFormSubmit = (
|
||||||
values,
|
values,
|
||||||
@@ -94,7 +76,7 @@ export default function ItemForm() {
|
|||||||
const onError = (errors) => {
|
const onError = (errors) => {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
const _errors = transformApiErrors(errors);
|
const _errors = transformSubmitRequestErrors(errors);
|
||||||
setErrors({ ..._errors });
|
setErrors({ ..._errors });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, createContext, useState } from 'react';
|
import React, { useEffect, createContext, useState } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||||
import {
|
import {
|
||||||
useItem,
|
useItem,
|
||||||
@@ -11,6 +12,7 @@ import {
|
|||||||
useAccounts,
|
useAccounts,
|
||||||
} from 'hooks/query';
|
} from 'hooks/query';
|
||||||
import { useDashboardPageTitle } from 'hooks/state';
|
import { useDashboardPageTitle } from 'hooks/state';
|
||||||
|
import { useWatchItemError } from './utils';
|
||||||
|
|
||||||
const ItemFormContext = createContext();
|
const ItemFormContext = createContext();
|
||||||
|
|
||||||
@@ -32,12 +34,14 @@ function ItemFormProvider({ itemId, ...props }) {
|
|||||||
} = useItemsCategories();
|
} = useItemsCategories();
|
||||||
|
|
||||||
// Fetches the given item details.
|
// Fetches the given item details.
|
||||||
const { isLoading: isItemLoading, data: item } = useItem(
|
const itemQuery = useItem(itemId || duplicateId, {
|
||||||
itemId || duplicateId,
|
enabled: !!itemId || !!duplicateId,
|
||||||
{
|
});
|
||||||
enabled: !!itemId || !!duplicateId,
|
|
||||||
},
|
const { isLoading: isItemLoading, data: item } = itemQuery;
|
||||||
);
|
|
||||||
|
// Watches and handles item not found response error.
|
||||||
|
useWatchItemError(itemQuery);
|
||||||
|
|
||||||
// Fetches item settings.
|
// Fetches item settings.
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import { defaultTo } from 'lodash';
|
import { defaultTo, includes } from 'lodash';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
import {
|
import {
|
||||||
transformTableStateToQuery,
|
transformTableStateToQuery,
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
import { transformToForm } from 'utils';
|
import { transformToForm } from 'utils';
|
||||||
import { useSettingsSelector } from '../../hooks/state';
|
import { useSettingsSelector } from '../../hooks/state';
|
||||||
import { transformItemFormData } from './ItemForm.schema';
|
import { transformItemFormData } from './ItemForm.schema';
|
||||||
|
import { useWatch } from 'hooks/utils';
|
||||||
|
|
||||||
const defaultInitialValues = {
|
const defaultInitialValues = {
|
||||||
active: 1,
|
active: 1,
|
||||||
@@ -182,3 +184,59 @@ export function transformItemsTableState(tableState) {
|
|||||||
inactive_mode: tableState.inactiveMode,
|
inactive_mode: tableState.inactiveMode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform API errors.
|
||||||
|
*/
|
||||||
|
export const transformSubmitRequestErrors = (error) => {
|
||||||
|
const {
|
||||||
|
response: {
|
||||||
|
data: { errors },
|
||||||
|
},
|
||||||
|
} = error;
|
||||||
|
const fields = {};
|
||||||
|
|
||||||
|
if (errors.find((e) => e.type === 'ITEM.NAME.ALREADY.EXISTS')) {
|
||||||
|
fields.name = intl.get('the_name_used_before');
|
||||||
|
}
|
||||||
|
if (errors.find((e) => e.type === 'INVENTORY_ACCOUNT_CANNOT_MODIFIED')) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('cannot_change_item_inventory_account'),
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
errors.find(
|
||||||
|
(e) => e.type === 'TYPE_CANNOT_CHANGE_WITH_ITEM_HAS_TRANSACTIONS',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get(
|
||||||
|
'item.error.type_cannot_change_with_item_has_transactions',
|
||||||
|
),
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches and handles item response not found error.
|
||||||
|
* @param {*} itemQuery
|
||||||
|
*/
|
||||||
|
export function useWatchItemError(itemQuery) {
|
||||||
|
const { error, isError } = itemQuery;
|
||||||
|
|
||||||
|
// History context.
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
useWatch(() => {
|
||||||
|
if (isError && includes([400, 404], error.response.status)) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: 'The given item not found.',
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
history.push('/items');
|
||||||
|
}
|
||||||
|
}, isError);
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ import {
|
|||||||
} from './PaymentMadeForm.schema';
|
} from './PaymentMadeForm.schema';
|
||||||
import { compose, orderingLinesIndexes } from 'utils';
|
import { compose, orderingLinesIndexes } from 'utils';
|
||||||
import { usePaymentMadeFormContext } from './PaymentMadeFormProvider';
|
import { usePaymentMadeFormContext } from './PaymentMadeFormProvider';
|
||||||
import { defaultPaymentMade, transformToEditForm, ERRORS } from './utils';
|
import {
|
||||||
|
defaultPaymentMade,
|
||||||
|
transformToEditForm,
|
||||||
|
ERRORS,
|
||||||
|
transformFormToRequest,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment made form component.
|
* Payment made form component.
|
||||||
@@ -71,15 +76,8 @@ function PaymentMadeForm({
|
|||||||
{ setSubmitting, resetForm, setFieldError },
|
{ setSubmitting, resetForm, setFieldError },
|
||||||
) => {
|
) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
// Filters entries that have no `bill_id` or `payment_amount`.
|
|
||||||
const entries = values.entries
|
|
||||||
.filter((item) => item.bill_id && item.payment_amount)
|
|
||||||
.map((entry) => ({
|
|
||||||
...pick(entry, ['payment_amount', 'bill_id']),
|
|
||||||
}));
|
|
||||||
// Total payment amount of entries.
|
// Total payment amount of entries.
|
||||||
const totalPaymentAmount = sumBy(entries, 'payment_amount');
|
const totalPaymentAmount = sumBy(values.entries, 'payment_amount');
|
||||||
|
|
||||||
if (totalPaymentAmount <= 0) {
|
if (totalPaymentAmount <= 0) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
@@ -88,7 +86,8 @@ function PaymentMadeForm({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const form = { ...values, entries };
|
// Transformes the form values to request body.
|
||||||
|
const form = transformFormToRequest(values);
|
||||||
|
|
||||||
// Triggers once the save request success.
|
// Triggers once the save request success.
|
||||||
const onSaved = (response) => {
|
const onSaved = (response) => {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { pick } from 'lodash';
|
||||||
import {
|
import {
|
||||||
defaultFastFieldShouldUpdate,
|
defaultFastFieldShouldUpdate,
|
||||||
safeSumBy,
|
safeSumBy,
|
||||||
transformToForm,
|
transformToForm,
|
||||||
|
orderingLinesIndexes,
|
||||||
} from 'utils';
|
} from 'utils';
|
||||||
|
|
||||||
export const ERRORS = {
|
export const ERRORS = {
|
||||||
@@ -75,3 +77,17 @@ export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
|||||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the form values to request body.
|
||||||
|
*/
|
||||||
|
export const transformFormToRequest = (form) => {
|
||||||
|
// Filters entries that have no `bill_id` or `payment_amount`.
|
||||||
|
const entries = form.entries
|
||||||
|
.filter((item) => item.bill_id && item.payment_amount)
|
||||||
|
.map((entry) => ({
|
||||||
|
...pick(entry, ['payment_amount', 'bill_id']),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { ...form, entries: orderingLinesIndexes(entries) };
|
||||||
|
};
|
||||||
|
|||||||
@@ -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 intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { sumBy, omit, isEmpty } from 'lodash';
|
import { sumBy, isEmpty } from 'lodash';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
@@ -144,7 +144,10 @@ function InvoiceForm({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create invoice form schema.
|
||||||
const CreateInvoiceFormSchema = getCreateInvoiceFormSchema();
|
const CreateInvoiceFormSchema = getCreateInvoiceFormSchema();
|
||||||
|
|
||||||
|
// Edit invoice form schema.
|
||||||
const EditInvoiceFormSchema = getEditInvoiceFormSchema();
|
const EditInvoiceFormSchema = getEditInvoiceFormSchema();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
|
|||||||
customers,
|
customers,
|
||||||
newInvoice,
|
newInvoice,
|
||||||
estimateId,
|
estimateId,
|
||||||
|
invoiceId,
|
||||||
submitPayload,
|
submitPayload,
|
||||||
|
|
||||||
isInvoiceLoading,
|
isInvoiceLoading,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { AppToaster } from 'components';
|
|||||||
import { transactionNumber, compose } from 'utils';
|
import { transactionNumber, compose } from 'utils';
|
||||||
|
|
||||||
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
|
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
|
||||||
import { defaultPaymentReceive, transformToEditForm } from './utils';
|
import { defaultPaymentReceive, transformToEditForm, transformFormToRequest } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment Receive form.
|
* Payment Receive form.
|
||||||
@@ -91,15 +91,8 @@ function PaymentReceiveForm({
|
|||||||
) => {
|
) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
// Filters entries that have no `invoice_id` and `payment_amount`.
|
|
||||||
const entries = values.entries
|
|
||||||
.filter((entry) => entry.invoice_id && entry.payment_amount)
|
|
||||||
.map((entry) => ({
|
|
||||||
...pick(entry, ['invoice_id', 'payment_amount']),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Calculates the total payment amount of entries.
|
// Calculates the total payment amount of entries.
|
||||||
const totalPaymentAmount = sumBy(entries, 'payment_amount');
|
const totalPaymentAmount = sumBy(values.entries, 'payment_amount');
|
||||||
|
|
||||||
if (totalPaymentAmount <= 0) {
|
if (totalPaymentAmount <= 0) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
@@ -108,13 +101,8 @@ function PaymentReceiveForm({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const form = {
|
// Transformes the form values to request body.
|
||||||
...omit(values, ['payment_receive_no_manually', 'payment_receive_no']),
|
const form = transformFormToRequest(values);
|
||||||
...(values.payment_receive_no_manually && {
|
|
||||||
payment_receive_no: values.payment_receive_no,
|
|
||||||
}),
|
|
||||||
entries,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle request response success.
|
// Handle request response success.
|
||||||
const onSaved = (response) => {
|
const onSaved = (response) => {
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { omit, pick } from 'lodash';
|
||||||
import {
|
import {
|
||||||
defaultFastFieldShouldUpdate,
|
defaultFastFieldShouldUpdate,
|
||||||
transactionNumber,
|
transactionNumber,
|
||||||
transformToForm,
|
transformToForm,
|
||||||
safeSumBy,
|
safeSumBy,
|
||||||
|
orderingLinesIndexes
|
||||||
} from 'utils';
|
} from 'utils';
|
||||||
|
|
||||||
// Default payment receive entry.
|
// Default payment receive entry.
|
||||||
export const defaultPaymentReceiveEntry = {
|
export const defaultPaymentReceiveEntry = {
|
||||||
|
index: '',
|
||||||
payment_amount: '',
|
payment_amount: '',
|
||||||
invoice_id: '',
|
invoice_id: '',
|
||||||
invoice_no: '',
|
invoice_no: '',
|
||||||
@@ -32,8 +35,23 @@ export const defaultPaymentReceive = {
|
|||||||
entries: [],
|
entries: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultRequestPaymentEntry = {
|
||||||
|
index: '',
|
||||||
|
payment_amount: '',
|
||||||
|
invoice_id: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultRequestPayment = {
|
||||||
|
customer_id: '',
|
||||||
|
deposit_account_id: '',
|
||||||
|
payment_date: '',
|
||||||
|
payment_receive_no: '',
|
||||||
|
statement: '',
|
||||||
|
entries: []
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Transformes the edit payment receive to initial values of the form.
|
||||||
*/
|
*/
|
||||||
export const transformToEditForm = (paymentReceive, paymentReceiveEntries) => ({
|
export const transformToEditForm = (paymentReceive, paymentReceiveEntries) => ({
|
||||||
...transformToForm(paymentReceive, defaultPaymentReceive),
|
...transformToForm(paymentReceive, defaultPaymentReceive),
|
||||||
@@ -124,3 +142,23 @@ export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
|||||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tranformes form values to request.
|
||||||
|
*/
|
||||||
|
export const transformFormToRequest = (form) => {
|
||||||
|
// Filters entries that have no `invoice_id` and `payment_amount`.
|
||||||
|
const entries = form.entries
|
||||||
|
.filter((entry) => entry.invoice_id && entry.payment_amount)
|
||||||
|
.map((entry) => ({
|
||||||
|
...pick(entry, Object.keys(defaultRequestPaymentEntry)),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...omit(form, ['payment_receive_no_manually', 'payment_receive_no']),
|
||||||
|
...(form.payment_receive_no_manually && {
|
||||||
|
payment_receive_no: form.payment_receive_no,
|
||||||
|
}),
|
||||||
|
entries: orderingLinesIndexes(entries),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -852,7 +852,7 @@ function keyIdentity(key) {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flatten(target, opts) {
|
export function flatten(opts, target) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
const delimiter = opts.delimiter || '.';
|
const delimiter = opts.delimiter || '.';
|
||||||
|
|||||||
Reference in New Issue
Block a user