From 0b40197cd20d7fe18eccf8a01898bdb1ee1be6e7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 17 Apr 2018 20:25:43 +1000 Subject: [PATCH] Update 'Build' - Part model now has active_builds and inactive_builds properties - --- InvenTree/build/admin.py | 19 +++--- .../migrations/0006_auto_20180417_0933.py | 66 +++++++++++++++++++ .../migrations/0007_auto_20180417_1025.py | 21 ++++++ InvenTree/build/models.py | 54 ++++++++++----- InvenTree/part/models.py | 22 +++++++ InvenTree/part/templates/part/build.html | 29 ++++++-- InvenTree/part/templates/part/build_list.html | 20 ++++++ 7 files changed, 201 insertions(+), 30 deletions(-) create mode 100644 InvenTree/build/migrations/0006_auto_20180417_0933.py create mode 100644 InvenTree/build/migrations/0007_auto_20180417_1025.py create mode 100644 InvenTree/part/templates/part/build_list.html diff --git a/InvenTree/build/admin.py b/InvenTree/build/admin.py index cf3d818636..dfbefc45e1 100644 --- a/InvenTree/build/admin.py +++ b/InvenTree/build/admin.py @@ -3,18 +3,19 @@ from __future__ import unicode_literals from django.contrib import admin -from .models import Build, BuildOutput +from .models import Build class BuildAdmin(admin.ModelAdmin): - list_display = ('status', ) - - -class BuildOutputAdmin(admin.ModelAdmin): - - list_display = ('build', 'part', 'batch', 'quantity', ) - + list_display = ('part', + 'status', + 'batch', + 'quantity', + 'creation_date', + 'completion_date', + 'title', + 'notes', + ) admin.site.register(Build, BuildAdmin) -admin.site.register(BuildOutput, BuildOutputAdmin) \ No newline at end of file diff --git a/InvenTree/build/migrations/0006_auto_20180417_0933.py b/InvenTree/build/migrations/0006_auto_20180417_0933.py new file mode 100644 index 0000000000..3ed5efb74e --- /dev/null +++ b/InvenTree/build/migrations/0006_auto_20180417_0933.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.12 on 2018-04-17 09:33 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0022_auto_20180417_0819'), + ('build', '0005_buildoutput_batch'), + ] + + operations = [ + migrations.RemoveField( + model_name='buildoutput', + name='build', + ), + migrations.RemoveField( + model_name='buildoutput', + name='part', + ), + migrations.AddField( + model_name='build', + name='batch', + field=models.CharField(blank=True, help_text='Batch code for this build output', max_length=100, null=True), + ), + migrations.AddField( + model_name='build', + name='completion_date', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='build', + name='creation_date', + field=models.DateField(auto_now=True), + ), + migrations.AddField( + model_name='build', + name='notes', + field=models.CharField(blank=True, max_length=500), + ), + migrations.AddField( + model_name='build', + name='part', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='builds', to='part.Part'), + preserve_default=False, + ), + migrations.AddField( + model_name='build', + name='quantity', + field=models.PositiveIntegerField(default=1, help_text='Number of parts to build', validators=[django.core.validators.MinValueValidator(1)]), + ), + migrations.AddField( + model_name='build', + name='title', + field=models.CharField(default='Build title', help_text='Brief description of the build', max_length=100), + preserve_default=False, + ), + migrations.DeleteModel( + name='BuildOutput', + ), + ] diff --git a/InvenTree/build/migrations/0007_auto_20180417_1025.py b/InvenTree/build/migrations/0007_auto_20180417_1025.py new file mode 100644 index 0000000000..d50af03384 --- /dev/null +++ b/InvenTree/build/migrations/0007_auto_20180417_1025.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.12 on 2018-04-17 10:25 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('build', '0006_auto_20180417_0933'), + ] + + operations = [ + migrations.AlterField( + model_name='build', + name='status', + field=models.PositiveIntegerField(choices=[(40, 'Complete'), (10, 'Pending'), (20, 'Holding'), (30, 'Cancelled')], default=10, validators=[django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 4a266d0bf1..ef4b495ced 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -15,44 +15,64 @@ class Build(models.Model): """ # Build status codes - PENDING = 10 - ALLOCATED = 20 - HOLDING = 30 - CANCELLED = 40 - COMPLETE = 50 + PENDING = 10 # Build is pending / active + HOLDING = 20 # Build is currently being held + CANCELLED = 30 # Build was cancelled + COMPLETE = 40 # Build is complete BUILD_STATUS_CODES = { PENDING : _("Pending"), - ALLOCATED : _("Allocated"), HOLDING : _("Holding"), CANCELLED : _("Cancelled"), COMPLETE : _("Complete"), } + batch = models.CharField(max_length=100, blank=True, null=True, + help_text='Batch code for this build output') + # Status of the build status = models.PositiveIntegerField(default=PENDING, choices=BUILD_STATUS_CODES.items(), validators=[MinValueValidator(0)]) -class BuildOutput(models.Model): - """ - A build output represents a single build part/quantity combination - """ + # Date the build model was 'created' + creation_date = models.DateField(auto_now=True, editable=False) - batch = models.CharField(max_length=100, blank=True, - help_text='Batch code for this build output') + # Date the build was 'completed' + completion_date = models.DateField(null=True, blank=True) - # Reference to the build object of which this output is a part - # A build can have multiple outputs - build = models.ForeignKey(Build, on_delete=models.CASCADE, - related_name='outputs') + # Brief build title + title = models.CharField(max_length=100, help_text='Brief description of the build') # A reference to the part being built + # Only 'buildable' parts can be selected part = models.ForeignKey(Part, on_delete=models.CASCADE, - related_name='builds') + related_name='builds', + limit_choices_to={'buildable': True}, + ) # How many parts to build? quantity = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Number of parts to build') + + # Notes can be attached to each build output + notes = models.CharField(max_length=500, blank=True) + + @property + def is_active(self): + """ Is this build active? + An active build is either: + - Pending + - Holding + """ + + return self.status in [ + self.PENDING, + self.HOLDING + ] + + @property + def is_complete(self): + return self.status == self.COMPLETE diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index d44b2ae6b5..e76e01ce06 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -183,6 +183,28 @@ class Part(models.Model): return total + @property + def active_builds(self): + """ Return a list of outstanding builds. + Builds marked as 'complete' or 'cancelled' are ignored + """ + + return [b for b in self.builds.all() if b.is_active] + + @property + def inactive_builds(self): + """ Return a list of inactive builds + """ + + return [b for b in self.builds.all() if not b.is_active] + + @property + def quantity_being_built(self): + """ Return the current number of parts currently being built + """ + + return sum([b.quantity for b in self.active_builds]) + @property def total_stock(self): """ Return the total stock quantity for this part. diff --git a/InvenTree/part/templates/part/build.html b/InvenTree/part/templates/part/build.html index 0c90630bc1..3aae16377f 100644 --- a/InvenTree/part/templates/part/build.html +++ b/InvenTree/part/templates/part/build.html @@ -4,10 +4,31 @@ {% include 'part/tabs.html' with tab='build' %} -

Build Part

+

Part Builds

-TODO -

-You can build {{ part.can_build }} of this part with current stock. + + + + + + + + +{% if part.active_builds|length > 0 %} + + + +{% include "part/build_list.html" with builds=part.active_builds %} +{% endif %} + +{% if part.inactive_builds|length > 0 %} + + + + +{% include "part/build_list.html" with builds=part.inactive_builds %} +{% endif %} + +
TitleQuantityStatusCompletion Date
Active Builds
Inactive Builds
{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/build_list.html b/InvenTree/part/templates/part/build_list.html new file mode 100644 index 0000000000..a42518964a --- /dev/null +++ b/InvenTree/part/templates/part/build_list.html @@ -0,0 +1,20 @@ +{% for build in builds %} + + {{ build.title }} + {{ build.quantity }} + + {% if build.status == build.PENDING %} + + {% elif build.status == build.HOLDING %} + + {% elif build.status == build.CANCELLED %} + + {% elif build.status == build.COMPLETE %} + + {% endif %} + {{ build.get_status_display }} + + + {{ build.completion_date }} + +{% endfor %} \ No newline at end of file