diff --git a/src/backend/InvenTree/stock/models.py b/src/backend/InvenTree/stock/models.py
index b781176096..d0f21f6862 100644
--- a/src/backend/InvenTree/stock/models.py
+++ b/src/backend/InvenTree/stock/models.py
@@ -1985,9 +1985,18 @@ class StockItem(
Returns:
The new StockItem object
+ Raises:
+ ValidationError: If the stock item cannot be split
+
- The provided quantity will be subtracted from this item and given to the new one.
- The new item will have a different StockItem ID, while this will remain the same.
"""
+ # Run initial checks to test if the stock item can actually be "split"
+
+ # Cannot split a stock item which is in production
+ if self.is_building:
+ raise ValidationError(_('Stock item is currently in production'))
+
notes = kwargs.get('notes', '')
# Do not split a serialized part
diff --git a/src/backend/InvenTree/stock/serializers.py b/src/backend/InvenTree/stock/serializers.py
index fc91e16660..e8deab1bd8 100644
--- a/src/backend/InvenTree/stock/serializers.py
+++ b/src/backend/InvenTree/stock/serializers.py
@@ -1565,18 +1565,18 @@ class StockAdjustmentItemSerializer(serializers.Serializer):
help_text=_('StockItem primary key value'),
)
- def validate_pk(self, pk):
+ def validate_pk(self, stock_item: StockItem) -> StockItem:
"""Ensure the stock item is valid."""
allow_out_of_stock_transfer = get_global_setting(
'STOCK_ALLOW_OUT_OF_STOCK_TRANSFER', backup_value=False, cache=False
)
- if not allow_out_of_stock_transfer and not pk.is_in_stock(
+ if not allow_out_of_stock_transfer and not stock_item.is_in_stock(
check_status=False, check_quantity=False
):
raise ValidationError(_('Stock item is not in stock'))
- return pk
+ return stock_item
quantity = serializers.DecimalField(
max_digits=15, decimal_places=5, min_value=Decimal(0), required=True
diff --git a/src/frontend/src/pages/stock/StockDetail.tsx b/src/frontend/src/pages/stock/StockDetail.tsx
index 3b069e99f4..eab214acce 100644
--- a/src/frontend/src/pages/stock/StockDetail.tsx
+++ b/src/frontend/src/pages/stock/StockDetail.tsx
@@ -667,13 +667,15 @@ export default function StockDetail() {
});
const stockActions = useMemo(() => {
- const inStock =
+ // Can this stock item be transferred to a different location?
+ const canTransfer =
user.hasChangeRole(UserRoles.stock) &&
!stockitem.sales_order &&
!stockitem.belongs_to &&
!stockitem.customer &&
- !stockitem.consumed_by &&
- !stockitem.is_building;
+ !stockitem.consumed_by;
+
+ const isBuilding = stockitem.is_building;
const serial = stockitem.serial;
const serialized =
@@ -704,7 +706,7 @@ export default function StockDetail() {
{
name: t`Count`,
tooltip: t`Count stock`,
- hidden: serialized || !inStock,
+ hidden: serialized || !canTransfer || isBuilding,
icon: (
),
@@ -715,7 +717,7 @@ export default function StockDetail() {
{
name: t`Add`,
tooltip: t`Add Stock`,
- hidden: serialized || !inStock,
+ hidden: serialized || !canTransfer || isBuilding,
icon: ,
onClick: () => {
stockitem.pk && addStockItem.open();
@@ -724,7 +726,11 @@ export default function StockDetail() {
{
name: t`Remove`,
tooltip: t`Remove Stock`,
- hidden: serialized || !inStock || stockitem.quantity <= 0,
+ hidden:
+ serialized ||
+ !canTransfer ||
+ isBuilding ||
+ stockitem.quantity <= 0,
icon: ,
onClick: () => {
stockitem.pk && removeStockItem.open();
@@ -733,7 +739,7 @@ export default function StockDetail() {
{
name: t`Transfer`,
tooltip: t`Transfer Stock`,
- hidden: !inStock,
+ hidden: !canTransfer,
icon: (
),
@@ -745,8 +751,10 @@ export default function StockDetail() {
name: t`Serialize`,
tooltip: t`Serialize stock`,
hidden:
- !inStock ||
+ !canTransfer ||
+ isBuilding ||
serialized ||
+ stockitem?.quantity != 1 ||
stockitem?.part_detail?.trackable != true,
icon: ,
onClick: () => {
diff --git a/src/frontend/src/tables/build/BuildOutputTable.tsx b/src/frontend/src/tables/build/BuildOutputTable.tsx
index 594d9471c1..3adf96be82 100644
--- a/src/frontend/src/tables/build/BuildOutputTable.tsx
+++ b/src/frontend/src/tables/build/BuildOutputTable.tsx
@@ -575,6 +575,7 @@ export default function BuildOutputTable({
props={{
params: {
part_detail: true,
+ location_detail: true,
tests: true,
is_building: true,
build: buildId