mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Render sales orders to a calendar view
This commit is contained in:
parent
b4277e09e8
commit
5f6442ba6b
@ -152,6 +152,11 @@ class SalesOrderStatus(StatusCode):
|
||||
PENDING,
|
||||
]
|
||||
|
||||
# Completed orders
|
||||
COMPLETE = [
|
||||
SHIPPED,
|
||||
]
|
||||
|
||||
|
||||
class StockStatus(StatusCode):
|
||||
|
||||
|
@ -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 = [
|
||||
|
@ -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')
|
||||
|
@ -1,5 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load inventree_extras %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
@ -12,6 +13,10 @@ InvenTree | {% trans "Sales Orders" %}
|
||||
<h3>{% trans "Sales Orders" %}</h3>
|
||||
<hr>
|
||||
|
||||
<div class='calendar-container' style="width: 80%; align-items: center; align-content: center;">
|
||||
<div id='calendar'></div>
|
||||
</div>
|
||||
|
||||
<div id='table-buttons'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
{% if roles.sales_order.add %}
|
||||
@ -29,9 +34,106 @@ InvenTree | {% trans "Sales Orders" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
{{ block.super }}
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
function startDate(calendar) {
|
||||
return calendar.currentData.dateProfile.activeRange.start.toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
function endDate(calendar) {
|
||||
return calendar.currentData.dateProfile.activeRange.end.toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
function loadOrderEvents(calendar) {
|
||||
|
||||
var start = startDate(calendar);
|
||||
var end = endDate(calendar);
|
||||
|
||||
// Clear existing orders from the calendar
|
||||
var events = calendar.getEvents();
|
||||
|
||||
events.forEach(function(event) {
|
||||
event.remove();
|
||||
});
|
||||
|
||||
// Request orders from the server within specified date range
|
||||
inventreeGet(
|
||||
'{% url "api-so-list" %}',
|
||||
{
|
||||
customer_detail: true,
|
||||
min_date: start,
|
||||
max_date: end,
|
||||
},
|
||||
{
|
||||
success: function(response) {
|
||||
|
||||
var prefix = '{% settings_value "SALESORDER_REFERENCE_PREFIX" %}';
|
||||
|
||||
for (var idx = 0; idx < response.length; idx++) {
|
||||
var order = response[idx];
|
||||
|
||||
var date = order.creation_date;
|
||||
|
||||
if (order.shipment_date) {
|
||||
date = order.shipment_date;
|
||||
} else if (order.target_date) {
|
||||
date = order.target_date;
|
||||
}
|
||||
|
||||
var title = `${prefix}${order.reference} - ${order.customer_detail.name}`;
|
||||
|
||||
// Default color is blue
|
||||
var color = '#4c68f5';
|
||||
|
||||
// Overdue orders are red
|
||||
if (order.overdue) {
|
||||
color = '#c22525';
|
||||
} else if (order.status == {{ SalesOrderStatus.SHIPPED }}) {
|
||||
color = '#25c235';
|
||||
}
|
||||
|
||||
var event = {
|
||||
title: title,
|
||||
start: date,
|
||||
end: date,
|
||||
url: `/order/sales-order/${order.pk}/`,
|
||||
backgroundColor: color,
|
||||
};
|
||||
|
||||
calendar.addEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var calendar = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
nowIndicator: true,
|
||||
aspectRatio: 2,
|
||||
width: '80%',
|
||||
datesSet: function() {
|
||||
loadOrderEvents(calendar);
|
||||
},
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
|
||||
|
||||
loadSalesOrderTable("#sales-order-table", {
|
||||
url: "{% url 'api-so-list' %}",
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user