From 8aed68a1d1b44877f217251a31207d54dc86c472 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 26 Nov 2021 23:20:27 +1100 Subject: [PATCH] Adds "shipped" field to SalesOrderLineItem - This is an internal tracker of quantity of items shipped - Updated by the database logic (not by the user) - Keeps track of how many items have been shipped against a lineitem - Does not matter if the actual stock items are later removed from the database --- .../0057_salesorderlineitem_shipped.py | 20 ++++++ .../migrations/0058_auto_20211126_1210.py | 62 +++++++++++++++++++ InvenTree/order/models.py | 9 +++ InvenTree/order/serializers.py | 3 + 4 files changed, 94 insertions(+) create mode 100644 InvenTree/order/migrations/0057_salesorderlineitem_shipped.py create mode 100644 InvenTree/order/migrations/0058_auto_20211126_1210.py diff --git a/InvenTree/order/migrations/0057_salesorderlineitem_shipped.py b/InvenTree/order/migrations/0057_salesorderlineitem_shipped.py new file mode 100644 index 0000000000..e11eb62cbb --- /dev/null +++ b/InvenTree/order/migrations/0057_salesorderlineitem_shipped.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.5 on 2021-11-26 12:06 + +import InvenTree.fields +import django.core.validators +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0056_alter_salesorderallocation_shipment'), + ] + + operations = [ + migrations.AddField( + model_name='salesorderlineitem', + name='shipped', + field=InvenTree.fields.RoundingDecimalField(decimal_places=5, default=0, help_text='Shipped quantity', max_digits=15, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Shipped'), + ), + ] diff --git a/InvenTree/order/migrations/0058_auto_20211126_1210.py b/InvenTree/order/migrations/0058_auto_20211126_1210.py new file mode 100644 index 0000000000..2736416e66 --- /dev/null +++ b/InvenTree/order/migrations/0058_auto_20211126_1210.py @@ -0,0 +1,62 @@ +# Generated by Django 3.2.5 on 2021-11-26 12:10 + +from django.db import migrations + +from InvenTree.status_codes import SalesOrderStatus + + +def calculate_shipped_quantity(apps, schema_editor): + """ + In migration 0057 we added a new field 'shipped' to the SalesOrderLineItem model. + + This field is used to record the number of items shipped, + even if the actual stock items get deleted from the database. + + For existing orders in the database, we calculate this as follows: + + - If the order is "shipped" then we use the total quantity + - Otherwise, we use the "fulfilled" calculated quantity + + """ + + StockItem = apps.get_model('stock', 'stockitem') + SalesOrderLineItem = apps.get_model('order', 'salesorderlineitem') + + for item in SalesOrderLineItem.objects.all(): + + if item.order.status == SalesOrderStatus.SHIPPED: + item.shipped = item.quantity + else: + # Calculate total stock quantity of items allocated to this order? + items = StockItem.objects.filter( + sales_order=item.order, + part=item.part + ) + + q = sum([item.quantity for item in items]) + + item.shipped = q + + item.save() + + +def reverse_calculate_shipped_quantity(apps, schema_editor): + """ + Provided only for reverse migration compatibility. + This function does nothing. + """ + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0057_salesorderlineitem_shipped'), + ] + + operations = [ + migrations.RunPython( + calculate_shipped_quantity, + reverse_code=reverse_calculate_shipped_quantity + ) + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index f87e337b35..73c507b38d 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -814,6 +814,7 @@ class SalesOrderLineItem(OrderLineItem): order: Link to the SalesOrder that this line item belongs to part: Link to a Part object (may be null) sale_price: The unit sale price for this OrderLineItem + shipped: The number of items which have actually shipped against this line item """ @staticmethod @@ -838,6 +839,14 @@ class SalesOrderLineItem(OrderLineItem): help_text=_('Unit sale price'), ) + shipped = RoundingDecimalField( + verbose_name=_('Shipped'), + help_text=_('Shipped quantity'), + default=0, + max_digits=15, decimal_places=5, + validators=[MinValueValidator(0)] + ) + class Meta: unique_together = [ ] diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index f75d373d13..6a139a32a9 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -555,6 +555,8 @@ class SOLineItemSerializer(InvenTreeModelSerializer): allocated = serializers.FloatField(source='allocated_quantity', read_only=True) fulfilled = serializers.FloatField(source='fulfilled_quantity', read_only=True) + shipped = InvenTreeDecimalField(read_only=True) + sale_price = InvenTreeMoneySerializer( allow_null=True ) @@ -584,6 +586,7 @@ class SOLineItemSerializer(InvenTreeModelSerializer): 'sale_price', 'sale_price_currency', 'sale_price_string', + 'shipped', ]