mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-25 13:43:30 +00:00
[bug] Trim stock allocation (#11060)
* Trim stock allocation - Handle condition where allocated quantity exceeds available stock - Prevent silent failure of build completion * Fix display in buildallocatedstock table * Consolidate table columns * Fetch substitutes for BOM table
This commit is contained in:
@@ -1887,7 +1887,7 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
return self.build_line.bom_item if self.build_line else None
|
return self.build_line.bom_item if self.build_line else None
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def complete_allocation(self, quantity=None, notes='', user=None) -> None:
|
def complete_allocation(self, quantity=None, notes: str = '', user=None) -> None:
|
||||||
"""Complete the allocation of this BuildItem into the output stock item.
|
"""Complete the allocation of this BuildItem into the output stock item.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@@ -1910,9 +1910,7 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
|
|
||||||
# Ensure we are not allocating more than available
|
# Ensure we are not allocating more than available
|
||||||
if quantity > item.quantity:
|
if quantity > item.quantity:
|
||||||
raise ValidationError({
|
quantity = item.quantity
|
||||||
'quantity': _('Allocated quantity exceeds available stock quantity')
|
|
||||||
})
|
|
||||||
|
|
||||||
# Split the allocated stock if there are more available than allocated
|
# Split the allocated stock if there are more available than allocated
|
||||||
if item.quantity > quantity:
|
if item.quantity > quantity:
|
||||||
|
|||||||
@@ -670,9 +670,10 @@ export function BomTable({
|
|||||||
params: {
|
params: {
|
||||||
...params,
|
...params,
|
||||||
part: partId,
|
part: partId,
|
||||||
category_detail: true,
|
substitutes: true,
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
sub_part_detail: true
|
sub_part_detail: true,
|
||||||
|
category_detail: true
|
||||||
},
|
},
|
||||||
tableActions: tableActions,
|
tableActions: tableActions,
|
||||||
tableFilters: tableFilters,
|
tableFilters: tableFilters,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
import { UserRoles } from '@lib/enums/Roles';
|
import { UserRoles } from '@lib/enums/Roles';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import { ActionButton } from '@lib/index';
|
import { ActionButton, formatDecimal } from '@lib/index';
|
||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { StockOperationProps } from '@lib/types/Forms';
|
import type { StockOperationProps } from '@lib/types/Forms';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
@@ -113,13 +113,6 @@ export default function BuildAllocatedStockTable({
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: true
|
switchable: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessor: 'serial',
|
|
||||||
title: t`Serial Number`,
|
|
||||||
sortable: false,
|
|
||||||
switchable: true,
|
|
||||||
render: (record: any) => record?.stock_item_detail?.serial
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'batch',
|
accessor: 'batch',
|
||||||
title: t`Batch Code`,
|
title: t`Batch Code`,
|
||||||
@@ -128,15 +121,22 @@ export default function BuildAllocatedStockTable({
|
|||||||
render: (record: any) => record?.stock_item_detail?.batch
|
render: (record: any) => record?.stock_item_detail?.batch
|
||||||
},
|
},
|
||||||
DecimalColumn({
|
DecimalColumn({
|
||||||
accessor: 'available',
|
accessor: 'stock_item_detail.quantity',
|
||||||
title: t`Available`
|
title: t`Available`
|
||||||
}),
|
}),
|
||||||
DecimalColumn({
|
{
|
||||||
accessor: 'quantity',
|
accessor: 'quantity',
|
||||||
title: t`Allocated`,
|
title: t`Allocated`,
|
||||||
sortable: true,
|
render: (record: any) => {
|
||||||
switchable: false
|
const serial = record?.stock_item_detail?.serial;
|
||||||
}),
|
|
||||||
|
if (serial && record?.quantity == 1) {
|
||||||
|
return `${t`Serial`}: ${serial}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatDecimal(record.quantity);
|
||||||
|
}
|
||||||
|
},
|
||||||
LocationColumn({
|
LocationColumn({
|
||||||
accessor: 'location_detail',
|
accessor: 'location_detail',
|
||||||
switchable: true,
|
switchable: true,
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ test('Parts - BOM', async ({ browser }) => {
|
|||||||
await page.getByRole('button', { name: 'Close' }).click();
|
await page.getByRole('button', { name: 'Close' }).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Part - Editing', async ({ browser }) => {
|
test('Parts - Editing', async ({ browser }) => {
|
||||||
const page = await doCachedLogin(browser, { url: 'part/104/details' });
|
const page = await doCachedLogin(browser, { url: 'part/104/details' });
|
||||||
|
|
||||||
await page.getByText('A square table - with blue paint').first().waitFor();
|
await page.getByText('A square table - with blue paint').first().waitFor();
|
||||||
|
|||||||
Reference in New Issue
Block a user