Add "target_date" for Build model

- Add "overdue" status to Build serializer
This commit is contained in:
Oliver Walters 2020-12-15 23:24:37 +11:00
parent a7d825158c
commit 802dd5174c
6 changed files with 108 additions and 28 deletions

View File

@ -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):

View File

@ -40,6 +40,7 @@ class EditBuildForm(HelperForm):
'part',
'quantity',
'batch',
'target_date',
'take_from',
'destination',
'parent',

View 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'),
),
]

View File

@ -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):
"""

View File

@ -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',
]

View File

@ -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>