mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-30 20:46:47 +00:00
Calculate 'fulfilled' quantity once a sales order is marked as shipped
- This allows us to delete the SalesOrderAllocation objects from the database
This commit is contained in:
parent
3c5ba75d27
commit
5167117067
@ -480,6 +480,8 @@ class BuildItem(models.Model):
|
|||||||
self.stock_item = item
|
self.stock_item = item
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
# TODO - If the item__part object is not trackable, delete the stock item here
|
||||||
|
|
||||||
item.status = StockStatus.ASSIGNED_TO_BUILD
|
item.status = StockStatus.ASSIGNED_TO_BUILD
|
||||||
item.build_order = self.build
|
item.build_order = self.build
|
||||||
item.save()
|
item.save()
|
||||||
|
@ -348,14 +348,17 @@ class SOLineItemList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
queryset = super().get_queryset(*args, **kwargs)
|
queryset = super().get_queryset(*args, **kwargs)
|
||||||
|
|
||||||
return queryset.prefetch_related(
|
queryset = queryset.prefetch_related(
|
||||||
'part',
|
'part',
|
||||||
'part__stock_items',
|
'part__stock_items',
|
||||||
'allocations',
|
'allocations',
|
||||||
'allocations__item__location',
|
'allocations__item__location',
|
||||||
'order',
|
'order',
|
||||||
|
'order__stock_items',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
filter_backends = [DjangoFilterBackend]
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
@ -324,8 +324,11 @@ class SalesOrder(Order):
|
|||||||
for allocation in line.allocations.all():
|
for allocation in line.allocations.all():
|
||||||
allocation.complete_allocation(user)
|
allocation.complete_allocation(user)
|
||||||
|
|
||||||
# TODO - Remove the allocation from the database
|
# Remove the allocation from the database once it has been 'fulfilled'
|
||||||
# allocation.delete()
|
if allocation.item.sales_order == self.order:
|
||||||
|
allocation.delete()
|
||||||
|
else:
|
||||||
|
raise ValidationError("Could not complete order - allocation item not fulfilled")
|
||||||
|
|
||||||
# Ensure the order status is marked as "Shipped"
|
# Ensure the order status is marked as "Shipped"
|
||||||
self.status = SalesOrderStatus.SHIPPED
|
self.status = SalesOrderStatus.SHIPPED
|
||||||
@ -458,6 +461,15 @@ class SalesOrderLineItem(OrderLineItem):
|
|||||||
|
|
||||||
part = models.ForeignKey('part.Part', on_delete=models.SET_NULL, related_name='sales_order_line_items', null=True, help_text=_('Part'), limit_choices_to={'salable': True})
|
part = models.ForeignKey('part.Part', on_delete=models.SET_NULL, related_name='sales_order_line_items', null=True, help_text=_('Part'), limit_choices_to={'salable': True})
|
||||||
|
|
||||||
|
def fulfilled_quantity(self):
|
||||||
|
"""
|
||||||
|
Return the total stock quantity fulfilled against this line item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = self.order.stock_items.filter(part=self.part).aggregate(fulfilled=Coalesce(Sum('quantity'), Decimal(0)))
|
||||||
|
|
||||||
|
return query['fulfilled']
|
||||||
|
|
||||||
def allocated_quantity(self):
|
def allocated_quantity(self):
|
||||||
""" Return the total stock quantity allocated to this LineItem.
|
""" Return the total stock quantity allocated to this LineItem.
|
||||||
|
|
||||||
|
@ -211,6 +211,7 @@ class SOLineItemSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
quantity = serializers.FloatField()
|
quantity = serializers.FloatField()
|
||||||
allocated = serializers.FloatField(source='allocated_quantity', read_only=True)
|
allocated = serializers.FloatField(source='allocated_quantity', read_only=True)
|
||||||
|
fulfilled = serializers.FloatField(source='fulfilled_quantity', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SalesOrderLineItem
|
model = SalesOrderLineItem
|
||||||
@ -220,6 +221,7 @@ class SOLineItemSerializer(InvenTreeModelSerializer):
|
|||||||
'allocated',
|
'allocated',
|
||||||
'allocations',
|
'allocations',
|
||||||
'quantity',
|
'quantity',
|
||||||
|
'fulfilled',
|
||||||
'reference',
|
'reference',
|
||||||
'notes',
|
'notes',
|
||||||
'order',
|
'order',
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{% include 'part/tabs.html' with tab='stock' %}
|
{% include 'part/tabs.html' with tab='stock' %}
|
||||||
|
|
||||||
<h4>Part Stock</h4>
|
<h4>{% trans "Part Stock" %}</h4>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
{% if part.is_template %}
|
{% if part.is_template %}
|
||||||
@ -40,6 +40,7 @@
|
|||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
location_detail: true,
|
location_detail: true,
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
|
in_stock: true,
|
||||||
},
|
},
|
||||||
groupByField: 'location',
|
groupByField: 'location',
|
||||||
buttons: [
|
buttons: [
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<a href="{% url 'part-sales-orders' part.id %}">{% trans "Sales Orders" %} <span class='badge'>{{ part.sales_orders|length }}</span></a>
|
<a href="{% url 'part-sales-orders' part.id %}">{% trans "Sales Orders" %} <span class='badge'>{{ part.sales_orders|length }}</span></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if part.trackable and 0 %}
|
{% if part.trackable %}
|
||||||
<li{% ifequal tab 'track' %} class="active"{% endifequal %}>
|
<li{% ifequal tab 'track' %} class="active"{% endifequal %}>
|
||||||
<a href="{% url 'part-track' part.id %}">{% trans "Tracking" %}
|
<a href="{% url 'part-track' part.id %}">{% trans "Tracking" %}
|
||||||
{% if parts.serials.all|length > 0 %}
|
{% if parts.serials.all|length > 0 %}
|
||||||
|
@ -1,28 +1,12 @@
|
|||||||
{% extends "part/part_base.html" %}
|
{% extends "part/part_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
{% block details %}
|
{% block details %}
|
||||||
|
|
||||||
{% include 'part/tabs.html' with tab='track' %}
|
{% include 'part/tabs.html' with tab='track' %}
|
||||||
|
|
||||||
Part tracking for {{ part.full_name }}
|
<h4>{% trans "Part Tracking" %}</h4>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<hr>
|
||||||
<tr>
|
|
||||||
<th>Serial</th>
|
|
||||||
<th>Status</th>
|
|
||||||
</tr>
|
|
||||||
{% for track in part.tracked_parts.all %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'track-detail' track.id %}">{{ track.serial }}</a></td>
|
|
||||||
<td>{{ track.get_status_display }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class='container-fluid'>
|
|
||||||
<a href="{% url 'track-create' %}?part={{ part.id }}">
|
|
||||||
<button class="btn btn-success">New Tracked Part</button>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -58,7 +58,8 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
<a href="{% url 'build-detail' item.build_order.id %}">
|
<a href="{% url 'build-detail' item.build_order.id %}">
|
||||||
<div class='label label-large label-large-blue'>{% trans "Used in Build" %}</div>
|
<div class='label label-large label-large-blue'>{% trans "Used in Build" %}</div>
|
||||||
</a>
|
</a>
|
||||||
{% elif item.status in StockStatus.UNAVAILABLE_CODES %}{% stock_status_label item.status large=True %}
|
{% else %}
|
||||||
|
{% stock_status_label item.status large=True %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h3>
|
</h3>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -233,6 +233,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
location_detail: true,
|
location_detail: true,
|
||||||
|
in_stock: true,
|
||||||
},
|
},
|
||||||
url: "{% url 'api-stock-list' %}",
|
url: "{% url 'api-stock-list' %}",
|
||||||
});
|
});
|
||||||
|
@ -21,11 +21,6 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
title: '{% trans "Include sublocations" %}',
|
title: '{% trans "Include sublocations" %}',
|
||||||
description: '{% trans "Include stock in sublocations" %}',
|
description: '{% trans "Include stock in sublocations" %}',
|
||||||
},
|
},
|
||||||
in_stock: {
|
|
||||||
type: 'bool',
|
|
||||||
title: '{% trans "In stock" %}',
|
|
||||||
description: '{% trans "Item is in stock" %}',
|
|
||||||
},
|
|
||||||
active: {
|
active: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Active parts" %}',
|
title: '{% trans "Active parts" %}',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user