mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Actually receive items
This commit is contained in:
parent
2aa505b2cb
commit
d30173132a
@ -5,7 +5,9 @@ JSON API for the Order app
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf.urls import url, include
|
||||
from django.db import transaction
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import generics
|
||||
@ -13,7 +15,6 @@ from rest_framework import filters, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.api import AttachmentMixin
|
||||
@ -252,25 +253,34 @@ class POReceive(generics.CreateAPIView):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Check that the received line items are indeed correct
|
||||
self.validate(serializer.validated_data)
|
||||
# Receive the line items
|
||||
self.receive_items(serializer)
|
||||
|
||||
headers = self.get_success_headers(serializer.data)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
def validate(self, data):
|
||||
@transaction.atomic
|
||||
def receive_items(self, serializer):
|
||||
"""
|
||||
Validate the deserialized data.
|
||||
Receive the items
|
||||
|
||||
At this point, much of the heavy lifting has been done for us by DRF serializers
|
||||
At this point, much of the heavy lifting has been done for us by DRF serializers!
|
||||
|
||||
We have a list of "items", each a dict which contains:
|
||||
- line_item: A PurchaseOrderLineItem matching this order
|
||||
- location: A destination location
|
||||
- quantity: A validated numerical quantity
|
||||
- status: The status code for the received item
|
||||
"""
|
||||
|
||||
data = serializer.validated_data
|
||||
|
||||
location = data['location']
|
||||
|
||||
# Keep track of validated data "on the fly"
|
||||
self.items = []
|
||||
items = data['items']
|
||||
|
||||
for item in data['items']:
|
||||
# Check if the location is not specified for any particular item
|
||||
for item in items:
|
||||
|
||||
supplier_part = item['supplier_part']
|
||||
|
||||
@ -287,7 +297,15 @@ class POReceive(generics.CreateAPIView):
|
||||
|
||||
item['location'] = location
|
||||
|
||||
quantity = item['quantity']
|
||||
# Now we can actually receive the items
|
||||
for item in items:
|
||||
self.order.receive_line_item(
|
||||
item['line_item'],
|
||||
item['location'],
|
||||
item['quantity'],
|
||||
self.request.user,
|
||||
status=item['status'],
|
||||
)
|
||||
|
||||
|
||||
class POLineItemList(generics.ListCreateAPIView):
|
||||
|
@ -433,7 +433,7 @@ class PurchaseOrder(Order):
|
||||
quantity=quantity,
|
||||
purchase_order=self,
|
||||
status=status,
|
||||
purchase_price=purchase_price,
|
||||
purchase_price=line.purchase_price,
|
||||
)
|
||||
|
||||
stock.save(add_note=False)
|
||||
|
@ -20,6 +20,8 @@ from InvenTree.serializers import InvenTreeAttachmentSerializer
|
||||
from InvenTree.serializers import InvenTreeMoneySerializer
|
||||
from InvenTree.serializers import InvenTreeAttachmentSerializerField
|
||||
|
||||
from InvenTree.status_codes import StockStatus
|
||||
|
||||
import company.models
|
||||
from company.serializers import CompanyBriefSerializer, SupplierPartSerializer
|
||||
|
||||
@ -200,10 +202,17 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
||||
required=True,
|
||||
)
|
||||
|
||||
status = serializers.ChoiceField(
|
||||
choices=StockStatus.options,
|
||||
default=StockStatus.OK,
|
||||
label=_('Status'),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = [
|
||||
'supplier_part',
|
||||
'location',
|
||||
'status',
|
||||
]
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
Tests for the Order API
|
||||
"""
|
||||
|
||||
from InvenTree.stock.models import StockItem
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from rest_framework import status
|
||||
@ -213,6 +214,9 @@ class PurchaseOrderReceiveTest(OrderTest):
|
||||
|
||||
self.url = reverse('api-po-receive', kwargs={'pk': 1})
|
||||
|
||||
# Number of stock items which exist at the start of each test
|
||||
self.n = StockItem.objects.count()
|
||||
|
||||
def test_empty(self):
|
||||
"""
|
||||
Test without any POST data
|
||||
@ -223,6 +227,9 @@ class PurchaseOrderReceiveTest(OrderTest):
|
||||
self.assertIn('This field is required', str(data['items']))
|
||||
self.assertIn('This field is required', str(data['location']))
|
||||
|
||||
# No new stock items have been created
|
||||
self.assertEqual(self.n, StockItem.objects.count())
|
||||
|
||||
def test_no_items(self):
|
||||
"""
|
||||
Test with an empty list of items
|
||||
@ -239,6 +246,9 @@ class PurchaseOrderReceiveTest(OrderTest):
|
||||
|
||||
self.assertIn('Line items must be provided', str(data['items']))
|
||||
|
||||
# No new stock items have been created
|
||||
self.assertEqual(self.n, StockItem.objects.count())
|
||||
|
||||
def test_invalid_items(self):
|
||||
"""
|
||||
Test than errors are returned as expected for invalid data
|
||||
@ -262,6 +272,34 @@ class PurchaseOrderReceiveTest(OrderTest):
|
||||
self.assertIn('Invalid pk "12345"', str(items['line_item']))
|
||||
self.assertIn("object does not exist", str(items['location']))
|
||||
|
||||
# No new stock items have been created
|
||||
self.assertEqual(self.n, StockItem.objects.count())
|
||||
|
||||
def test_invalid_status(self):
|
||||
"""
|
||||
Test with an invalid StockStatus value
|
||||
"""
|
||||
|
||||
data = self.post(
|
||||
self.url,
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"line_item": 22,
|
||||
"location": 1,
|
||||
"status": 99999,
|
||||
"quantity": 5,
|
||||
}
|
||||
]
|
||||
},
|
||||
expected_code=400
|
||||
).data
|
||||
|
||||
self.assertIn('"99999" is not a valid choice.', str(data))
|
||||
|
||||
# No new stock items have been created
|
||||
self.assertEqual(self.n, StockItem.objects.count())
|
||||
|
||||
def test_mismatched_items(self):
|
||||
"""
|
||||
Test for supplier parts which *do* exist but do not match the order supplier
|
||||
@ -284,6 +322,9 @@ class PurchaseOrderReceiveTest(OrderTest):
|
||||
|
||||
self.assertIn('Line item does not match purchase order', str(data))
|
||||
|
||||
# No new stock items have been created
|
||||
self.assertEqual(self.n, StockItem.objects.count())
|
||||
|
||||
|
||||
class SalesOrderTest(OrderTest):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user