mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add "batch code" and "serial numbers" serializer fields when receiving stock items against a purchase order
This commit is contained in:
parent
010ce48ce0
commit
73484192a5
@ -398,12 +398,22 @@ class PurchaseOrder(Order):
|
||||
return self.lines.count() > 0 and self.pending_line_items().count() == 0
|
||||
|
||||
@transaction.atomic
|
||||
def receive_line_item(self, line, location, quantity, user, status=StockStatus.OK, purchase_price=None, **kwargs):
|
||||
""" Receive a line item (or partial line item) against this PO
|
||||
def receive_line_item(self, line, location, quantity, user, status=StockStatus.OK, **kwargs):
|
||||
"""
|
||||
Receive a line item (or partial line item) against this PO
|
||||
"""
|
||||
|
||||
# Extract optional batch code for the new stock item
|
||||
batch_code = kwargs.get('batch_code', '')
|
||||
|
||||
# Extract optional list of serial numbers
|
||||
serials = kwargs.get('serials', None)
|
||||
|
||||
# Extract optional notes field
|
||||
notes = kwargs.get('notes', '')
|
||||
barcode = kwargs.get('barcode', '')
|
||||
|
||||
# Extract optional barcode field
|
||||
barcode = kwargs.get('barcode', None)
|
||||
|
||||
# Prevent null values for barcode
|
||||
if barcode is None:
|
||||
@ -427,33 +437,44 @@ class PurchaseOrder(Order):
|
||||
|
||||
# Create a new stock item
|
||||
if line.part and quantity > 0:
|
||||
stock = stock_models.StockItem(
|
||||
part=line.part.part,
|
||||
supplier_part=line.part,
|
||||
location=location,
|
||||
quantity=quantity,
|
||||
purchase_order=self,
|
||||
status=status,
|
||||
purchase_price=line.purchase_price,
|
||||
uid=barcode
|
||||
)
|
||||
|
||||
stock.save(add_note=False)
|
||||
# Determine if we should individually serialize the items, or not
|
||||
if type(serials) is list and len(serials) > 0:
|
||||
quantity = 1
|
||||
else:
|
||||
serials = [None]
|
||||
|
||||
tracking_info = {
|
||||
'status': status,
|
||||
'purchaseorder': self.pk,
|
||||
}
|
||||
for sn in serials:
|
||||
|
||||
stock.add_tracking_entry(
|
||||
StockHistoryCode.RECEIVED_AGAINST_PURCHASE_ORDER,
|
||||
user,
|
||||
notes=notes,
|
||||
deltas=tracking_info,
|
||||
location=location,
|
||||
purchaseorder=self,
|
||||
quantity=quantity
|
||||
)
|
||||
stock = stock_models.StockItem(
|
||||
part=line.part.part,
|
||||
supplier_part=line.part,
|
||||
location=location,
|
||||
quantity=quantity,
|
||||
purchase_order=self,
|
||||
status=status,
|
||||
batch=batch_code,
|
||||
serial=sn,
|
||||
purchase_price=line.purchase_price,
|
||||
uid=barcode
|
||||
)
|
||||
|
||||
stock.save(add_note=False)
|
||||
|
||||
tracking_info = {
|
||||
'status': status,
|
||||
'purchaseorder': self.pk,
|
||||
}
|
||||
|
||||
stock.add_tracking_entry(
|
||||
StockHistoryCode.RECEIVED_AGAINST_PURCHASE_ORDER,
|
||||
user,
|
||||
notes=notes,
|
||||
deltas=tracking_info,
|
||||
location=location,
|
||||
purchaseorder=self,
|
||||
quantity=quantity
|
||||
)
|
||||
|
||||
# Update the number of parts received against the particular line item
|
||||
line.received += quantity
|
||||
|
@ -5,6 +5,8 @@ JSON serializers for the Order API
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
@ -203,6 +205,17 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
||||
A serializer for receiving a single purchase order line item against a purchase order
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
fields = [
|
||||
'barcode',
|
||||
'line_item',
|
||||
'location',
|
||||
'quantity',
|
||||
'status',
|
||||
'batch_code'
|
||||
'serial_numbers',
|
||||
]
|
||||
|
||||
line_item = serializers.PrimaryKeyRelatedField(
|
||||
queryset=order.models.PurchaseOrderLineItem.objects.all(),
|
||||
many=False,
|
||||
@ -241,6 +254,22 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
||||
|
||||
return quantity
|
||||
|
||||
batch_code = serializers.CharField(
|
||||
label=_('Batch Code'),
|
||||
help_text=_('Enter batch code for incoming stock items'),
|
||||
required=False,
|
||||
default='',
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
serial_numbers = serializers.CharField(
|
||||
label=_('Serial Numbers'),
|
||||
help_text=_('Enter serial numbers for incoming stock items'),
|
||||
required=False,
|
||||
default='',
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
status = serializers.ChoiceField(
|
||||
choices=list(StockStatus.items()),
|
||||
default=StockStatus.OK,
|
||||
@ -270,15 +299,35 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
||||
|
||||
return barcode
|
||||
|
||||
class Meta:
|
||||
fields = [
|
||||
'barcode',
|
||||
'line_item',
|
||||
'location',
|
||||
'quantity',
|
||||
'status',
|
||||
]
|
||||
def validate(self, data):
|
||||
|
||||
data = super().validate(data)
|
||||
|
||||
line_item = data['line_item']
|
||||
quantity = data['quantity']
|
||||
serial_numbers = data.get('serial_numbers', '').strip()
|
||||
|
||||
base_part = line_item.part.part
|
||||
|
||||
# Does the quantity need to be "integer" (for trackable parts?)
|
||||
if base_part.trackable:
|
||||
|
||||
if Decimal(quantity) != int(quantity):
|
||||
raise ValidationError({
|
||||
'quantity': _('An integer quantity must be provided for trackable parts'),
|
||||
})
|
||||
|
||||
# If serial numbers are provided
|
||||
if serial_numbers:
|
||||
try:
|
||||
# Pass the serial numbers through to the parent serializer once validated
|
||||
data['serials'] = extract_serial_numbers(serial_numbers, quantity, base_part.getLatestSerialNumberInt())
|
||||
except DjangoValidationError as e:
|
||||
raise ValidationError({
|
||||
'serial_numbers': e.messages,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
class POReceiveSerializer(serializers.Serializer):
|
||||
"""
|
||||
@ -366,6 +415,8 @@ class POReceiveSerializer(serializers.Serializer):
|
||||
request.user,
|
||||
status=item['status'],
|
||||
barcode=item.get('barcode', ''),
|
||||
batch_code=item.get('batch_code', ''),
|
||||
serials=item.get('serials', None),
|
||||
)
|
||||
except (ValidationError, DjangoValidationError) as exc:
|
||||
# Catch model errors and re-throw as DRF errors
|
||||
|
Loading…
Reference in New Issue
Block a user