mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Fix state changes on stock items (#7976)
* Revert changes from https://github.com/inventree/InvenTree/pull/7965 * Add error handling for wrong key * Add e2e test case for error condition Fixes #7964 * Better code code / flow * [BUG] Order of states in schema descriptions is not stable Fixes #7977
This commit is contained in:
parent
df8efa902e
commit
ed2da62a46
@ -41,7 +41,7 @@ class CustomChoiceField(serializers.ChoiceField):
|
|||||||
if self.is_custom:
|
if self.is_custom:
|
||||||
return logical.key
|
return logical.key
|
||||||
return logical.logical_key
|
return logical.logical_key
|
||||||
except ObjectDoesNotExist:
|
except (ObjectDoesNotExist, Exception):
|
||||||
raise serializers.ValidationError('Invalid choice')
|
raise serializers.ValidationError('Invalid choice')
|
||||||
|
|
||||||
def get_field_info(self, field, field_info):
|
def get_field_info(self, field, field_info):
|
||||||
@ -145,24 +145,32 @@ class InvenTreeCustomStatusSerializerMixin:
|
|||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
"""Ensure the custom field is updated if the leader was changed."""
|
"""Ensure the custom field is updated if the leader was changed."""
|
||||||
self.gather_custom_fields()
|
self.gather_custom_fields()
|
||||||
|
# Mirror values from leader to follower
|
||||||
for field in self._custom_fields_leader:
|
for field in self._custom_fields_leader:
|
||||||
|
follower_field_name = f'{field}_custom_key'
|
||||||
if (
|
if (
|
||||||
field in self.initial_data
|
field in self.initial_data
|
||||||
and self.instance
|
and self.instance
|
||||||
and self.initial_data[field]
|
and self.initial_data[field]
|
||||||
!= getattr(self.instance, f'{field}_custom_key', None)
|
!= getattr(self.instance, follower_field_name, None)
|
||||||
):
|
):
|
||||||
setattr(self.instance, f'{field}_custom_key', self.initial_data[field])
|
setattr(self.instance, follower_field_name, self.initial_data[field])
|
||||||
|
|
||||||
|
# Mirror values from follower to leader
|
||||||
for field in self._custom_fields_follower:
|
for field in self._custom_fields_follower:
|
||||||
if (
|
leader_field_name = field.replace('_custom_key', '')
|
||||||
field in validated_data
|
if field in validated_data and leader_field_name not in self.initial_data:
|
||||||
and field.replace('_custom_key', '') not in self.initial_data
|
try:
|
||||||
):
|
|
||||||
reference = get_logical_value(
|
reference = get_logical_value(
|
||||||
validated_data[field],
|
validated_data[field],
|
||||||
self.fields[field].choice_mdl._meta.model_name,
|
self.fields[field].choice_mdl._meta.model_name,
|
||||||
)
|
)
|
||||||
validated_data[field.replace('_custom_key', '')] = reference.logical_key
|
validated_data[leader_field_name] = reference.logical_key
|
||||||
|
except (ObjectDoesNotExist, Exception):
|
||||||
|
if validated_data[field] in self.fields[leader_field_name].choices:
|
||||||
|
validated_data[leader_field_name] = validated_data[field]
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError('Invalid choice')
|
||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
|
@ -1004,6 +1004,14 @@ class CustomStockItemStatusTest(StockAPITestCase):
|
|||||||
self.assertEqual(response.data['status'], self.status.logical_key)
|
self.assertEqual(response.data['status'], self.status.logical_key)
|
||||||
self.assertEqual(response.data['status_custom_key'], self.status.logical_key)
|
self.assertEqual(response.data['status_custom_key'], self.status.logical_key)
|
||||||
|
|
||||||
|
# Test case with wrong key
|
||||||
|
response = self.patch(
|
||||||
|
reverse('api-stock-detail', kwargs={'pk': pk}),
|
||||||
|
{'status_custom_key': 23456789},
|
||||||
|
expected_code=400,
|
||||||
|
)
|
||||||
|
self.assertIn('Invalid choice', str(response.data))
|
||||||
|
|
||||||
def test_options(self):
|
def test_options(self):
|
||||||
"""Test the StockItem OPTIONS endpoint to contain custom StockStatuses."""
|
"""Test the StockItem OPTIONS endpoint to contain custom StockStatuses."""
|
||||||
response = self.options(self.list_url)
|
response = self.options(self.list_url)
|
||||||
|
@ -380,7 +380,7 @@ function stockItemFields(options={}) {
|
|||||||
batch: {
|
batch: {
|
||||||
icon: 'fa-layer-group',
|
icon: 'fa-layer-group',
|
||||||
},
|
},
|
||||||
status: {},
|
status_custom_key: {},
|
||||||
expiry_date: {
|
expiry_date: {
|
||||||
icon: 'fa-calendar-alt',
|
icon: 'fa-calendar-alt',
|
||||||
},
|
},
|
||||||
|
@ -138,7 +138,7 @@ export function useStockFields({
|
|||||||
value: batchCode,
|
value: batchCode,
|
||||||
onValueChange: (value) => setBatchCode(value)
|
onValueChange: (value) => setBatchCode(value)
|
||||||
},
|
},
|
||||||
status: {},
|
status_custom_key: {},
|
||||||
expiry_date: {
|
expiry_date: {
|
||||||
// TODO: icon
|
// TODO: icon
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user