mirror of
https://github.com/inventree/InvenTree.git
synced 2026-08-16 02:06:29 +00:00
Allow bulk-edit for ReturnOrderLineItem (#12635)
* Allow bulk-edit for ReturnOrderLineItem - Allow bulk change of line item outcome * Update API version documentation with pull request links
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 530
|
||||
INVENTREE_API_VERSION = 531
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v531 -> 2026-08-13 : https://github.com/inventree/InvenTree/pull/12635
|
||||
- Adds "bulk update" support for the ReturnOrderLineItem API endpoint
|
||||
|
||||
v530 -> 2026-07-28 : https://github.com/inventree/InvenTree/pull/12487
|
||||
- Adds searching against ReportSnippet API endpoint
|
||||
|
||||
|
||||
@@ -1793,6 +1793,7 @@ class ReturnOrderLineItemOutputOptions(OutputConfiguration):
|
||||
|
||||
class ReturnOrderLineItemList(
|
||||
ReturnOrderLineItemMixin,
|
||||
BulkUpdateMixin,
|
||||
DataExportViewMixin,
|
||||
OutputOptionsMixin,
|
||||
ListCreateDestroyAPIView,
|
||||
|
||||
@@ -3716,6 +3716,42 @@ class ReturnOrderLineItemTests(InvenTreeAPITestCase):
|
||||
|
||||
self.assertEqual(models.ReturnOrderLineItem.objects.count(), n - 1)
|
||||
|
||||
def test_bulk_update(self):
|
||||
"""Test that we can bulk update the 'outcome' field for multiple ReturnOrderLineItems via the API."""
|
||||
ro = models.ReturnOrder.objects.get(pk=6)
|
||||
|
||||
# Create some extra line items against the same order, so we have multiple to update
|
||||
models.ReturnOrderLineItem.objects.bulk_create([
|
||||
models.ReturnOrderLineItem(order=ro, item_id=1006, quantity=1),
|
||||
models.ReturnOrderLineItem(order=ro, item_id=1007, quantity=1),
|
||||
])
|
||||
|
||||
items = list(
|
||||
models.ReturnOrderLineItem.objects.filter(order=ro).values_list(
|
||||
'pk', flat=True
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(len(items), 3)
|
||||
|
||||
for line in models.ReturnOrderLineItem.objects.filter(pk__in=items):
|
||||
self.assertEqual(line.outcome, ReturnOrderLineStatus.PENDING)
|
||||
|
||||
url = reverse('api-return-order-line-list')
|
||||
|
||||
data = {'items': items, 'outcome': ReturnOrderLineStatus.REPAIR.value}
|
||||
|
||||
# Update should fail without the correct role
|
||||
self.patch(url, data, expected_code=403)
|
||||
|
||||
self.assignRole('return_order.change')
|
||||
|
||||
response = self.patch(url, data, expected_code=200).data
|
||||
self.assertEqual(len(response['items']), 3)
|
||||
|
||||
for line in models.ReturnOrderLineItem.objects.filter(pk__in=items):
|
||||
self.assertEqual(line.outcome, ReturnOrderLineStatus.REPAIR.value)
|
||||
|
||||
def test_extra_line_bulk_delete(self):
|
||||
"""Test that we can bulk delete multiple ReturnOrderExtraLine items via the API."""
|
||||
ro = models.ReturnOrder.objects.first()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconSquareArrowRight } from '@tabler/icons-react';
|
||||
import { IconFlag, IconSquareArrowRight } from '@tabler/icons-react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { ActionButton } from '@lib/components/ActionButton';
|
||||
@@ -16,6 +16,7 @@ import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { TableColumn } from '@lib/types/Tables';
|
||||
import { Alert } from '@mantine/core';
|
||||
import {
|
||||
DateColumn,
|
||||
DescriptionColumn,
|
||||
@@ -37,6 +38,7 @@ import {
|
||||
useReturnOrderLineItemFields
|
||||
} from '../../forms/ReturnOrderForms';
|
||||
import {
|
||||
useBulkEditApiFormModal,
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal,
|
||||
useEditApiFormModal
|
||||
@@ -110,6 +112,21 @@ export default function ReturnOrderLineItemTable({
|
||||
table: table
|
||||
});
|
||||
|
||||
const setOutcome = useBulkEditApiFormModal({
|
||||
url: ApiEndpoints.return_order_line_list,
|
||||
items: table.selectedIds,
|
||||
title: t`Set Outcome`,
|
||||
preFormContent: (
|
||||
<Alert color='blue'>
|
||||
{t`Adjust the outcome for the selected line items.`}
|
||||
</Alert>
|
||||
),
|
||||
fields: {
|
||||
outcome: {}
|
||||
},
|
||||
onFormSuccess: table.refreshTable
|
||||
});
|
||||
|
||||
const tableColumns: TableColumn[] = useMemo(() => {
|
||||
return [
|
||||
LineItemColumn({}),
|
||||
@@ -211,6 +228,16 @@ export default function ReturnOrderLineItemTable({
|
||||
receiveLineItems.open();
|
||||
}}
|
||||
disabled={table.selectedRecords.length == 0}
|
||||
/>,
|
||||
<ActionButton
|
||||
key='set-outcome'
|
||||
tooltip={t`Set outcome for selected items`}
|
||||
icon={<IconFlag />}
|
||||
hidden={!editable || !user.hasChangeRole(UserRoles.return_order)}
|
||||
onClick={() => {
|
||||
setOutcome.open();
|
||||
}}
|
||||
disabled={table.selectedRecords.length == 0}
|
||||
/>
|
||||
];
|
||||
}, [user, editable, inProgress, orderId, table.selectedRecords]);
|
||||
@@ -266,6 +293,7 @@ export default function ReturnOrderLineItemTable({
|
||||
{editLine.modal}
|
||||
{deleteLine.modal}
|
||||
{receiveLineItems.modal}
|
||||
{setOutcome.modal}
|
||||
<InvenTreeTable
|
||||
url={apiUrl(ApiEndpoints.return_order_line_list)}
|
||||
tableState={table}
|
||||
@@ -279,7 +307,7 @@ export default function ReturnOrderLineItemTable({
|
||||
},
|
||||
defaultSortColumn: 'line',
|
||||
enableSelection:
|
||||
inProgress && user.hasChangeRole(UserRoles.return_order),
|
||||
editable && user.hasChangeRole(UserRoles.return_order),
|
||||
enableBulkDelete:
|
||||
editable && user.hasDeleteRole(UserRoles.return_order),
|
||||
afterBulkDelete: orderDetailRefresh,
|
||||
|
||||
Reference in New Issue
Block a user