2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 13:05:42 +00:00

Add Metadata to further models (#4410)

* Add metadata for ManufacturerPart

* Add Metadata for SupplierPart

* Add metadata to label models

* Add metadata to order line items

* Add metadata to shipment

* Add metadata to Build and BuildItem

* Add metadata to BomItem

* Add metadata to PartParameterTemplate

* Syntax, lint

* Fix isort style

* Lint

* Correction of model name

* Metadata for Reports

* Fix silly error

* Fix silly error

* Correct model name

* Correct model name

* Correction

* Correct company urls

* Apply generic model to Report metadat

* Rename/remove redundant import

* Remove shadowing of report in loop variable

* Update import ordering

* More corrections

* better docstrings

* Correct names for API endpoints

* Default to PO, required for api-doc to work

* Changes by @matmair

* Suppress metadata from Bom export

* Add migration files

* Increment API version

* Add tests for all Metadata models, even previously existing ones

* Update tests

* Fix

* Delay tests

* Fix imports

* Fix tests

* API Version number

* Remove unused import

* isort

* Revent  unintended change of cache
This commit is contained in:
miggland
2023-03-23 11:51:08 +01:00
committed by GitHub
parent 4e72ac303f
commit 807784d9e4
32 changed files with 642 additions and 40 deletions

View File

@ -318,7 +318,7 @@ class BomItemResource(InvenTreeResource):
is_importing = getattr(self, 'is_importing', False)
include_pricing = getattr(self, 'include_pricing', False)
to_remove = []
to_remove = ['metadata']
if is_importing or not include_pricing:
# Remove pricing fields in this instance

View File

@ -1459,6 +1459,16 @@ class PartParameterTemplateDetail(RetrieveUpdateDestroyAPI):
serializer_class = part_serializers.PartParameterTemplateSerializer
class PartParameterTemplateMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartParameterTemplate metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartParameterTemplate instance"""
return MetadataSerializer(PartParameterTemplate, *args, **kwargs)
queryset = PartParameterTemplate.objects.all()
class PartParameterList(ListCreateAPI):
"""API endpoint for accessing a list of PartParameter objects.
@ -1926,6 +1936,16 @@ class BomItemSubstituteDetail(RetrieveUpdateDestroyAPI):
serializer_class = part_serializers.BomItemSubstituteSerializer
class BomItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartBOM metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartCategory instance"""
return MetadataSerializer(BomItem, *args, **kwargs)
queryset = BomItem.objects.all()
part_api_urls = [
# Base URL for PartCategory API endpoints
@ -1933,8 +1953,8 @@ part_api_urls = [
re_path(r'^tree/', CategoryTree.as_view(), name='api-part-category-tree'),
re_path(r'^parameters/', include([
re_path('^(?P<pk>\d+)/', CategoryParameterDetail.as_view(), name='api-part-category-parameter-detail'),
re_path('^.*$', CategoryParameterList.as_view(), name='api-part-category-parameter-list'),
re_path(r'^(?P<pk>\d+)/', CategoryParameterDetail.as_view(), name='api-part-category-parameter-detail'),
re_path(r'^.*$', CategoryParameterList.as_view(), name='api-part-category-parameter-list'),
])),
# Category detail endpoints
@ -1982,7 +2002,10 @@ part_api_urls = [
# Base URL for PartParameter API endpoints
re_path(r'^parameter/', include([
path('template/', include([
re_path(r'^(?P<pk>\d+)/', PartParameterTemplateDetail.as_view(), name='api-part-parameter-template-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^metadata/?', PartParameterTemplateMetadata.as_view(), name='api-part-parameter-template-metadata'),
re_path(r'^.*$', PartParameterTemplateDetail.as_view(), name='api-part-parameter-template-detail'),
])),
re_path(r'^.*$', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'),
])),
@ -2059,6 +2082,7 @@ bom_api_urls = [
# BOM Item Detail
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^validate/?', BomItemValidate.as_view(), name='api-bom-item-validate'),
re_path(r'^metadata/?', BomItemMetadata.as_view(), name='api-bom-item-metadata'),
re_path(r'^.*$', BomDetail.as_view(), name='api-bom-item-detail'),
])),

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.18 on 2023-03-17 08:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0102_auto_20230314_0112'),
]
operations = [
migrations.AddField(
model_name='bomitem',
name='metadata',
field=models.JSONField(blank=True, help_text='JSON metadata field, for use by external plugins', null=True, verbose_name='Plugin Metadata'),
),
migrations.AddField(
model_name='partparametertemplate',
name='metadata',
field=models.JSONField(blank=True, help_text='JSON metadata field, for use by external plugins', null=True, verbose_name='Plugin Metadata'),
),
]

View File

@ -3277,7 +3277,7 @@ def validate_template_name(name):
"""Placeholder for legacy function used in migrations."""
class PartParameterTemplate(models.Model):
class PartParameterTemplate(MetadataMixin, models.Model):
"""A PartParameterTemplate provides a template for key:value pairs for extra parameters fields/values to be added to a Part.
This allows users to arbitrarily assign data fields to a Part beyond the built-in attributes.
@ -3419,7 +3419,7 @@ class PartCategoryParameterTemplate(models.Model):
help_text=_('Default Parameter Value'))
class BomItem(DataImportMixin, models.Model):
class BomItem(DataImportMixin, MetadataMixin, models.Model):
"""A BomItem links a part to its component items.
A part can have a BOM (bill of materials) which defines

View File

@ -245,3 +245,21 @@ class BomItemTest(TestCase):
)
self.assertEqual(assembly.can_build, 20)
def test_metadata(self):
"""Unit tests for the metadata field."""
for model in [BomItem]:
p = model.objects.first()
self.assertIsNone(p.metadata)
self.assertIsNone(p.get_metadata('test'))
self.assertEqual(p.get_metadata('test', backup_value=123), 123)
# Test update via the set_metadata() method
p.set_metadata('test', 3)
self.assertEqual(p.get_metadata('test'), 3)
for k in ['apple', 'banana', 'carrot', 'carrot', 'banana']:
p.set_metadata(k, k)
self.assertEqual(len(p.metadata.keys()), 4)

View File

@ -43,6 +43,24 @@ class TestParams(TestCase):
t3.full_clean()
t3.save() # pragma: no cover
def test_metadata(self):
"""Unit tests for the metadata field."""
for model in [PartParameterTemplate]:
p = model.objects.first()
self.assertIsNone(p.metadata)
self.assertIsNone(p.get_metadata('test'))
self.assertEqual(p.get_metadata('test', backup_value=123), 123)
# Test update via the set_metadata() method
p.set_metadata('test', 3)
self.assertEqual(p.get_metadata('test'), 3)
for k in ['apple', 'banana', 'carrot', 'carrot', 'banana']:
p.set_metadata(k, k)
self.assertEqual(len(p.metadata.keys()), 4)
class TestCategoryTemplates(TransactionTestCase):
"""Test class for PartCategoryParameterTemplate model"""

View File

@ -274,21 +274,22 @@ class PartTest(TestCase):
self.assertEqual(float(self.r1.get_internal_price(10)), 0.5)
def test_metadata(self):
"""Unit tests for the Part metadata field."""
p = Part.objects.get(pk=1)
self.assertIsNone(p.metadata)
"""Unit tests for the metadata field."""
for model in [Part]:
p = model.objects.first()
self.assertIsNone(p.metadata)
self.assertIsNone(p.get_metadata('test'))
self.assertEqual(p.get_metadata('test', backup_value=123), 123)
self.assertIsNone(p.get_metadata('test'))
self.assertEqual(p.get_metadata('test', backup_value=123), 123)
# Test update via the set_metadata() method
p.set_metadata('test', 3)
self.assertEqual(p.get_metadata('test'), 3)
# Test update via the set_metadata() method
p.set_metadata('test', 3)
self.assertEqual(p.get_metadata('test'), 3)
for k in ['apple', 'banana', 'carrot', 'carrot', 'banana']:
p.set_metadata(k, k)
for k in ['apple', 'banana', 'carrot', 'carrot', 'banana']:
p.set_metadata(k, k)
self.assertEqual(len(p.metadata.keys()), 4)
self.assertEqual(len(p.metadata.keys()), 4)
def test_related(self):
"""Unit tests for the PartRelated model"""