2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-08-09 21:30:54 +00:00
Files
InvenTree/InvenTree/company/serializers.py
Oliver 258957c14c SupplierPart availability (#3148)
* Adds new fields to the SupplierPart model:

- available
- availability_updated

* Allow availability_updated field to be blank

* Revert "Remove stat context variables"

This reverts commit 0989c308d0.

* Increment API version

* Adds availability information to the SupplierPart API serializer

- If the 'available' field is updated, the current date is added to the availability_updated field

* Add 'available' field to SupplierPart table

* More JS refactoring

* Add unit testing for specifying availability via the API

* Display availability data on the SupplierPart detail page

* Add ability to set 'available' quantity from the SupplierPart detail page

* Revert "Revert "Remove stat context variables""

This reverts commit 3f98037f79.
2022-06-08 21:49:07 +10:00

340 lines
9.7 KiB
Python

"""JSON serializers for Company app."""
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from sql_util.utils import SubqueryCount
from common.settings import currency_code_default, currency_code_mappings
from InvenTree.serializers import (InvenTreeAttachmentSerializer,
InvenTreeDecimalField,
InvenTreeImageSerializerField,
InvenTreeModelSerializer,
InvenTreeMoneySerializer)
from part.serializers import PartBriefSerializer
from .models import (Company, ManufacturerPart, ManufacturerPartAttachment,
ManufacturerPartParameter, SupplierPart,
SupplierPriceBreak)
class CompanyBriefSerializer(InvenTreeModelSerializer):
"""Serializer for Company object (limited detail)"""
url = serializers.CharField(source='get_absolute_url', read_only=True)
image = serializers.CharField(source='get_thumbnail_url', read_only=True)
class Meta:
"""Metaclass options."""
model = Company
fields = [
'pk',
'url',
'name',
'description',
'image',
]
class CompanySerializer(InvenTreeModelSerializer):
"""Serializer for Company object (full detail)"""
@staticmethod
def annotate_queryset(queryset):
"""Annoate the supplied queryset with aggregated information"""
# Add count of parts manufactured
queryset = queryset.annotate(
parts_manufactured=SubqueryCount('manufactured_parts')
)
queryset = queryset.annotate(
parts_supplied=SubqueryCount('supplied_parts')
)
return queryset
url = serializers.CharField(source='get_absolute_url', read_only=True)
image = InvenTreeImageSerializerField(required=False, allow_null=True)
parts_supplied = serializers.IntegerField(read_only=True)
parts_manufactured = serializers.IntegerField(read_only=True)
currency = serializers.ChoiceField(
choices=currency_code_mappings(),
initial=currency_code_default,
help_text=_('Default currency used for this supplier'),
label=_('Currency Code'),
required=True,
)
class Meta:
"""Metaclass options."""
model = Company
fields = [
'pk',
'url',
'name',
'description',
'website',
'name',
'phone',
'address',
'email',
'currency',
'contact',
'link',
'image',
'is_customer',
'is_manufacturer',
'is_supplier',
'notes',
'parts_supplied',
'parts_manufactured',
]
class ManufacturerPartSerializer(InvenTreeModelSerializer):
"""Serializer for ManufacturerPart object."""
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
manufacturer_detail = CompanyBriefSerializer(source='manufacturer', many=False, read_only=True)
pretty_name = serializers.CharField(read_only=True)
def __init__(self, *args, **kwargs):
"""Initialize this serializer with extra detail fields as required"""
part_detail = kwargs.pop('part_detail', True)
manufacturer_detail = kwargs.pop('manufacturer_detail', True)
prettify = kwargs.pop('pretty', False)
super(ManufacturerPartSerializer, self).__init__(*args, **kwargs)
if part_detail is not True:
self.fields.pop('part_detail')
if manufacturer_detail is not True:
self.fields.pop('manufacturer_detail')
if prettify is not True:
self.fields.pop('pretty_name')
manufacturer = serializers.PrimaryKeyRelatedField(queryset=Company.objects.filter(is_manufacturer=True))
class Meta:
"""Metaclass options."""
model = ManufacturerPart
fields = [
'pk',
'part',
'part_detail',
'pretty_name',
'manufacturer',
'manufacturer_detail',
'description',
'MPN',
'link',
]
class ManufacturerPartAttachmentSerializer(InvenTreeAttachmentSerializer):
"""Serializer for the ManufacturerPartAttachment class."""
class Meta:
"""Metaclass options."""
model = ManufacturerPartAttachment
fields = [
'pk',
'manufacturer_part',
'attachment',
'filename',
'link',
'comment',
'upload_date',
'user',
'user_detail',
]
read_only_fields = [
'upload_date',
]
class ManufacturerPartParameterSerializer(InvenTreeModelSerializer):
"""Serializer for the ManufacturerPartParameter model."""
manufacturer_part_detail = ManufacturerPartSerializer(source='manufacturer_part', many=False, read_only=True)
def __init__(self, *args, **kwargs):
"""Initialize this serializer with extra detail fields as required"""
man_detail = kwargs.pop('manufacturer_part_detail', False)
super(ManufacturerPartParameterSerializer, self).__init__(*args, **kwargs)
if not man_detail:
self.fields.pop('manufacturer_part_detail')
class Meta:
"""Metaclass options."""
model = ManufacturerPartParameter
fields = [
'pk',
'manufacturer_part',
'manufacturer_part_detail',
'name',
'value',
'units',
]
class SupplierPartSerializer(InvenTreeModelSerializer):
"""Serializer for SupplierPart object."""
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True)
manufacturer_detail = CompanyBriefSerializer(source='manufacturer_part.manufacturer', many=False, read_only=True)
pretty_name = serializers.CharField(read_only=True)
def __init__(self, *args, **kwargs):
"""Initialize this serializer with extra detail fields as required"""
# Check if 'available' quantity was supplied
self.has_available_quantity = 'available' in kwargs.get('data', {})
part_detail = kwargs.pop('part_detail', True)
supplier_detail = kwargs.pop('supplier_detail', True)
manufacturer_detail = kwargs.pop('manufacturer_detail', True)
prettify = kwargs.pop('pretty', False)
super(SupplierPartSerializer, self).__init__(*args, **kwargs)
if part_detail is not True:
self.fields.pop('part_detail')
if supplier_detail is not True:
self.fields.pop('supplier_detail')
if manufacturer_detail is not True:
self.fields.pop('manufacturer_detail')
if prettify is not True:
self.fields.pop('pretty_name')
supplier = serializers.PrimaryKeyRelatedField(queryset=Company.objects.filter(is_supplier=True))
manufacturer = serializers.CharField(read_only=True)
MPN = serializers.CharField(read_only=True)
manufacturer_part_detail = ManufacturerPartSerializer(source='manufacturer_part', read_only=True)
class Meta:
"""Metaclass options."""
model = SupplierPart
fields = [
'available',
'availability_updated',
'description',
'link',
'manufacturer',
'manufacturer_detail',
'manufacturer_part',
'manufacturer_part_detail',
'MPN',
'note',
'pk',
'packaging',
'part',
'part_detail',
'pretty_name',
'SKU',
'supplier',
'supplier_detail',
]
read_only_fields = [
'availability_updated',
]
def update(self, supplier_part, data):
"""Custom update functionality for the serializer"""
available = data.pop('available', None)
response = super().update(supplier_part, data)
if available is not None and self.has_available_quantity:
supplier_part.update_available_quantity(available)
return response
def create(self, validated_data):
"""Extract manufacturer data and process ManufacturerPart."""
# Extract 'available' quantity from the serializer
available = validated_data.pop('available', None)
# Create SupplierPart
supplier_part = super().create(validated_data)
if available is not None and self.has_available_quantity:
supplier_part.update_available_quantity(available)
# Get ManufacturerPart raw data (unvalidated)
manufacturer = self.initial_data.get('manufacturer', None)
MPN = self.initial_data.get('MPN', None)
if manufacturer and MPN:
kwargs = {
'manufacturer': manufacturer,
'MPN': MPN,
}
supplier_part.save(**kwargs)
return supplier_part
class SupplierPriceBreakSerializer(InvenTreeModelSerializer):
"""Serializer for SupplierPriceBreak object."""
quantity = InvenTreeDecimalField()
price = InvenTreeMoneySerializer(
allow_null=True,
required=True,
label=_('Price'),
)
price_currency = serializers.ChoiceField(
choices=currency_code_mappings(),
default=currency_code_default,
label=_('Currency'),
)
class Meta:
"""Metaclass options."""
model = SupplierPriceBreak
fields = [
'pk',
'part',
'quantity',
'price',
'price_currency',
'updated',
]