mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	Calendar view for purchase orders
This commit is contained in:
		| @@ -107,6 +107,13 @@ class POList(generics.ListCreateAPIView): | ||||
|             except (ValueError, SupplierPart.DoesNotExist): | ||||
|                 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 = PurchaseOrder.filterByDate(queryset, min_date, max_date) | ||||
|  | ||||
|         return queryset | ||||
|  | ||||
|     filter_backends = [ | ||||
| @@ -298,7 +305,7 @@ class SOList(generics.ListCreateAPIView): | ||||
|         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) | ||||
|             queryset = SalesOrder.filterByDate(queryset, min_date, max_date) | ||||
|  | ||||
|         return queryset | ||||
|  | ||||
|   | ||||
| @@ -121,6 +121,44 @@ class PurchaseOrder(Order): | ||||
|         received_by: User that received the goods | ||||
|     """ | ||||
|  | ||||
|     @staticmethod | ||||
|     def filterByDate(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 bewteen these dates | ||||
|  | ||||
|         To be "interesting": | ||||
|         - A "received" order where the received date lies within the date range | ||||
|         - TODO: 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 "received" orders within the range | ||||
|         received = Q(status=PurchaseOrderStatus.COMPLETE) & Q(complete_date__gte=min_date) & Q(complete_date__lte=max_date) | ||||
|  | ||||
|         # TODO - Construct a queryset for "pending" orders within the range | ||||
|  | ||||
|         # TODO - Construct a queryset for "overdue" orders within the range | ||||
|  | ||||
|         flt = received | ||||
|  | ||||
|         queryset = queryset.filter(flt) | ||||
|  | ||||
|         return queryset | ||||
|  | ||||
|     def __str__(self): | ||||
|  | ||||
|         prefix = getSetting('PURCHASEORDER_REFERENCE_PREFIX') | ||||
| @@ -302,7 +340,7 @@ 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): | ||||
|     def filterByDate(queryset, min_date, max_date): | ||||
|         """ | ||||
|         Filter by "minimum and maximum date range" | ||||
|  | ||||
| @@ -332,7 +370,8 @@ class SalesOrder(Order): | ||||
|         # 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 | ||||
|         # TODO: Construct a queryset for "overdue" orders within the range | ||||
|  | ||||
|         flt = completed | pending | ||||
|  | ||||
|         queryset = queryset.filter(flt) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| {% extends "base.html" %} | ||||
|  | ||||
| {% load inventree_extras %} | ||||
| {% load static %} | ||||
| {% load i18n %} | ||||
|  | ||||
| @@ -18,6 +19,12 @@ InvenTree | {% trans "Purchase Orders" %} | ||||
|         <button class='btn btn-primary' type='button' id='po-create' title='{% trans "Create new purchase order" %}'> | ||||
|             <span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %}</button> | ||||
|         {% endif %} | ||||
|         <button class='btn btn-default' type='button' id='view-calendar' title='{% trans "Display calendar view" %}'> | ||||
|             <span class='fas fa-calendar-alt'></span> | ||||
|         </button> | ||||
|         <button class='btn btn-default' type='button' id='view-list' title='{% trans "Display list view" %}'> | ||||
|             <span class='fas fa-th-list'></span> | ||||
|         </button> | ||||
|         <div class='filter-list' id='filter-list-purchaseorder'> | ||||
|             <!-- An empty div in which the filter list will be constructed --> | ||||
|         </div> | ||||
| @@ -27,11 +34,116 @@ InvenTree | {% trans "Purchase Orders" %} | ||||
| <table class='table table-striped table-condensed po-table' data-toolbar='#table-buttons' id='purchase-order-table'> | ||||
| </table> | ||||
|  | ||||
| <div id='purchase-order-calendar'></div> | ||||
|  | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js_load %} | ||||
| {{ block.super }} | ||||
|  | ||||
| <script type='text/javascript'> | ||||
|  | ||||
|     function loadOrderEvents(calendar) { | ||||
|  | ||||
|         var start = startDate(calendar); | ||||
|         var end = endDate(calendar); | ||||
|  | ||||
|         clearEvents(calendar); | ||||
|  | ||||
|         // Request purchase orders from the server within specified date range | ||||
|         inventreeGet( | ||||
|             '{% url "api-po-list" %}', | ||||
|             { | ||||
|                 supplier_detail: true, | ||||
|                 min_date: start, | ||||
|                 max_date: end, | ||||
|             }, | ||||
|             { | ||||
|                 success: function(response) { | ||||
|                     var prefix = '{% settings_value "PURCHASEORDER_REFERENCE_PREFIX" %}'; | ||||
|  | ||||
|                     for (var idx = 0; idx < response.length; idx++) { | ||||
|  | ||||
|                         var order = response[idx]; | ||||
|  | ||||
|                         var date = order.creation_date; | ||||
|  | ||||
|                         if (order.complete_date) { | ||||
|                             date = order.complete_date; | ||||
|                         } | ||||
|  | ||||
|                         var title = `${prefix}${order.reference} - ${order.supplier_detail.name}`; | ||||
|  | ||||
|                         var color = '#25c235'; | ||||
|  | ||||
|                         var event = { | ||||
|                             title: title, | ||||
|                             start: date, | ||||
|                             end: date, | ||||
|                             url: `/order/purchase-order/${order.pk}/`, | ||||
|                             backgroundColor: color, | ||||
|                         }; | ||||
|  | ||||
|                         calendar.addEvent(event); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     var calendar = null; | ||||
|  | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|         var el = document.getElementById('purchase-order-calendar'); | ||||
|  | ||||
|         calendar = new FullCalendar.Calendar(el, { | ||||
|             initialView: 'dayGridMonth', | ||||
|             nowIndicator: true, | ||||
|             aspectRatio: 2.5, | ||||
|             datesSet: function() { | ||||
|                 loadOrderEvents(calendar); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         calendar.render(); | ||||
|     }) | ||||
|  | ||||
| </script> | ||||
|  | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js_ready %} | ||||
| {{ block.super }} | ||||
|  | ||||
| $('#purchase-order-calendar').hide(); | ||||
| $('#view-list').hide(); | ||||
|  | ||||
| $('#view-calendar').click(function() { | ||||
|     // Hide the list view, show the calendar view | ||||
|     $("#purchase-order-table").hide(); | ||||
|     $("#view-calendar").hide(); | ||||
|     $(".fixed-table-pagination").hide(); | ||||
|     $(".columns-right").hide(); | ||||
|     $(".search").hide(); | ||||
|     $('#filter-list-salesorder').hide(); | ||||
|      | ||||
|     $("#purchase-order-calendar").show(); | ||||
|     $("#view-list").show(); | ||||
| }); | ||||
|  | ||||
| $("#view-list").click(function() { | ||||
|     // Hide the calendar view, show the list view | ||||
|     $("#purchase-order-calendar").hide(); | ||||
|     $("#view-list").hide(); | ||||
|      | ||||
|     $(".fixed-table-pagination").show(); | ||||
|     $(".columns-right").show(); | ||||
|     $(".search").show(); | ||||
|     $("#purchase-order-table").show(); | ||||
|     $('#filter-list-salesorder').show(); | ||||
|     $("#view-calendar").show(); | ||||
| }); | ||||
|  | ||||
| $("#po-create").click(function() { | ||||
|     launchModalForm("{% url 'po-create' %}", | ||||
|         { | ||||
|   | ||||
| @@ -12,7 +12,6 @@ InvenTree | {% trans "Sales Orders" %} | ||||
|  | ||||
| <h3>{% trans "Sales Orders" %}</h3> | ||||
| <hr> | ||||
|      | ||||
|  | ||||
| <div id='table-buttons'> | ||||
|     <div class='button-toolbar container-fluid' style='float: right;'> | ||||
| @@ -34,10 +33,9 @@ InvenTree | {% trans "Sales Orders" %} | ||||
|  | ||||
| <table class='table table-striped table-condensed po-table' data-toolbar='#table-buttons' id='sales-order-table'> | ||||
| </table> | ||||
|  | ||||
| <div id='sales-order-calendar'></div> | ||||
|  | ||||
|  | ||||
|  | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js_load %} | ||||
| @@ -45,25 +43,12 @@ InvenTree | {% trans "Sales Orders" %} | ||||
|  | ||||
| <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(); | ||||
|         }); | ||||
|         clearEvents(calendar); | ||||
|  | ||||
|         // Request orders from the server within specified date range | ||||
|         inventreeGet( | ||||
| @@ -124,7 +109,6 @@ InvenTree | {% trans "Sales Orders" %} | ||||
|             initialView: 'dayGridMonth', | ||||
|             nowIndicator: true, | ||||
|             aspectRatio: 2.5, | ||||
|             width: '80%', | ||||
|             datesSet: function() { | ||||
|                 loadOrderEvents(calendar); | ||||
|             }, | ||||
| @@ -149,6 +133,7 @@ $('#view-calendar').click(function() { | ||||
|     $(".fixed-table-pagination").hide(); | ||||
|     $(".columns-right").hide(); | ||||
|     $(".search").hide(); | ||||
|     $('#filter-list-salesorder').hide(); | ||||
|      | ||||
|     $("#sales-order-calendar").show(); | ||||
|     $("#view-list").show(); | ||||
| @@ -158,11 +143,12 @@ $("#view-list").click(function() { | ||||
|     // Hide the calendar view, show the list view | ||||
|     $("#sales-order-calendar").hide(); | ||||
|     $("#view-list").hide(); | ||||
|  | ||||
|      | ||||
|     $(".fixed-table-pagination").show(); | ||||
|     $(".columns-right").show(); | ||||
|     $(".search").show(); | ||||
|     $("#sales-order-table").show(); | ||||
|     $('#filter-list-salesorder').show(); | ||||
|     $("#view-calendar").show(); | ||||
| }); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user