diff --git a/CHANGELOG.md b/CHANGELOG.md
index eee68fb4d6..0bbe434ec4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+[#11816](https://github.com/inventree/InvenTree/pull/11816) makes the `issued_by` field on the `Build` API read only, and instead sets the `issued_by` field to the current user when a build is created. This change was made to ensure that the `issued_by` field accurately reflects the user who created the build, and to prevent users from setting this field to an arbitrary value when creating or updating a build.
+
### Removed
## 1.3.0 - 2026-04-11
diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py
index 0b03d4790a..476e408b8e 100644
--- a/src/backend/InvenTree/InvenTree/api_version.py
+++ b/src/backend/InvenTree/InvenTree/api_version.py
@@ -1,11 +1,14 @@
"""InvenTree API version information."""
# InvenTree API version
-INVENTREE_API_VERSION = 479
+INVENTREE_API_VERSION = 480
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
+v480 -> 2026-04-27 : https://github.com/inventree/InvenTree/pull/11816
+ - The "issued_by" field on the Build API endpoint is now read-only, and is automatically set to the current user when a build is created
+
v479 -> 2026-04-11 : https://github.com/inventree/InvenTree/pull/11723
- POST /api//notifications/readall/ now requires a POST action
- POST /api/admin/email/test/ - now returns a 200 on. a successful test
diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py
index 232b7adca7..7253f87f95 100644
--- a/src/backend/InvenTree/build/api.py
+++ b/src/backend/InvenTree/build/api.py
@@ -386,6 +386,20 @@ class BuildList(
kwargs['create'] = True
return super().get_serializer(*args, **kwargs)
+ def create(self, request, *args, **kwargs):
+ """Save user information on order creation."""
+ serializer = self.get_serializer(data=self.clean_data(request.data))
+ serializer.is_valid(raise_exception=True)
+
+ build = serializer.save()
+ build.issued_by = request.user
+ build.save()
+
+ headers = self.get_success_headers(serializer.data)
+ return Response(
+ serializer.data, status=status.HTTP_201_CREATED, headers=headers
+ )
+
class BuildDetail(BuildMixin, RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a Build object."""
diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py
index 39018c661a..c908bddd24 100644
--- a/src/backend/InvenTree/build/models.py
+++ b/src/backend/InvenTree/build/models.py
@@ -403,6 +403,14 @@ class Build(
related_name='builds_issued',
)
+ @property
+ def created_by(self):
+ """Alias for issued_by field.
+
+ This is used for compatibility with the order models
+ """
+ return self.issued_by
+
responsible = models.ForeignKey(
users.models.Owner,
on_delete=models.SET_NULL,
diff --git a/src/backend/InvenTree/build/serializers.py b/src/backend/InvenTree/build/serializers.py
index 724182c978..9264af7375 100644
--- a/src/backend/InvenTree/build/serializers.py
+++ b/src/backend/InvenTree/build/serializers.py
@@ -104,7 +104,8 @@ class BuildSerializer(
read_only_fields = [
'completed',
'creation_date',
- 'completion_data',
+ 'issued_by',
+ 'completion_date',
'status',
'status_text',
'level',
diff --git a/src/backend/InvenTree/build/test_api.py b/src/backend/InvenTree/build/test_api.py
index e63a313238..b7aa4a9cbd 100644
--- a/src/backend/InvenTree/build/test_api.py
+++ b/src/backend/InvenTree/build/test_api.py
@@ -568,6 +568,9 @@ class BuildTest(BuildAPITest):
self.assertEqual(bo.children.count(), 0)
+ self.assertIsNotNone(bo.issued_by)
+ self.assertEqual(bo.issued_by, self.user)
+
class BuildAllocationTest(BuildAPITest):
"""Unit tests for allocation of stock items against a build order.
diff --git a/src/backend/InvenTree/users/test_api.py b/src/backend/InvenTree/users/test_api.py
index c3acd2de0b..20cd9488d8 100644
--- a/src/backend/InvenTree/users/test_api.py
+++ b/src/backend/InvenTree/users/test_api.py
@@ -54,12 +54,16 @@ class UserAPITests(InvenTreeAPITestCase):
url = reverse('api-build-list')
response = self.options(url)
actions = response.data['actions']['POST']
- issued_by = actions['issued_by']
- self.assertEqual(issued_by['pk_field'], 'pk')
- self.assertEqual(issued_by['model'], 'user')
- self.assertEqual(issued_by['api_url'], reverse('api-user-list'))
- self.assertEqual(issued_by['default'], self.user.pk)
+ issued_by = actions['issued_by']
+ self.assertTrue(issued_by['read_only'])
+
+ project_code = actions['project_code']
+ self.assertFalse(project_code['read_only'])
+ self.assertEqual(project_code['type'], 'related field')
+ self.assertEqual(project_code['model'], 'projectcode')
+ self.assertEqual(project_code['api_url'], reverse('api-project-code-list'))
+ self.assertEqual(project_code['pk_field'], 'pk')
def test_user_api(self):
"""Tests for User API endpoints."""
diff --git a/src/frontend/src/forms/BuildForms.tsx b/src/frontend/src/forms/BuildForms.tsx
index 2fc4b447eb..0707f433db 100644
--- a/src/frontend/src/forms/BuildForms.tsx
+++ b/src/frontend/src/forms/BuildForms.tsx
@@ -8,7 +8,6 @@ import {
IconList,
IconSitemap,
IconTruckDelivery,
- IconUser,
IconUsersGroup
} from '@tabler/icons-react';
import { useEffect, useMemo, useState } from 'react';
@@ -128,12 +127,6 @@ export function useBuildOrderFields({
link: {
icon:
},
- issued_by: {
- icon: ,
- filters: {
- is_active: true
- }
- },
responsible: {
icon: ,
filters: {