2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-02-06 05:15:52 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into matmair/issue6281

This commit is contained in:
Matthias Mair
2025-01-12 04:58:35 +01:00
87 changed files with 40208 additions and 40479 deletions

View File

@@ -11,6 +11,10 @@ v299 - 2025-01-10 : https://github.com/inventree/InvenTree/pull/6293
- Removes a considerable amount of old auth endpoints
- Introduces allauth based REST API
v299 - 2025-01-10 - https://github.com/inventree/InvenTree/pull/8867
- Adds 'expiry_date' field to the PurchaseOrderReceive API endpoint
- Adds 'default_expiry` field to the PartBriefSerializer, affecting API endpoints which use it
v298 - 2025-01-07 - https://github.com/inventree/InvenTree/pull/8848
- Adds 'created_by' field to PurchaseOrder API endpoints
- Adds 'created_by' field to SalesOrder API endpoints

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -410,6 +410,7 @@ class PurchaseOrderReceive(PurchaseOrderContextMixin, CreateAPI):
- supplier_part: pk value of the supplier part
- quantity: quantity to receive
- status: stock item status
- expiry_date: stock item expiry date (optional)
- location: destination for stock item (optional)
- batch_code: the batch code for this stock item
- serial_numbers: serial numbers for this stock item

View File

@@ -796,10 +796,32 @@ class PurchaseOrder(TotalPriceMixin, Order):
def receive_line_item(
self, line, location, quantity, user, status=StockStatus.OK.value, **kwargs
):
"""Receive a line item (or partial line item) against this PurchaseOrder."""
"""Receive a line item (or partial line item) against this PurchaseOrder.
Arguments:
line: The PurchaseOrderLineItem to receive against
location: The StockLocation to receive the item into
quantity: The quantity to receive
user: The User performing the action
status: The StockStatus to assign to the item (default: StockStatus.OK)
Keyword Arguments:
barch_code: Optional batch code for the new StockItem
serials: Optional list of serial numbers to assign to the new StockItem(s)
notes: Optional notes field for the StockItem
packaging: Optional packaging field for the StockItem
barcode: Optional barcode field for the StockItem
Raises:
ValidationError: If the quantity is negative or otherwise invalid
ValidationError: If the order is not in the 'PLACED' state
"""
# Extract optional batch code for the new stock item
batch_code = kwargs.get('batch_code', '')
# Extract optional expiry date for the new stock item
expiry_date = kwargs.get('expiry_date')
# Extract optional list of serial numbers
serials = kwargs.get('serials')
@@ -863,6 +885,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
purchase_order=self,
status=status,
batch=batch_code,
expiry_date=expiry_date,
packaging=packaging,
serial=sn,
purchase_price=unit_purchase_price,

View File

@@ -717,6 +717,7 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
'quantity',
'status',
'batch_code',
'expiry_date',
'serial_numbers',
'packaging',
'note',
@@ -765,6 +766,13 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
allow_blank=True,
)
expiry_date = serializers.DateField(
label=_('Expiry Date'),
help_text=_('Enter expiry date for incoming stock items'),
required=False,
default=None,
)
serial_numbers = serializers.CharField(
label=_('Serial Numbers'),
help_text=_('Enter serial numbers for incoming stock items'),
@@ -967,6 +975,7 @@ class PurchaseOrderReceiveSerializer(serializers.Serializer):
status=item['status'],
barcode=item.get('barcode', ''),
batch_code=item.get('batch_code', ''),
expiry_date=item.get('expiry_date', None),
packaging=item.get('packaging', ''),
serials=item.get('serials', None),
notes=item.get('note', None),

View File

@@ -3,7 +3,7 @@
import base64
import io
import json
from datetime import datetime, timedelta
from datetime import date, datetime, timedelta
from django.core.exceptions import ValidationError
from django.db import connection
@@ -1061,12 +1061,20 @@ class PurchaseOrderReceiveTest(OrderTest):
self.assertEqual(line_1.received, 0)
self.assertEqual(line_2.received, 50)
one_week_from_today = date.today() + timedelta(days=7)
valid_data = {
'items': [
{'line_item': 1, 'quantity': 50, 'barcode': 'MY-UNIQUE-BARCODE-123'},
{
'line_item': 1,
'quantity': 50,
'expiry_date': one_week_from_today.strftime(r'%Y-%m-%d'),
'barcode': 'MY-UNIQUE-BARCODE-123',
},
{
'line_item': 2,
'quantity': 200,
'expiry_date': one_week_from_today.strftime(r'%Y-%m-%d'),
'location': 2, # Explicit location
'barcode': 'MY-UNIQUE-BARCODE-456',
},
@@ -1111,6 +1119,10 @@ class PurchaseOrderReceiveTest(OrderTest):
self.assertEqual(stock_1.last().location.pk, 1)
self.assertEqual(stock_2.last().location.pk, 2)
# Expiry dates should be set
self.assertEqual(stock_1.last().expiry_date, one_week_from_today)
self.assertEqual(stock_2.last().expiry_date, one_week_from_today)
# Barcodes should have been assigned to the stock items
self.assertTrue(
StockItem.objects.filter(barcode_data='MY-UNIQUE-BARCODE-123').exists()

View File

@@ -352,6 +352,7 @@ class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):
'barcode_hash',
'category_default_location',
'default_location',
'default_expiry',
'name',
'revision',
'full_name',