diff --git a/InvenTree/InvenTree/status_codes.py b/InvenTree/InvenTree/status_codes.py index 1d5335ad2f..916b3341cb 100644 --- a/InvenTree/InvenTree/status_codes.py +++ b/InvenTree/InvenTree/status_codes.py @@ -152,6 +152,11 @@ class SalesOrderStatus(StatusCode): PENDING, ] + # Completed orders + COMPLETE = [ + SHIPPED, + ] + class StockStatus(StatusCode): diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 6b8a3c81e0..12f0854c19 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -9,6 +9,8 @@ from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics from rest_framework import filters +from django.db.models import Q + from django.conf.urls import url, include from InvenTree.helpers import str2bool @@ -293,6 +295,13 @@ class SOList(generics.ListCreateAPIView): except (Part.DoesNotExist, ValueError): pass + # Filter by 'date range' + min_date = params.get('min_date', None) + max_date = params.get('max_date', None) + + if min_date is not None and max_date is not None: + queryset = SalesOrder.filter_interesting_orders(queryset, min_date, max_date) + return queryset filter_backends = [ diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 9045ab86d7..d0373fa324 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -301,6 +301,44 @@ class SalesOrder(Order): OVERDUE_FILTER = Q(status__in=SalesOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date()) + @staticmethod + def filter_interesting_orders(queryset, min_date, max_date): + """ + Filter by "minimum and maximum date range" + + - Specified as min_date, max_date + - Both must be specified for filter to be applied + - Determine which "interesting" orders exist between these dates + + To be "interesting": + - A "completed" order where the completion date lies within the date range + - A "pending" order where the target date lies within the date range + - TODO: An "overdue" order where the target date is in the past + """ + + DATE_FMT = '%Y-%m-%d' # ISO format date string + + # Ensure that both dates are valid + try: + min_date = datetime.strptime(str(min_date), DATE_FMT).date() + max_date = datetime.strptime(str(max_date), DATE_FMT).date() + except (ValueError, TypeError): + # Date processing error, return queryset unchanged + return queryset + + # Construct a queryset for "completed" orders within the range + COMPLETED = Q(status__in=SalesOrderStatus.COMPLETE) & Q(shipment_date__gte=min_date) & Q(shipment_date__lte=max_date) + + # Construct a queryset for "pending" orders within the range + PENDING = Q(status__in=SalesOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__gte=min_date) & Q(target_date__lte=max_date) + + # Construct a queryset for "overdue" orders within the range + FILTER = COMPLETED | PENDING + + queryset = queryset.filter(FILTER) + + return queryset + def __str__(self): prefix = getSetting('SALESORDER_REFERENCE_PREFIX') diff --git a/InvenTree/order/templates/order/sales_orders.html b/InvenTree/order/templates/order/sales_orders.html index acfd875078..f9031912bf 100644 --- a/InvenTree/order/templates/order/sales_orders.html +++ b/InvenTree/order/templates/order/sales_orders.html @@ -1,5 +1,6 @@ {% extends "base.html" %} +{% load inventree_extras %} {% load static %} {% load i18n %} @@ -12,6 +13,10 @@ InvenTree | {% trans "Sales Orders" %}

{% trans "Sales Orders" %}


+
+
+
+
{% if roles.sales_order.add %} @@ -29,9 +34,106 @@ InvenTree | {% trans "Sales Orders" %} {% endblock %} +{% block js_load %} +{{ block.super }} + + +{% endblock %} + {% block js_ready %} {{ block.super }} + loadSalesOrderTable("#sales-order-table", { url: "{% url 'api-so-list' %}", });