2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

[PUI] Fix stock actions (#8569)

* Fix useAssignStockItems

- Only allow "salable" parts

* Assign item to customer

* Adjust playwright tests
This commit is contained in:
Oliver 2024-11-27 15:01:07 +11:00 committed by GitHub
parent af39189e7e
commit 81e87a65e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 13 deletions

View File

@ -870,6 +870,7 @@ function stockOperationModal({
endpoint,
filters,
title,
successMessage,
modalFunc = useCreateApiFormModal
}: {
items?: object;
@ -880,6 +881,7 @@ function stockOperationModal({
fieldGenerator: (items: any[]) => ApiFormFieldSet;
endpoint: ApiEndpoints;
title: string;
successMessage?: string;
modalFunc?: apiModalFunc;
}) {
const baseParams: any = {
@ -932,12 +934,13 @@ function stockOperationModal({
fields: fields,
title: title,
size: '80%',
successMessage: successMessage,
onFormSuccess: () => refresh()
});
}
export type StockOperationProps = {
items?: object;
items?: any[];
pk?: number;
filters?: any;
model: ModelType.stockitem | 'location' | ModelType.part;
@ -949,7 +952,8 @@ export function useAddStockItem(props: StockOperationProps) {
...props,
fieldGenerator: stockAddFields,
endpoint: ApiEndpoints.stock_add,
title: t`Add Stock`
title: t`Add Stock`,
successMessage: t`Stock added`
});
}
@ -958,7 +962,8 @@ export function useRemoveStockItem(props: StockOperationProps) {
...props,
fieldGenerator: stockRemoveFields,
endpoint: ApiEndpoints.stock_remove,
title: t`Remove Stock`
title: t`Remove Stock`,
successMessage: t`Stock removed`
});
}
@ -967,7 +972,8 @@ export function useTransferStockItem(props: StockOperationProps) {
...props,
fieldGenerator: stockTransferFields,
endpoint: ApiEndpoints.stock_transfer,
title: t`Transfer Stock`
title: t`Transfer Stock`,
successMessage: t`Stock transferred`
});
}
@ -976,7 +982,8 @@ export function useCountStockItem(props: StockOperationProps) {
...props,
fieldGenerator: stockCountFields,
endpoint: ApiEndpoints.stock_count,
title: t`Count Stock`
title: t`Count Stock`,
successMessage: t`Stock counted`
});
}
@ -985,7 +992,8 @@ export function useChangeStockStatus(props: StockOperationProps) {
...props,
fieldGenerator: stockChangeStatusFields,
endpoint: ApiEndpoints.stock_change_status,
title: t`Change Stock Status`
title: t`Change Stock Status`,
successMessage: t`Stock status changed`
});
}
@ -994,16 +1002,24 @@ export function useMergeStockItem(props: StockOperationProps) {
...props,
fieldGenerator: stockMergeFields,
endpoint: ApiEndpoints.stock_merge,
title: t`Merge Stock`
title: t`Merge Stock`,
successMessage: t`Stock merged`
});
}
export function useAssignStockItem(props: StockOperationProps) {
// Filter items - only allow 'salable' items
const items = useMemo(() => {
return props.items?.filter((item) => item?.part_detail?.salable);
}, [props.items]);
return stockOperationModal({
...props,
items: items,
fieldGenerator: stockAssignFields,
endpoint: ApiEndpoints.stock_assign,
title: t`Assign Stock to Customer`
title: t`Assign Stock to Customer`,
successMessage: t`Stock assigned to customer`
});
}
@ -1013,7 +1029,8 @@ export function useDeleteStockItem(props: StockOperationProps) {
fieldGenerator: stockDeleteFields,
endpoint: ApiEndpoints.stock_item_list,
modalFunc: useDeleteApiFormModal,
title: t`Delete Stock Items`
title: t`Delete Stock Items`,
successMessage: t`Stock deleted`
});
}

View File

@ -48,6 +48,7 @@ import { UserRoles } from '../../enums/Roles';
import {
type StockOperationProps,
useAddStockItem,
useAssignStockItem,
useCountStockItem,
useRemoveStockItem,
useStockFields,
@ -588,7 +589,7 @@ export default function StockDetail() {
const stockActionProps: StockOperationProps = useMemo(() => {
return {
items: stockitem,
items: [stockitem],
model: ModelType.stockitem,
refresh: refreshInstance,
filters: {
@ -601,6 +602,7 @@ export default function StockDetail() {
const addStockItem = useAddStockItem(stockActionProps);
const removeStockItem = useRemoveStockItem(stockActionProps);
const transferStockItem = useTransferStockItem(stockActionProps);
const assignToCustomer = useAssignStockItem(stockActionProps);
const serializeStockFields = useStockItemSerializeFields({
partId: stockitem.part,
@ -731,7 +733,7 @@ export default function StockDetail() {
{
name: t`Return`,
tooltip: t`Return from customer`,
hidden: !stockitem.sales_order,
hidden: !stockitem.customer,
icon: (
<InvenTreeIcon
icon='return_orders'
@ -741,6 +743,17 @@ export default function StockDetail() {
onClick: () => {
stockitem.pk && returnStockItem.open();
}
},
{
name: t`Assign to Customer`,
tooltip: t`Assign to a customer`,
hidden: !!stockitem.customer,
icon: (
<InvenTreeIcon icon='customer' iconProps={{ color: 'blue' }} />
),
onClick: () => {
stockitem.pk && assignToCustomer.open();
}
}
]}
/>,
@ -874,6 +887,7 @@ export default function StockDetail() {
{transferStockItem.modal}
{serializeStockItem.modal}
{returnStockItem.modal}
{assignToCustomer.modal}
</Stack>
</InstanceDetail>
);

View File

@ -604,7 +604,7 @@ export function StockItemTable({
{
name: t`Assign to customer`,
icon: <InvenTreeIcon icon='customer' />,
tooltip: t`Order new stock`,
tooltip: t`Assign items to a customer`,
disabled: !can_add_stock,
onClick: () => {
assignStock.open();

View File

@ -189,7 +189,7 @@ test('Stock - Stock Actions', async ({ page }) => {
await page.getByRole('button', { name: 'Cancel' }).click();
// Find an item which has been sent to a customer
await page.goto(`${baseUrl}/stock/item/1012/details`);
await page.goto(`${baseUrl}/stock/item/1014/details`);
await page.getByText('Batch Code: 2022-11-12').waitFor();
await page.getByText('Unavailable').waitFor();
await page.getByLabel('action-menu-stock-operations').click();