2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-04-28 13:54:25 +00:00

[bug] Make "issued_by" field read-only (#11816)

* Fix "issued_by" for BuildOrder model

- Automatically capture user information
- Mark field as read-only
- Remove from frontend forms

* Add "created_by" property

* Update unit test

* Update API and CHANGELOG

* Further adjustments to unit tests
This commit is contained in:
Oliver
2026-04-27 17:35:28 +10:00
committed by GitHub
parent e3a2a02857
commit 9763ce01ae
8 changed files with 42 additions and 14 deletions
+2
View File
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### 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 ### Removed
## 1.3.0 - 2026-04-11 ## 1.3.0 - 2026-04-11
@@ -1,11 +1,14 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # 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.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ 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 v479 -> 2026-04-11 : https://github.com/inventree/InvenTree/pull/11723
- POST /api//notifications/readall/ now requires a POST action - POST /api//notifications/readall/ now requires a POST action
- POST /api/admin/email/test/ - now returns a 200 on. a successful test - POST /api/admin/email/test/ - now returns a 200 on. a successful test
+14
View File
@@ -386,6 +386,20 @@ class BuildList(
kwargs['create'] = True kwargs['create'] = True
return super().get_serializer(*args, **kwargs) 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): class BuildDetail(BuildMixin, RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a Build object.""" """API endpoint for detail view of a Build object."""
+8
View File
@@ -403,6 +403,14 @@ class Build(
related_name='builds_issued', 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( responsible = models.ForeignKey(
users.models.Owner, users.models.Owner,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
+2 -1
View File
@@ -104,7 +104,8 @@ class BuildSerializer(
read_only_fields = [ read_only_fields = [
'completed', 'completed',
'creation_date', 'creation_date',
'completion_data', 'issued_by',
'completion_date',
'status', 'status',
'status_text', 'status_text',
'level', 'level',
+3
View File
@@ -568,6 +568,9 @@ class BuildTest(BuildAPITest):
self.assertEqual(bo.children.count(), 0) self.assertEqual(bo.children.count(), 0)
self.assertIsNotNone(bo.issued_by)
self.assertEqual(bo.issued_by, self.user)
class BuildAllocationTest(BuildAPITest): class BuildAllocationTest(BuildAPITest):
"""Unit tests for allocation of stock items against a build order. """Unit tests for allocation of stock items against a build order.
+9 -5
View File
@@ -54,12 +54,16 @@ class UserAPITests(InvenTreeAPITestCase):
url = reverse('api-build-list') url = reverse('api-build-list')
response = self.options(url) response = self.options(url)
actions = response.data['actions']['POST'] actions = response.data['actions']['POST']
issued_by = actions['issued_by']
self.assertEqual(issued_by['pk_field'], 'pk') issued_by = actions['issued_by']
self.assertEqual(issued_by['model'], 'user') self.assertTrue(issued_by['read_only'])
self.assertEqual(issued_by['api_url'], reverse('api-user-list'))
self.assertEqual(issued_by['default'], self.user.pk) 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): def test_user_api(self):
"""Tests for User API endpoints.""" """Tests for User API endpoints."""
-7
View File
@@ -8,7 +8,6 @@ import {
IconList, IconList,
IconSitemap, IconSitemap,
IconTruckDelivery, IconTruckDelivery,
IconUser,
IconUsersGroup IconUsersGroup
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
@@ -128,12 +127,6 @@ export function useBuildOrderFields({
link: { link: {
icon: <IconLink /> icon: <IconLink />
}, },
issued_by: {
icon: <IconUser />,
filters: {
is_active: true
}
},
responsible: { responsible: {
icon: <IconUsersGroup />, icon: <IconUsersGroup />,
filters: { filters: {