mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Sales Order Allocation Improvements (#4556)
* Do not remove sales order allocations when returning an item against a return order * Also do not clear allocations when returning manually * stock item display tweaks * Add extra column to sales order allocation table * Improve methods for introspecting sales order allocations for stockitems * Only display "active" sales order allocations on a stock item detail page - All allocations are still visible in the allocation table * Can't have available quantity if you're not available tap's side of nose
This commit is contained in:
parent
847d49a42d
commit
4d8cfd77ff
@ -1766,9 +1766,6 @@ class ReturnOrder(TotalPriceMixin, Order):
|
|||||||
|
|
||||||
stock_item = line.item
|
stock_item = line.item
|
||||||
|
|
||||||
# Remove any allocations against the returned StockItem
|
|
||||||
stock_item.clearAllocations()
|
|
||||||
|
|
||||||
deltas = {
|
deltas = {
|
||||||
'status': StockStatus.QUARANTINED,
|
'status': StockStatus.QUARANTINED,
|
||||||
'returnorder': self.pk,
|
'returnorder': self.pk,
|
||||||
|
@ -33,7 +33,8 @@ from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
|||||||
InvenTreeURLField)
|
InvenTreeURLField)
|
||||||
from InvenTree.models import (InvenTreeAttachment, InvenTreeBarcodeMixin,
|
from InvenTree.models import (InvenTreeAttachment, InvenTreeBarcodeMixin,
|
||||||
InvenTreeTree, extract_int)
|
InvenTreeTree, extract_int)
|
||||||
from InvenTree.status_codes import StockHistoryCode, StockStatus
|
from InvenTree.status_codes import (SalesOrderStatus, StockHistoryCode,
|
||||||
|
StockStatus)
|
||||||
from part import models as PartModels
|
from part import models as PartModels
|
||||||
from plugin.events import trigger_event
|
from plugin.events import trigger_event
|
||||||
from plugin.models import MetadataMixin
|
from plugin.models import MetadataMixin
|
||||||
@ -1013,7 +1014,6 @@ class StockItem(InvenTreeBarcodeMixin, MetadataMixin, common.models.MetaMixin, M
|
|||||||
location=location
|
location=location
|
||||||
)
|
)
|
||||||
|
|
||||||
self.clearAllocations()
|
|
||||||
self.customer = None
|
self.customer = None
|
||||||
self.belongs_to = None
|
self.belongs_to = None
|
||||||
self.sales_order = None
|
self.sales_order = None
|
||||||
@ -1059,9 +1059,33 @@ class StockItem(InvenTreeBarcodeMixin, MetadataMixin, common.models.MetaMixin, M
|
|||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def sales_order_allocation_count(self):
|
def get_sales_order_allocations(self, active=True):
|
||||||
|
"""Return a queryset for SalesOrderAllocations against this StockItem, with optional filters.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
active: Filter by 'active' status of the allocation
|
||||||
|
"""
|
||||||
|
query = self.sales_order_allocations.all()
|
||||||
|
|
||||||
|
if active is True:
|
||||||
|
query = query.filter(
|
||||||
|
line__order__status__in=SalesOrderStatus.OPEN,
|
||||||
|
shipment__shipment_date=None
|
||||||
|
)
|
||||||
|
elif active is False:
|
||||||
|
query = query.exclude(
|
||||||
|
line__order__status__in=SalesOrderStatus.OPEN
|
||||||
|
).exclude(
|
||||||
|
shipment__shipment_date=None
|
||||||
|
)
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
||||||
|
def sales_order_allocation_count(self, active=True):
|
||||||
"""Return the total quantity allocated to SalesOrders."""
|
"""Return the total quantity allocated to SalesOrders."""
|
||||||
query = self.sales_order_allocations.aggregate(q=Coalesce(Sum('quantity'), Decimal(0)))
|
|
||||||
|
query = self.get_sales_order_allocations(active=active)
|
||||||
|
query = query.aggregate(q=Coalesce(Sum('quantity'), Decimal(0)))
|
||||||
|
|
||||||
total = query['q']
|
total = query['q']
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
{% include "filter_list.html" with id="salesorderallocation" %}
|
{% include "filter_list.html" with id="salesorderallocation" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class='table table-striped table-condensed' data-toolbar='#sales-order-allocation-toolbar' id='sales-order-allocation-table'></table>
|
<table class='table table-striped table-condensed' data-toolbar='#sales-order-allocations-toolbar' id='sales-order-allocation-table'></table>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -266,6 +266,12 @@
|
|||||||
|
|
||||||
<div class='info-messages'>
|
<div class='info-messages'>
|
||||||
|
|
||||||
|
{% if not item.in_stock %}
|
||||||
|
<div class='alert alert-block alert-danger'>
|
||||||
|
<span class='fas fa-info-circle'></span> {% trans "This stock item is unavailable" %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if item.is_building %}
|
{% if item.is_building %}
|
||||||
<div class='alert alert-block alert-info'>
|
<div class='alert alert-block alert-info'>
|
||||||
{% trans "This stock item is in production and cannot be edited." %}<br>
|
{% trans "This stock item is in production and cannot be edited." %}<br>
|
||||||
@ -281,12 +287,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if item.hasRequiredTests and not item.passedAllRequiredTests %}
|
{% if item.hasRequiredTests and not item.passedAllRequiredTests %}
|
||||||
<div class='alert alert-block alert-danger'>
|
<div class='alert alert-block alert-warning'>
|
||||||
{% trans "This stock item has not passed all required tests" %}
|
{% trans "This stock item has not passed all required tests" %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for allocation in item.sales_order_allocations.all %}
|
{% for allocation in item.get_sales_order_allocations.all %}
|
||||||
<div class='alert alert-block alert-info'>
|
<div class='alert alert-block alert-info'>
|
||||||
{% object_link 'so-detail' allocation.line.order.id allocation.line.order as link %}
|
{% object_link 'so-detail' allocation.line.order.id allocation.line.order as link %}
|
||||||
{% decimal allocation.quantity as qty %}
|
{% decimal allocation.quantity as qty %}
|
||||||
@ -301,12 +307,6 @@
|
|||||||
{% trans "This stock item is allocated to Build Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
|
{% trans "This stock item is allocated to Build Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if item.serialized %}
|
|
||||||
<div class='alert alert-block alert-warning'>
|
|
||||||
{% trans "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock details %}
|
{% endblock details %}
|
||||||
|
|
||||||
@ -320,7 +320,7 @@
|
|||||||
<h5><span class='fas fa-hashtag'></span></h5>
|
<h5><span class='fas fa-hashtag'></span></h5>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h5>{% trans "Serial Number" %}</h5>
|
<h5 title='{% trans "This stock item is serialized. It has a unique serial number and the quantity cannot be adjusted" %}'>{% trans "Serial Number" %}</h5>
|
||||||
</td>
|
</td>
|
||||||
<td><h5>
|
<td><h5>
|
||||||
{{ item.serial }}
|
{{ item.serial }}
|
||||||
@ -348,7 +348,11 @@
|
|||||||
<h5><div class='fas fa-boxes'></div></h5>
|
<h5><div class='fas fa-boxes'></div></h5>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
{% if item.in_stock %}
|
||||||
<h5>{% trans "Available Quantity" %}</h5>
|
<h5>{% trans "Available Quantity" %}</h5>
|
||||||
|
{% else %}
|
||||||
|
<h5>{% trans "Quantity" %}</h5>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h5>{% if item.quantity != available %}{% decimal available %} / {% endif %}{% decimal item.quantity %} {% include "part/part_units.html" with part=item.part %}</h5>
|
<h5>{% if item.quantity != available %}{% decimal available %} / {% endif %}{% decimal item.quantity %} {% include "part/part_units.html" with part=item.part %}</h5>
|
||||||
@ -367,7 +371,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% elif item.sales_order %}
|
{% elif item.sales_order %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-user-tie'></span></td>
|
<td><span class='fas fa-th-list'></span></td>
|
||||||
<td>{% trans "Sales Order" %}</td>
|
<td>{% trans "Sales Order" %}</td>
|
||||||
<td><a href="{% url 'so-detail' item.sales_order.id %}">{{ item.sales_order.reference }}</a> - <a href="{% url 'company-detail' item.sales_order.customer.id %}">{{ item.sales_order.customer.name }}</a></td>
|
<td><a href="{% url 'so-detail' item.sales_order.id %}">{{ item.sales_order.reference }}</a> - <a href="{% url 'company-detail' item.sales_order.customer.id %}">{{ item.sales_order.customer.name }}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1387,6 +1387,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'item',
|
field: 'item',
|
||||||
|
switchable: false,
|
||||||
title: '{% trans "Stock Item" %}',
|
title: '{% trans "Stock Item" %}',
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
// Render a link to the particular stock item
|
// Render a link to the particular stock item
|
||||||
@ -1409,6 +1410,18 @@ function loadSalesOrderAllocationTable(table, options={}) {
|
|||||||
title: '{% trans "Quantity" %}',
|
title: '{% trans "Quantity" %}',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'shipment_date',
|
||||||
|
title: '{% trans "Shipped" %}',
|
||||||
|
sortable: true,
|
||||||
|
formatter: function(value, row) {
|
||||||
|
if (value) {
|
||||||
|
return renderDate(value);
|
||||||
|
} else {
|
||||||
|
return `<em>{% trans "Not shipped" %}</em>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user