Add a "completed" field to the Build model

- Keeps track of how many outputs have been produced
- Will not be directly editable by the user
This commit is contained in:
Oliver Walters 2020-10-20 23:59:37 +11:00
parent fd6d630037
commit e02536071d
7 changed files with 183 additions and 124 deletions

View File

@ -0,0 +1,24 @@
# Generated by Django 3.0.7 on 2020-10-20 12:48
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('build', '0024_auto_20201020_1144'),
]
operations = [
migrations.AddField(
model_name='build',
name='completed',
field=models.PositiveIntegerField(default=0, help_text='Number of stock items which have been completed', verbose_name='Completed items'),
),
migrations.AlterField(
model_name='build',
name='quantity',
field=models.PositiveIntegerField(default=1, help_text='Number of stock items to build', validators=[django.core.validators.MinValueValidator(1)], verbose_name='Build Quantity'),
),
]

View File

@ -63,21 +63,6 @@ class Build(MPTTModel):
def get_absolute_url(self):
return reverse('build-detail', kwargs={'pk': self.id})
def clean(self):
"""
Validation for Build object.
"""
super().clean()
# Build quantity must be an integer
# Maybe in the future this will be adjusted?
if not self.quantity == int(self.quantity):
raise ValidationError({
'quantity': _("Build quantity must be integer value for trackable parts")
})
reference = models.CharField(
unique=True,
max_length=64,
@ -149,7 +134,13 @@ class Build(MPTTModel):
verbose_name=_('Build Quantity'),
default=1,
validators=[MinValueValidator(1)],
help_text=_('Number of parts to build')
help_text=_('Number of stock items to build')
)
completed = models.PositiveIntegerField(
verbose_name=_('Completed items'),
default=0,
help_text=_('Number of stock items which have been completed')
)
status = models.PositiveIntegerField(

View File

@ -38,6 +38,7 @@ class BuildSerializer(InvenTreeModelSerializer):
'url',
'title',
'creation_date',
'completed',
'completion_date',
'part',
'part_detail',
@ -51,9 +52,10 @@ class BuildSerializer(InvenTreeModelSerializer):
]
read_only_fields = [
'status',
'completed',
'creation_date',
'completion_data',
'status',
'status_text',
]

View File

@ -68,11 +68,6 @@ src="{% static 'img/blank_image.png' %}"
<h4>{% trans "Build Details" %}</h4>
<table class='table table-striped table-condensed'>
<tr>
<td><span class='fas fa-hashtag'></span></td>
<td>{% trans "Build Order Reference" %}</td>
<td>{{ build }}</td>
</tr>
<tr>
<td><span class='fas fa-shapes'></span></td>
<td>{% trans "Part" %}</td>
@ -88,6 +83,11 @@ src="{% static 'img/blank_image.png' %}"
<td>{% trans "Status" %}</td>
<td>{% build_status_label build.status %}</td>
</tr>
<tr>
<td><span class='fas fa-spinner'></span></td>
<td>{% trans "Progress" %}</td>
<td> {{ build.completed }} / {{ build.quantity }}</td>
</tr>
{% if build.parent %}
<tr>
<td><span class='fas fa-sitemap'></span></td>
@ -102,20 +102,6 @@ src="{% static 'img/blank_image.png' %}"
<td><a href="{% url 'so-detail' build.sales_order.id %}">{{ build.sales_order }}</a></td>
</tr>
{% endif %}
<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>
</table>
{% endblock %}

View File

