mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
BIG-14: avoid allocate landed cost on non-inventory items.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useItem } from 'hooks/query';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { DataTableEditable } from 'components';
|
||||
@@ -9,12 +8,13 @@ import { useEditableItemsEntriesColumns } from './components';
|
||||
import {
|
||||
saveInvoke,
|
||||
compose,
|
||||
updateTableRow,
|
||||
updateTableCell,
|
||||
updateMinEntriesLines,
|
||||
updateAutoAddNewLine,
|
||||
updateRemoveLineByIndex,
|
||||
} from 'utils';
|
||||
import { updateItemsEntriesTotal, ITEM_TYPE } from './utils';
|
||||
import { updateItemsEntriesTotal, useFetchItemRow } from './utils';
|
||||
import { updateTableRow } from '../../utils';
|
||||
|
||||
/**
|
||||
* Items entries table.
|
||||
@@ -30,62 +30,9 @@ function ItemsEntriesTable({
|
||||
linesNumber,
|
||||
currencyCode,
|
||||
itemType, // sellable or purchasable
|
||||
landedCost = false
|
||||
landedCost = false,
|
||||
}) {
|
||||
const [rows, setRows] = React.useState(initialEntries);
|
||||
const [rowItem, setRowItem] = React.useState(null);
|
||||
const [cellsLoading, setCellsLoading] = React.useState(null);
|
||||
|
||||
// Fetches the item details.
|
||||
const {
|
||||
data: item,
|
||||
isFetching: isItemFetching,
|
||||
isSuccess: isItemSuccess,
|
||||
} = useItem(rowItem && rowItem.itemId, {
|
||||
enabled: !!(rowItem && rowItem.itemId),
|
||||
});
|
||||
|
||||
// Once the item start loading give the table cells loading state.
|
||||
useEffect(() => {
|
||||
if (rowItem && isItemFetching) {
|
||||
setCellsLoading([
|
||||
[rowItem.rowIndex, 'rate'],
|
||||
[rowItem.rowIndex, 'description'],
|
||||
[rowItem.rowIndex, 'quantity'],
|
||||
[rowItem.rowIndex, 'discount'],
|
||||
]);
|
||||
} else {
|
||||
setCellsLoading(null);
|
||||
}
|
||||
}, [isItemFetching, setCellsLoading, rowItem]);
|
||||
|
||||
// Once the item selected and fetched set the initial details to the table.
|
||||
useEffect(() => {
|
||||
if (isItemSuccess && item && rowItem) {
|
||||
const { rowIndex } = rowItem;
|
||||
const price =
|
||||
itemType === ITEM_TYPE.PURCHASABLE
|
||||
? item.cost_price
|
||||
: item.sell_price;
|
||||
|
||||
const description =
|
||||
itemType === ITEM_TYPE.PURCHASABLE
|
||||
? item.cost_description
|
||||
: item.sell_description;
|
||||
|
||||
// Update the rate, description and quantity data of the row.
|
||||
const newRows = compose(
|
||||
updateItemsEntriesTotal,
|
||||
updateTableRow(rowIndex, 'rate', price),
|
||||
updateTableRow(rowIndex, 'description', description),
|
||||
updateTableRow(rowIndex, 'quantity', 1),
|
||||
)(rows);
|
||||
|
||||
setRows(newRows);
|
||||
setRowItem(null);
|
||||
saveInvoke(onUpdateData, newRows);
|
||||
}
|
||||
}, [item, rowItem, rows, itemType, onUpdateData, isItemSuccess]);
|
||||
|
||||
// Allows to observes `entries` to make table rows outside controlled.
|
||||
useEffect(() => {
|
||||
@@ -97,22 +44,38 @@ function ItemsEntriesTable({
|
||||
// Editiable items entries columns.
|
||||
const columns = useEditableItemsEntriesColumns({ landedCost });
|
||||
|
||||
// Handles the editor data update.
|
||||
const handleUpdateData = useCallback(
|
||||
(rowIndex, columnId, value) => {
|
||||
if (columnId === 'item_id') {
|
||||
setRowItem({ rowIndex, columnId, itemId: value });
|
||||
}
|
||||
// Handle the fetch item row details.
|
||||
const { setItemRow, cellsLoading, isItemFetching } = useFetchItemRow({
|
||||
landedCost,
|
||||
itemType,
|
||||
notifyNewRow: (newRow, rowIndex) => {
|
||||
// Update the rate, description and quantity data of the row.
|
||||
const newRows = compose(
|
||||
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
||||
updateItemsEntriesTotal,
|
||||
updateTableRow(rowIndex, columnId, value),
|
||||
updateTableRow(rowIndex, newRow),
|
||||
)(rows);
|
||||
|
||||
setRows(newRows);
|
||||
onUpdateData(newRows);
|
||||
},
|
||||
[rows, defaultEntry, onUpdateData],
|
||||
});
|
||||
|
||||
// Handles the editor data update.
|
||||
const handleUpdateData = useCallback(
|
||||
(rowIndex, columnId, value) => {
|
||||
if (columnId === 'item_id') {
|
||||
setItemRow({ rowIndex, columnId, itemId: value });
|
||||
}
|
||||
const newRows = compose(
|
||||
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
||||
updateItemsEntriesTotal,
|
||||
updateTableCell(rowIndex, columnId, value),
|
||||
)(rows);
|
||||
|
||||
setRows(newRows);
|
||||
onUpdateData(newRows);
|
||||
},
|
||||
[rows, defaultEntry, onUpdateData, setItemRow],
|
||||
);
|
||||
|
||||
// Handle table rows removing by index.
|
||||
|
||||
@@ -179,6 +179,7 @@ export function useEditableItemsEntriesColumns({ landedCost }) {
|
||||
accessor: 'landed_cost',
|
||||
Cell: CheckBoxFieldCell,
|
||||
width: 100,
|
||||
disabledAccessor: 'landed_cost_disabled',
|
||||
disableSortBy: true,
|
||||
disableResizing: true,
|
||||
className: 'landed-cost',
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { sumBy, isEmpty, last } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import { toSafeNumber } from 'utils';
|
||||
|
||||
import { useItem } from 'hooks/query';
|
||||
import { toSafeNumber, saveInvoke } from 'utils';
|
||||
|
||||
/**
|
||||
* Retrieve item entry total from the given rate, quantity and discount.
|
||||
@@ -52,4 +55,79 @@ export const ensureEntriesHaveEmptyLine = R.curry((defaultEntry, entries) => {
|
||||
return [...entries, defaultEntry];
|
||||
}
|
||||
return entries;
|
||||
});
|
||||
});
|
||||
|
||||
export const isLandedCostDisabled = (item) =>
|
||||
['service', 'non-inventory'].indexOf(item.type) !== -1;
|
||||
|
||||
/**
|
||||
* Handle fetch item row details and retrieves the new table row.
|
||||
*/
|
||||
export function useFetchItemRow({ landedCost, itemType, notifyNewRow }) {
|
||||
const [itemRow, setItemRow] = React.useState(null);
|
||||
const [cellsLoading, setCellsLoading] = React.useState(null);
|
||||
|
||||
// Fetches the item details.
|
||||
const {
|
||||
data: item,
|
||||
isFetching: isItemFetching,
|
||||
isSuccess: isItemSuccess,
|
||||
} = useItem(itemRow && itemRow.itemId, {
|
||||
enabled: !!(itemRow && itemRow.itemId),
|
||||
});
|
||||
|
||||
// Once the item start loading give the table cells loading state.
|
||||
React.useEffect(() => {
|
||||
if (itemRow && isItemFetching) {
|
||||
setCellsLoading([
|
||||
[itemRow.rowIndex, 'rate'],
|
||||
[itemRow.rowIndex, 'description'],
|
||||
[itemRow.rowIndex, 'quantity'],
|
||||
[itemRow.rowIndex, 'discount'],
|
||||
]);
|
||||
} else {
|
||||
setCellsLoading(null);
|
||||
}
|
||||
}, [isItemFetching, setCellsLoading, itemRow]);
|
||||
|
||||
// Once the item selected and fetched set the initial details to the table.
|
||||
React.useEffect(() => {
|
||||
if (isItemSuccess && item && itemRow) {
|
||||
const { rowIndex } = itemRow;
|
||||
const price =
|
||||
itemType === ITEM_TYPE.PURCHASABLE ? item.cost_price : item.sell_price;
|
||||
|
||||
const description =
|
||||
itemType === ITEM_TYPE.PURCHASABLE
|
||||
? item.cost_description
|
||||
: item.sell_description;
|
||||
|
||||
// Detarmines whether the landed cost checkbox should be disabled.
|
||||
const landedCostDisabled = isLandedCostDisabled(item);
|
||||
|
||||
// The new row.
|
||||
const newRow = {
|
||||
rate: price,
|
||||
description,
|
||||
quantity: 1,
|
||||
...(landedCost
|
||||
? {
|
||||
landed_cost: false,
|
||||
landed_cost_disabled: landedCostDisabled,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
setItemRow(null);
|
||||
saveInvoke(notifyNewRow, newRow, rowIndex);
|
||||
}
|
||||
}, [item, itemRow, itemType, isItemSuccess, landedCost, notifyNewRow]);
|
||||
|
||||
return {
|
||||
isItemFetching,
|
||||
isItemSuccess,
|
||||
item,
|
||||
setItemRow,
|
||||
itemRow,
|
||||
cellsLoading,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user