2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 03:00:54 +00:00

Add 'Tag' management (#4367)

* 'Tag' management
Fixes #83

* Add for ManufacturerPart, SupplierPart

* Add tags for StockLocation, StockItem

* fix serializer definition

* add migrations

* update pre-commit

* bump dependencies

* revert updates

* set version for bugbear

* remove bugbear

* readd bugbear remove isort

* and remove bugbear again

* remove bugbear

* make tag fields not required

* add ruleset

* Merge migrations

* fix migrations

* add unittest for detail

* test tag add

* order api

* reduce database access

* add tag modification test

* use overriden serializer to ensuer the manager is always available

* fix typo

* fix serializer

* increae query thershold by 1

* move tag serializer

* fix migrations

* content_types are changing between tests - removing them

* remove unneeded fixture

* Add basic docs

* bump API version

* add api access to the docs

* add python code

* Add tags to search and filters for all models
This commit is contained in:
Matthias Mair
2023-05-04 01:02:48 +02:00
committed by GitHub
parent baaa147fd0
commit f5c2591fd4
22 changed files with 258 additions and 14 deletions

View File

@ -214,7 +214,9 @@ class StockLocationList(APIDownloadMixin, ListCreateAPI):
- POST: Create a new StockLocation
"""
queryset = StockLocation.objects.all()
queryset = StockLocation.objects.all().prefetch_related(
'tags',
)
serializer_class = StockSerializers.LocationSerializer
def download_queryset(self, queryset, export_format):
@ -300,11 +302,15 @@ class StockLocationList(APIDownloadMixin, ListCreateAPI):
'name',
'structural',
'external',
'tags__name',
'tags__slug',
]
search_fields = [
'name',
'description',
'tags__name',
'tags__slug',
]
ordering_fields = [
@ -351,6 +357,8 @@ class StockFilter(rest_filters.FilterSet):
'customer',
'sales_order',
'purchase_order',
'tags__name',
'tags__slug',
]
# Relationship filters
@ -811,7 +819,8 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
queryset = queryset.prefetch_related(
'part',
'part__category',
'location'
'location',
'tags',
)
return queryset
@ -1035,6 +1044,8 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
'part__IPN',
'part__description',
'location__name',
'tags__name',
'tags__slug',
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.18 on 2023-04-27 20:33
from django.db import migrations
import taggit.managers
class Migration(migrations.Migration):
dependencies = [
('taggit', '0005_auto_20220424_2025'),
('stock', '0097_alter_stockitem_notes'),
]
operations = [
migrations.AddField(
model_name='stockitem',
name='tags',
field=taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'),
),
migrations.AddField(
model_name='stocklocation',
name='tags',
field=taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'),
),
]

View File

@ -21,6 +21,7 @@ from django.utils.translation import gettext_lazy as _
from jinja2 import Template
from mptt.managers import TreeManager
from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
import common.models
import InvenTree.helpers
@ -53,6 +54,8 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
verbose_name = _('Stock Location')
verbose_name_plural = _('Stock Locations')
tags = TaggableManager()
def delete_recursive(self, *args, **kwargs):
"""This function handles the recursive deletion of sub-locations depending on kwargs contents"""
delete_stock_items = kwargs.get('delete_stock_items', False)
@ -321,6 +324,8 @@ class StockItem(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, commo
}
}
tags = TaggableManager()
# A Query filter which will be re-used in multiple places to determine if a StockItem is actually "in stock"
IN_STOCK_FILTER = Q(
quantity__gt=0,

View File

@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.serializers import ValidationError
from sql_util.utils import SubqueryCount, SubquerySum
from taggit.serializers import TagListSerializerField
import common.models
import company.models
@ -76,7 +77,7 @@ class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer):
return value
class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
"""Serializer for a StockItem.
- Includes serialization for the linked part
@ -123,6 +124,8 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
'updated',
'purchase_price',
'purchase_price_currency',
'tags',
]
"""
@ -236,6 +239,8 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
purchase_order_reference = serializers.CharField(source='purchase_order.reference', read_only=True)
sales_order_reference = serializers.CharField(source='sales_order.reference', read_only=True)
tags = TagListSerializerField(required=False)
def __init__(self, *args, **kwargs):
"""Add detail fields."""
part_detail = kwargs.pop('part_detail', False)
@ -566,7 +571,7 @@ class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer):
]
class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
class LocationSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
"""Detailed information about a stock location."""
class Meta:
@ -587,6 +592,8 @@ class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
'icon',
'structural',
'external',
'tags',
]
read_only_fields = [
@ -610,6 +617,8 @@ class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
level = serializers.IntegerField(read_only=True)
tags = TagListSerializerField(required=False)
class StockItemAttachmentSerializer(InvenTree.serializers.InvenTreeAttachmentSerializer):
"""Serializer for StockItemAttachment model."""