@ -10,23 +10,25 @@
<hr>
<table class='table table-striped'>
<div class='row'>
<div class='col-sm-6'>
<table class='table table-striped'>
<col width='25'>
<tr>
<td></td>
<td>{% trans "Title" %}</td>
<tr>
<td><span class='fas fa-info'></span></td>
<td>{% trans "Description" %}</td>
<td>{{ build.title }}</td>
</tr>
<tr>
</tr>
<tr>
<td><span class='fas fa-shapes'></span></td>
<td>{% trans "Part" %}</td>
<td><a href="{% url 'part-build' build.part.id %}">{{ build.part.full_name }}</a></td>
</tr>
<tr>
</tr>
<tr>
<td></td>
<td>{% trans "Quantity" %}</td><td>{{ build.quantity }}</td>
</tr>
<tr>
</tr>
<tr>
<td><span class='fas fa-map-marker-alt'></span></td>
<td>{% trans "Stock Source" %}</td>
<td>
@ -36,8 +38,8 @@
<i>{% trans "Stock can be taken from any available location." %}</i>
{% endif %}
</td>
</tr>
<tr>
</tr>
<tr>
<td><span class='fas fa-map-marker-alt'></span></td>
<td>{% trans "Destination" %}</td>
<td>
@ -49,33 +51,71 @@
<i>{% trans "Destination location not specified" %}</i>
{% endif %}
</td>
</tr>
<tr>
</tr>
<tr>
<td><span class='fas fa-info'></span></td>
<td>{% trans "Status" %}</td>
<td>{% build_status_label build.status %}</td>
</tr>
{% if build.batch %}
<tr>
<td></td>
</tr>
<tr>
<td><span class='fas fa-spinner'></span></td>
<td>{% trans "Progress" %}</td>
<td>{{ build.completed }} / {{ build.quantity }}</td>
</tr>
{% if build.batch %}
<tr>
<td><span class='fas fa-layer-group'></span></td>
<td>{% trans "Batch" %}</td>
<td>{{ build.batch }}</td>
</tr>
{% endif %}
{% if build.link %}
<tr>
</tr>
{% endif %}
{% if build.parent %}
<tr>
<td><span class='fas fa-sitemap'></span></td>
<td>{% trans "Parent Build" %}</td>
<td><a href="{% url 'build-detail' build.parent.id %}">{{ build.parent }}</a></td>
</tr>
{% endif %}
{% if build.sales_order %}
<tr>
<td><span class='fas fa-dolly'></span></td>
<td>{% trans "Sales Order" %}</td>
<td><a href="{% url 'so-detail' build.sales_order.id %}">{{ build.sales_order }}</a></td>
</tr>
{% endif %}
{% if build.link %}
<tr>
<td><span class='fas fa-link'></span></td>
<td>{% trans "External Link" %}</td>
<td><a href="{{ build.link }}">{{ build.link }}</a></td>
</tr>
{% endif %}
<tr>
</tr>
{% endif %}
<tr>
<td><span class='fas fa-calendar-alt'></span></td>
<td>{% trans "Created" %}</td>
<td>{{ build.creation_date }}</td>
</tr>
{% if build.is_active %}
<tr>
</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.is_active %}
<tr>
<td></td>
<td>{% trans "Enough Parts?" %}</td>
<td>
@ -85,15 +125,18 @@
{% trans "No" %}
{% endif %}
</td>
</tr>
{% endif %}
{% if build.completion_date %}
<tr>
</tr>
{% endif %}
{% 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>
{% endif %}
</table>
</tr>
{% endif %}
</table>
</div>
</div>
{% endblock %}

View File

@ -130,7 +130,7 @@ class StockItem(MPTTModel):
status: Status of this StockItem (ref: InvenTree.status_codes.StockStatus)
notes: Extra notes field
build: Link to a Build (if this stock item was created from a build)
is_building: Boolean field indicating if this stock item is currently being built
is_building: Boolean field indicating if this stock item is currently being built (or is "in production")
purchase_order: Link to a PurchaseOrder (if this stock item was created from a PurchaseOrder)
infinite: If True this StockItem can never be exhausted
sales_order: Link to a SalesOrder object (if the StockItem has been assigned to a SalesOrder)

View File

@ -15,6 +15,20 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% block pre_content %}
{% include 'stock/loc_link.html' with location=item.location %}
{% if item.is_building %}
<div class='alert alert-block alert-info'>
{% trans "This stock item is in production and cannot be edited." %}<br>
{% trans "Edit the stock item from the build view." %}<br>
{% if item.build %}
<a href="{% url 'build-detail' item.build.id %}">
<b>{{ item.build }}</b>
</a>
{% endif %}
</div>
{% endif %}
{% if item.hasRequiredTests and not item.passedAllRequiredTests %}
<div class='alert alert-block alert-danger'>
{% trans "This stock item has not passed all required tests" %}
@ -79,7 +93,6 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
<div class='btn-group' role='group'>
</div>
<div class='btn-group action-buttons' role='group'>
@ -99,7 +112,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</ul>
</div>
<!-- Stock adjustment menu -->
{% if roles.stock.change %}
{% if roles.stock.change and not item.is_building %}
<div class='btn-group'>
<button id='stock-options' title='{% trans "Stock adjustment actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
@ -129,7 +142,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</div>
{% endif %}
<!-- Edit stock item -->
{% if roles.stock.change %}
{% if roles.stock.change and not item.is_building %}
<div class='btn-group'>
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
@ -221,7 +234,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% if item.location %}
<td><a href="{% url 'stock-location-detail' item.location.id %}">{{ item.location.name }}</a></td>
{% else %}
<td>{% trans "No location set" %}</td>
<td><i>{% trans "No location set" %}</i></td>
{% endif %}
</tr>
{% endif %}
@ -290,7 +303,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% if item.stocktake_date %}
<td>{{ item.stocktake_date }} <span class='badge'>{{ item.stocktake_user }}</span></td>
{% else %}
<td>{% trans "No stocktake performed" %}</td>
<td><i>{% trans "No stocktake performed" %}</i></td>
{% endif %}
</tr>
<tr>