mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-03 13:58:47 +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
|
return self.lines.count() > 0 and self.pending_line_items().count() == 0
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def receive_line_item(self, line, location, quantity, user, status=StockStatus.OK, purchase_price=None, **kwargs):
|
def receive_line_item(self, line, location, quantity, user, status=StockStatus.OK, **kwargs):
|
||||||
""" Receive a line item (or partial line item) against this PO
|
"""
|
||||||
|
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', '')
|
notes = kwargs.get('notes', '')
|
||||||
barcode = kwargs.get('barcode', '')
|
|
||||||
|
# Extract optional barcode field
|
||||||
|
barcode = kwargs.get('barcode', None)
|
||||||
|
|
||||||
# Prevent null values for barcode
|
# Prevent null values for barcode
|
||||||
if barcode is None:
|
if barcode is None:
|
||||||
@ -427,33 +437,44 @@ class PurchaseOrder(Order):
|
|||||||
|
|
||||||
# Create a new stock item
|
# Create a new stock item
|
||||||
if line.part and quantity > 0:
|
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 = {
|
for sn in serials:
|
||||||
'status': status,
|
|
||||||
'purchaseorder': self.pk,
|
|
||||||
}
|
|
||||||
|
|
||||||
stock.add_tracking_entry(
|
stock = stock_models.StockItem(
|
||||||
StockHistoryCode.RECEIVED_AGAINST_PURCHASE_ORDER,
|
part=line.part.part,
|
||||||
user,
|
supplier_part=line.part,
|
||||||
notes=notes,
|
location=location,
|
||||||
deltas=tracking_info,
|
quantity=quantity,
|
||||||
location=location,
|
purchase_order=self,
|
||||||
purchaseorder=self,
|
status=status,
|
||||||
quantity=quantity
|
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
|
# Update the number of parts received against the particular line item
|
||||||
line.received += quantity
|
line.received += quantity
|
||||||
|
@ -5,6 +5,8 @@ JSON serializers for the Order API
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
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
|
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(
|
line_item = serializers.PrimaryKeyRelatedField(
|
||||||
queryset=order.models.PurchaseOrderLineItem.objects.all(),
|
queryset=order.models.PurchaseOrderLineItem.objects.all(),
|
||||||
many=False,
|
many=False,
|
||||||
@ -241,6 +254,22 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
return quantity
|
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(
|
status = serializers.ChoiceField(
|
||||||
choices=list(StockStatus.items()),
|
choices=list(StockStatus.items()),
|
||||||
default=StockStatus.OK,
|
default=StockStatus.OK,
|
||||||
@ -270,15 +299,35 @@ class POLineItemReceiveSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
return barcode
|
return barcode
|
||||||
|
|
||||||
class Meta:
|
def validate(self, data):
|
||||||
fields = [
|
|
||||||
'barcode',
|
|
||||||
'line_item',
|
|
||||||
'location',
|
|
||||||
'quantity',
|
|
||||||
'status',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
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):
|
class POReceiveSerializer(serializers.Serializer):
|
||||||
"""
|
"""
|
||||||
@ -366,6 +415,8 @@ class POReceiveSerializer(serializers.Serializer):
|
|||||||
request.user,
|
request.user,
|
||||||
status=item['status'],
|
status=item['status'],
|
||||||
barcode=item.get('barcode', ''),
|
barcode=item.get('barcode', ''),
|
||||||
|
batch_code=item.get('batch_code', ''),
|
||||||
|
serials=item.get('serials', None),
|
||||||
)
|
)
|
||||||
except (ValidationError, DjangoValidationError) as exc:
|
except (ValidationError, DjangoValidationError) as exc:
|
||||||
# Catch model errors and re-throw as DRF errors
|
# Catch model errors and re-throw as DRF errors
|
||||||
|
Loading…
x
Reference in New Issue
Block a user