mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 21:25:42 +00:00 
			
		
		
		
	Add "target_date" for Build model
- Add "overdue" status to Build serializer
This commit is contained in:
		| @@ -46,6 +46,8 @@ class BuildList(generics.ListCreateAPIView): | ||||
|  | ||||
|         queryset = super().get_queryset().prefetch_related('part') | ||||
|  | ||||
|         queryset = BuildSerializer.annotate_queryset(queryset) | ||||
|  | ||||
|         return queryset | ||||
|      | ||||
|     def filter_queryset(self, queryset): | ||||
|   | ||||
| @@ -40,6 +40,7 @@ class EditBuildForm(HelperForm): | ||||
|             'part', | ||||
|             'quantity', | ||||
|             'batch', | ||||
|             'target_date', | ||||
|             'take_from', | ||||
|             'destination', | ||||
|             'parent', | ||||
|   | ||||
							
								
								
									
										18
									
								
								InvenTree/build/migrations/0025_build_target_date.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								InvenTree/build/migrations/0025_build_target_date.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # Generated by Django 3.0.7 on 2020-12-15 12:13 | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('build', '0024_auto_20201201_1023'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='build', | ||||
|             name='target_date', | ||||
|             field=models.DateField(blank=True, help_text='Target date for build completion. Build will be overdue after this date.', null=True, verbose_name='Target completion date'), | ||||
|         ), | ||||
|     ] | ||||
| @@ -47,7 +47,8 @@ class Build(MPTTModel): | ||||
|         status: Build status code | ||||
|         batch: Batch code transferred to build parts (optional) | ||||
|         creation_date: Date the build was created (auto) | ||||
|         completion_date: Date the build was completed | ||||
|         target_date: Date the build will be overdue | ||||
|         completion_date: Date the build was completed (or, if incomplete, the expected date of completion) | ||||
|         link: External URL for extra information | ||||
|         notes: Text notes | ||||
|     """ | ||||
| @@ -164,6 +165,12 @@ class Build(MPTTModel): | ||||
|      | ||||
|     creation_date = models.DateField(auto_now_add=True, editable=False) | ||||
|      | ||||
|     target_date = models.DateField( | ||||
|         null=True, blank=True, | ||||
|         verbose_name=_('Target completion date'), | ||||
|         help_text=_('Target date for build completion. Build will be overdue after this date.') | ||||
|     ) | ||||
|  | ||||
|     completion_date = models.DateField(null=True, blank=True) | ||||
|  | ||||
|     completed_by = models.ForeignKey( | ||||
| @@ -183,6 +190,22 @@ class Build(MPTTModel): | ||||
|         blank=True, help_text=_('Extra build notes') | ||||
|     ) | ||||
|  | ||||
|     def is_overdue(self): | ||||
|         """ | ||||
|         Returns true if this build is "overdue": | ||||
|  | ||||
|         - Not completed | ||||
|         - Target date is "in the past" | ||||
|         """ | ||||
|  | ||||
|         # Cannot be deemed overdue if target_date is not set | ||||
|         if self.target_date is None: | ||||
|             return False | ||||
|  | ||||
|         today = datetime.now().date() | ||||
|  | ||||
|         return self.active and self.target_date < today | ||||
|  | ||||
|     @property | ||||
|     def active(self): | ||||
|         """ | ||||
|   | ||||
| @@ -5,12 +5,21 @@ JSON serializers for Build API | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import datetime | ||||
|  | ||||
| from django.db.models import Q | ||||
| from django.db.models import Case, When, Value | ||||
| from django.db.models import BooleanField | ||||
|  | ||||
| from rest_framework import serializers | ||||
|  | ||||
| from InvenTree.serializers import InvenTreeModelSerializer | ||||
| from InvenTree.status_codes import BuildStatus | ||||
|  | ||||
| from stock.serializers import StockItemSerializerBrief | ||||
| from part.serializers import PartBriefSerializer | ||||
|  | ||||
| from .models import Build, BuildItem | ||||
| from part.serializers import PartBriefSerializer | ||||
|  | ||||
|  | ||||
| class BuildSerializer(InvenTreeModelSerializer): | ||||
| @@ -23,6 +32,38 @@ class BuildSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|     quantity = serializers.FloatField() | ||||
|  | ||||
|     overdue = serializers.BooleanField() | ||||
|  | ||||
|     @staticmethod | ||||
|     def annotate_queryset(queryset): | ||||
|         """ | ||||
|         Add custom annotations to the BuildSerializer queryset, | ||||
|         performing database queries as efficiently as possible. | ||||
|  | ||||
|         The following annoted fields are added: | ||||
|  | ||||
|         - overdue: True if the build is outstanding *and* the completion date has past | ||||
|  | ||||
|         """ | ||||
|  | ||||
|         # Annotate a boolean 'overdue' flag | ||||
|  | ||||
|         # Construct a filter for finding overdue builds | ||||
|         today = datetime.datetime.now().date() | ||||
|         overdue = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=today) | ||||
|  | ||||
|         queryset = queryset.annotate( | ||||
|             overdue=Case( | ||||
|                 When( | ||||
|                     overdue, then=Value(True, output_field=BooleanField()), | ||||
|                 ), | ||||
|                 default=Value(False, output_field=BooleanField()) | ||||
|             ) | ||||
|         ) | ||||
|  | ||||
|         return queryset | ||||
|  | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         part_detail = kwargs.pop('part_detail', False) | ||||
|  | ||||
| @@ -42,11 +83,13 @@ class BuildSerializer(InvenTreeModelSerializer): | ||||
|             'completion_date', | ||||
|             'part', | ||||
|             'part_detail', | ||||
|             'overdue', | ||||
|             'reference', | ||||
|             'sales_order', | ||||
|             'quantity', | ||||
|             'status', | ||||
|             'status_text', | ||||
|             'target_date', | ||||
|             'notes', | ||||
|             'link', | ||||
|         ] | ||||
|   | ||||
| @@ -95,33 +95,26 @@ | ||||
|             <td>{% trans "Created" %}</td> | ||||
|             <td>{{ build.creation_date }}</td> | ||||
|         </tr> | ||||
|         </table> | ||||
|     </div> | ||||
|     <div class='col-sm-6'> | ||||
|         <table class='table table-striped'> | ||||
|             <col width='25'> | ||||
|             <tr> | ||||
|                 <td><span class='fas fa-dollar-sign'></span></td> | ||||
|                 <td>{% trans "BOM Price" %}</td> | ||||
|                 <td> | ||||
|                     {% if bom_price %} | ||||
|                     {{ bom_price }} | ||||
|                     {% if build.part.has_complete_bom_pricing == False %} | ||||
|                     <br><span class='warning-msg'><i>{% trans "BOM pricing is incomplete" %}</i></span> | ||||
|                     {% endif %} | ||||
|                     {% else %} | ||||
|                     <span class='warning-msg'><i>{% trans "No pricing information" %}</i></span> | ||||
|                     {% endif %} | ||||
|                 </td> | ||||
|             </tr> | ||||
|             {% if build.completion_date %} | ||||
|             <tr> | ||||
|                 <td><span class='fas fa-calendar-alt'></span></td> | ||||
|                 <td>{% trans "Completed" %}</td> | ||||
|                 <td>{{ build.completion_date }}{% if build.completed_by %}<span class='badge'>{{ build.completed_by }}</span>{% endif %}</td> | ||||
|             </tr> | ||||
|         <tr> | ||||
|             <td><span class='fas fa-calendar-alt'></span></td> | ||||
|             <td>{% trans "Target Date" %}</td> | ||||
|             {% if build.target_date %} | ||||
|             <td> | ||||
|                 {{ build.target_date }}{% if build.is_overdue %} <span class='fas fa-calendar-times icon-red'></span>{% endif %} | ||||
|             </td> | ||||
|             {% else %} | ||||
|             <td><i>{% trans "No target date set" %}</i></td> | ||||
|             {% endif %} | ||||
|      | ||||
|         </tr> | ||||
|         <tr> | ||||
|             <td><span class='fas fa-calendar-alt'></span></td> | ||||
|             <td>{% trans "Completed" %}</td> | ||||
|             {% if build.completion_date %} | ||||
|             <td>{{ build.completion_date }}{% if build.completed_by %}<span class='badge'>{{ build.completed_by }}</span>{% endif %}</td> | ||||
|             {% else %} | ||||
|             <td><i>{% trans "Build not complete" %}</i></td> | ||||
|             {% endif %} | ||||
|         </tr> | ||||
|         </table> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user