From e0d52843a45de3b2e891845b405f391d619218d5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 8 Dec 2021 23:01:26 +1100 Subject: [PATCH] Basic stock assignment serializer implementation --- InvenTree/company/fixtures/company.yaml | 1 + InvenTree/stock/api.py | 18 ++++ InvenTree/stock/serializers.py | 118 ++++++++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/InvenTree/company/fixtures/company.yaml b/InvenTree/company/fixtures/company.yaml index 3113d6209f..02a0a4e830 100644 --- a/InvenTree/company/fixtures/company.yaml +++ b/InvenTree/company/fixtures/company.yaml @@ -17,6 +17,7 @@ fields: name: Zerg Corp description: We eat the competition + is_customer: False - model: company.company pk: 4 diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 8a2d2fa051..26787878a8 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -163,6 +163,23 @@ class StockTransfer(StockAdjustView): serializer_class = StockSerializers.StockTransferSerializer +class StockAssign(generics.CreateAPIView): + """ + API endpoint for assigning stock to a particular customer + """ + + queryset = StockItem.objects.all() + serializer_class = StockSerializers.StockAssignmentSerializer + + def get_serializer_context(self): + + ctx = super().get_serializer_context() + + ctx['request'] = self.request + + return ctx + + class StockLocationList(generics.ListCreateAPIView): """ API endpoint for list view of StockLocation objects: @@ -1174,6 +1191,7 @@ stock_api_urls = [ url(r'^add/', StockAdd.as_view(), name='api-stock-add'), url(r'^remove/', StockRemove.as_view(), name='api-stock-remove'), url(r'^transfer/', StockTransfer.as_view(), name='api-stock-transfer'), + url(r'^assign/', StockAssign.as_view(), name='api-stock-assign'), # StockItemAttachment API endpoints url(r'^attachment/', include([ diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 9bd5ea64be..a7228a81d9 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -28,6 +28,8 @@ from .models import StockItemTestResult import common.models from common.settings import currency_code_default, currency_code_mappings + +import company.models from company.serializers import SupplierPartSerializer import InvenTree.helpers @@ -537,6 +539,122 @@ class StockTrackingSerializer(InvenTree.serializers.InvenTreeModelSerializer): ] +class StockAssignmentItemSerializer(serializers.Serializer): + """ + Serializer for a single StockItem with in StockAssignment request. + + Here, the particular StockItem is being assigned (manually) to a customer + + Fields: + - item: StockItem object + """ + + class Meta: + fields = [ + 'item', + ] + + item = serializers.PrimaryKeyRelatedField( + queryset=StockItem.objects.all(), + many=False, + allow_null=False, + required=True, + label=_('Stock Item'), + ) + + def validate_item(self, item): + + # The item must currently be "in stock" + if not item.in_stock: + raise ValidationError(_("Item must be in stock")) + + # The item must not be allocated to a sales order + if item.sales_order_allocations.count() > 0: + raise ValidationError(_("Item is allocated to a sales order")) + + # The item must not be allocated to a build order + if item.allocations.count() > 0: + raise ValidationError(_("Item is allocated to a build order")) + + return item + + +class StockAssignmentSerializer(serializers.Serializer): + """ + Serializer for assigning one (or more) stock items to a customer. + + This is a manual assignment process, separate for (for example) a Sales Order + """ + + class Meta: + fields = [ + 'items', + 'customer', + 'notes', + ] + + items = StockAssignmentItemSerializer( + many=True, + required=True, + ) + + customer = serializers.PrimaryKeyRelatedField( + queryset=company.models.Company.objects.all(), + many=False, + allow_null=False, + required=True, + label=_('Customer'), + help_text=_('Customer to assign stock items'), + ) + + def validate_customer(self, customer): + + if customer and not customer.is_customer: + raise ValidationError(_('Selected company is not a customer')) + + return customer + + notes = serializers.CharField( + required=False, + allow_blank=True, + label=_('Notes'), + help_text=_('Stock assignment notes'), + ) + + def validate(self, data): + + data = super().validate(data) + + items = data.get('items', []) + + if len(items) == 0: + raise ValidationError(_("A list of stock items must be provided")) + + return data + + def save(self): + + request = self.context['request'] + + user = getattr(request, 'user', None) + + data = self.validated_data + + items = data['items'] + customer = data['customer'] + notes = data.get('notes', '') + + with transaction.atomic(): + for item in items: + + stock_item = item['item'] + + stock_item.allocateToCustomer( + customer, + user=user, + notes=notes, + ) + class StockAdjustmentItemSerializer(serializers.Serializer): """ Serializer for a single StockItem within a stock adjument request.