mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
feat: auto-complete warehouse transfer row.
This commit is contained in:
@@ -3,11 +3,12 @@ import { FastField } from 'formik';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { useWarehouseTransferFormContext } from './WarehouseTransferFormProvider';
|
||||
import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable';
|
||||
import {
|
||||
entriesFieldShouldUpdate,
|
||||
defaultWarehouseTransferEntry,
|
||||
} from './utils';
|
||||
import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable';
|
||||
|
||||
|
||||
/**
|
||||
* Warehouse transafer editor field.
|
||||
@@ -35,6 +36,8 @@ export default function WarehouseTransferEditorField() {
|
||||
items={items}
|
||||
defaultEntry={defaultWarehouseTransferEntry}
|
||||
errors={error}
|
||||
sourceWarehouseId={values.from_warehouse_id}
|
||||
distentionWarehouseId={value.to_warehouse_id}
|
||||
/>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
@@ -68,9 +68,7 @@ function WarehouseTransferForm({
|
||||
const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
|
||||
setSubmitting(true);
|
||||
// Transformes the values of the form to request.
|
||||
const form = {
|
||||
...transformValueToRequest(values),
|
||||
};
|
||||
const form = transformValueToRequest(values);
|
||||
|
||||
// Handle the request success.
|
||||
const onSuccess = () => {
|
||||
|
||||
@@ -17,8 +17,6 @@ const Schema = Yup.object().shape({
|
||||
entries: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
item_id: Yup.number().nullable(),
|
||||
// source_warehouse: Yup.number().nullable(),
|
||||
// destination_warehouse: Yup.number().nullable(),
|
||||
description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT),
|
||||
quantity: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10),
|
||||
}),
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useWarehouseTransferTableColumns } from '../utils';
|
||||
import { DataTableEditable } from 'components';
|
||||
import {
|
||||
saveInvoke,
|
||||
compose,
|
||||
updateTableCell,
|
||||
updateMinEntriesLines,
|
||||
updateAutoAddNewLine,
|
||||
updateRemoveLineByIndex,
|
||||
orderingLinesIndexes,
|
||||
} from 'utils';
|
||||
|
||||
import { useWarehouseTransferTableColumns } from '../utils';
|
||||
import { useFetchItemWarehouseQuantity } from './hooks';
|
||||
import { useDeepCompareEffect } from 'hooks/utils';
|
||||
|
||||
import { saveInvoke } from 'utils';
|
||||
import { mutateTableCell, mutateTableRow, deleteTableRow } from './utils';
|
||||
|
||||
/**
|
||||
* Warehouse transfer form entries table.
|
||||
*/
|
||||
@@ -21,34 +19,63 @@ export default function WarehouseTransferFormEntriesTable({
|
||||
defaultEntry,
|
||||
onUpdateData,
|
||||
errors,
|
||||
|
||||
destinationWarehouseId,
|
||||
sourceWarehouseId,
|
||||
}) {
|
||||
// Fetch the table row.
|
||||
const { newRowMeta, setTableRow, resetTableRow, cellsLoading } =
|
||||
useFetchItemWarehouseQuantity();
|
||||
|
||||
// Retrieve the warehouse transfer table columns.
|
||||
const columns = useWarehouseTransferTableColumns();
|
||||
|
||||
// Observes the new row meta to call `onUpdateData` callback.
|
||||
useDeepCompareEffect(() => {
|
||||
if (newRowMeta) {
|
||||
const newRow = {
|
||||
item_id: newRowMeta.itemId,
|
||||
warehouses: newRowMeta.warehouses,
|
||||
description: '',
|
||||
quantity: 0,
|
||||
};
|
||||
const newRows = mutateTableRow(newRowMeta.rowIndex, newRow, entries);
|
||||
|
||||
saveInvoke(onUpdateData, newRows);
|
||||
resetTableRow();
|
||||
}
|
||||
}, [newRowMeta]);
|
||||
|
||||
// Handle update data.
|
||||
const handleUpdateData = React.useCallback(
|
||||
(rowIndex, columnId, value) => {
|
||||
const newRows = compose(
|
||||
// Update auto-adding new line.
|
||||
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
||||
// Update the row value of the given row index and column id.
|
||||
updateTableCell(rowIndex, columnId, value),
|
||||
)(entries);
|
||||
(rowIndex, columnId, itemId) => {
|
||||
if (columnId === 'item_id') {
|
||||
setTableRow({
|
||||
rowIndex,
|
||||
columnId,
|
||||
itemId,
|
||||
sourceWarehouseId,
|
||||
destinationWarehouseId,
|
||||
});
|
||||
}
|
||||
const editCell = mutateTableCell(rowIndex, columnId, defaultEntry);
|
||||
const newRows = editCell(itemId, entries);
|
||||
|
||||
saveInvoke(onUpdateData, newRows);
|
||||
},
|
||||
[entries, defaultEntry, onUpdateData],
|
||||
[
|
||||
entries,
|
||||
defaultEntry,
|
||||
onUpdateData,
|
||||
destinationWarehouseId,
|
||||
sourceWarehouseId,
|
||||
setTableRow,
|
||||
],
|
||||
);
|
||||
// Handles click remove datatable row.
|
||||
const handleRemoveRow = React.useCallback(
|
||||
(rowIndex) => {
|
||||
const newRows = compose(
|
||||
// Ensure minimum lines count.
|
||||
updateMinEntriesLines(4, defaultEntry),
|
||||
// Remove the line by the given index.
|
||||
updateRemoveLineByIndex(rowIndex),
|
||||
)(entries);
|
||||
|
||||
const newRows = deleteTableRow(rowIndex, defaultEntry, entries);
|
||||
saveInvoke(onUpdateData, newRows);
|
||||
},
|
||||
[entries, defaultEntry, onUpdateData],
|
||||
@@ -58,12 +85,17 @@ export default function WarehouseTransferFormEntriesTable({
|
||||
<DataTableEditable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
cellsLoading={!!cellsLoading}
|
||||
cellsLoadingCoords={cellsLoading}
|
||||
payload={{
|
||||
items,
|
||||
errors: errors || [],
|
||||
updateData: handleUpdateData,
|
||||
removeRow: handleRemoveRow,
|
||||
autoFocus: ['item_id', 0],
|
||||
|
||||
sourceWarehouseId,
|
||||
destinationWarehouseId,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { useItem } from 'hooks/query';
|
||||
|
||||
interface IItemMeta {
|
||||
rowIndex: number;
|
||||
columnId: string;
|
||||
itemId: number;
|
||||
|
||||
sourceWarehouseId: number;
|
||||
distentionWarehouseId: number;
|
||||
}
|
||||
|
||||
type CellLoading = any;
|
||||
|
||||
interface IWarehouseMeta {
|
||||
warehouseId: number;
|
||||
warehouseQuantity: number;
|
||||
warehouseQuantityFormatted: string;
|
||||
}
|
||||
interface IRow {
|
||||
rowIndex: number;
|
||||
columnId: number;
|
||||
itemId: number;
|
||||
|
||||
warehouses: IWarehouseMeta[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the item warehouse quantity.
|
||||
* @returns
|
||||
*/
|
||||
export const useFetchItemWarehouseQuantity = () => {
|
||||
// Holds the table row meta of the given row index.
|
||||
const [tableRow, setTableRow] = React.useState<IItemMeta | null>(null);
|
||||
|
||||
// Table cells loading coords.
|
||||
const [cellsLoading, setCellsLoading] = React.useState<CellLoading | null>(
|
||||
null,
|
||||
);
|
||||
// Fetches the item warehouse locations.
|
||||
const {
|
||||
data: item,
|
||||
isLoading: isItemLoading,
|
||||
isSuccess: isItemSuccess,
|
||||
} = useItem(tableRow?.itemId, {
|
||||
enabled: !!(tableRow && tableRow.itemId),
|
||||
});
|
||||
|
||||
// Effects with row cells loading state.
|
||||
React.useEffect(() => {
|
||||
setCellsLoading(null);
|
||||
|
||||
if (isItemLoading && tableRow) {
|
||||
setCellsLoading([
|
||||
[tableRow.rowIndex, 'quantity'],
|
||||
[tableRow.rowIndex, 'source_warehouse'],
|
||||
[tableRow.rowIndex, 'destination_warehouse'],
|
||||
]);
|
||||
}
|
||||
}, [isItemLoading, tableRow]);
|
||||
|
||||
// New table row meta.
|
||||
const newRowMeta = React.useMemo(() => {
|
||||
return isItemSuccess
|
||||
? {
|
||||
...tableRow,
|
||||
warehouses: [],
|
||||
}
|
||||
: null;
|
||||
}, [isItemSuccess, tableRow]);
|
||||
|
||||
// Reset the table row.
|
||||
const resetTableRow = React.useCallback(() => {
|
||||
setTableRow(null);
|
||||
setCellsLoading(null);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
setTableRow,
|
||||
resetTableRow,
|
||||
|
||||
cellsLoading,
|
||||
newRowMeta,
|
||||
};
|
||||
};
|
||||
@@ -2,16 +2,25 @@ import React from 'react';
|
||||
import moment from 'moment';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { AppToaster } from 'components';
|
||||
import { omit } from 'lodash';
|
||||
import { useFormikContext } from 'formik';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
import {
|
||||
orderingLinesIndexes,
|
||||
updateAutoAddNewLine,
|
||||
updateTableCell,
|
||||
} from 'utils';
|
||||
import {
|
||||
compose,
|
||||
transformToForm,
|
||||
repeatValue,
|
||||
transactionNumber,
|
||||
defaultFastFieldShouldUpdate,
|
||||
updateTableRow,
|
||||
updateMinEntriesLines,
|
||||
updateRemoveLineByIndex,
|
||||
} from 'utils';
|
||||
|
||||
// import { defaultFastFieldShouldUpdate } from 'utils';
|
||||
@@ -88,6 +97,10 @@ export const useObserveTransferNoSettings = (prefix, nextNumber) => {
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.items !== oldProps.items ||
|
||||
newProps.formik.values.from_warehouse_id !==
|
||||
oldProps.formik.values.from_warehouse_id ||
|
||||
newProps.formik.values.to_warehouse_id !==
|
||||
oldProps.formik.values.to_warehouse_id ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
@@ -102,7 +115,7 @@ export function transformValueToRequest(values) {
|
||||
return {
|
||||
...values,
|
||||
entries: entries.map((entry) => ({
|
||||
...omit(entry, ['destination_warehouse', 'source_warehouse']),
|
||||
...omit(entry, ['warehouses']),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -122,3 +135,42 @@ export const transformErrors = (errors, { setErrors }) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mutates table cell.
|
||||
* @param {*} rowIndex
|
||||
* @param {*} columnId
|
||||
* @param {*} defaultEntry
|
||||
* @param {*} value
|
||||
* @param {*} entries
|
||||
* @returns
|
||||
*/
|
||||
export const mutateTableCell = R.curry(
|
||||
(rowIndex, columnId, defaultEntry, value, entries) => {
|
||||
return compose(
|
||||
// Update auto-adding new line.
|
||||
updateAutoAddNewLine(defaultEntry, ['item_id']),
|
||||
// Update the row value of the given row index and column id.
|
||||
updateTableCell(rowIndex, columnId, value),
|
||||
)(entries);
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Compose table rows when insert a new row to table rows.
|
||||
*/
|
||||
export const mutateTableRow = R.curry((rowIndex, newRow, rows) => {
|
||||
return compose(orderingLinesIndexes, updateTableRow(rowIndex, newRow))(rows);
|
||||
});
|
||||
|
||||
/**
|
||||
* Deletes the table row from the given rows.
|
||||
*/
|
||||
export const deleteTableRow = R.curry((rowIndex, defaultEntry, rows) => {
|
||||
return compose(
|
||||
// Ensure minimum lines count.
|
||||
updateMinEntriesLines(4, defaultEntry),
|
||||
// Remove the line by the given index.
|
||||
updateRemoveLineByIndex(rowIndex),
|
||||
)(rows);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { find, get } from 'lodash';
|
||||
import { Tooltip, Button, Intent, Position } from '@blueprintjs/core';
|
||||
|
||||
import {
|
||||
@@ -43,6 +44,26 @@ export function ActionsCellRenderer({
|
||||
);
|
||||
}
|
||||
|
||||
function SourceWarehouseAccessorCell({ value, row: { original }, payload }) {
|
||||
const warehouse = find(
|
||||
original.warehouses,
|
||||
(w) => w.warehouseId === payload.sourceWarehouseId,
|
||||
);
|
||||
return get(warehouse, 'warehouseQuantityFormatted', '0');
|
||||
}
|
||||
|
||||
function DistentionWarehouseAccessorCell({
|
||||
value,
|
||||
row: { original },
|
||||
payload,
|
||||
}) {
|
||||
const warehouse = find(
|
||||
original.warehouses,
|
||||
(w) => w.warehouseId === payload.distentionWarehouseId,
|
||||
);
|
||||
return get(warehouse, 'warehouseQuantityFormatted', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves warehouse transfer table columns.
|
||||
* @returns
|
||||
@@ -82,6 +103,7 @@ export const useWarehouseTransferTableColumns = () => {
|
||||
Header: 'Source Warehouse',
|
||||
accessor: 'source_warehouse',
|
||||
disableSortBy: true,
|
||||
Cell: SourceWarehouseAccessorCell,
|
||||
align: 'right',
|
||||
width: 120,
|
||||
},
|
||||
@@ -89,6 +111,7 @@ export const useWarehouseTransferTableColumns = () => {
|
||||
id: 'destination_warehouse',
|
||||
Header: 'Destination Warehouse',
|
||||
accessor: 'destination_warehouse',
|
||||
Cell: DistentionWarehouseAccessorCell,
|
||||
disableSortBy: true,
|
||||
align: 'right',
|
||||
width: 120,
|
||||
|
||||
Reference in New Issue
Block a user