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

@ -62,21 +62,6 @@ class Build(MPTTModel):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('build-detail', kwargs={'pk': self.id}) 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( reference = models.CharField(
unique=True, unique=True,
@ -149,7 +134,13 @@ class Build(MPTTModel):
verbose_name=_('Build Quantity'), verbose_name=_('Build Quantity'),
default=1, default=1,
validators=[MinValueValidator(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( status = models.PositiveIntegerField(

View File

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

View File

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

View File

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

View File

@ -130,7 +130,7 @@ class StockItem(MPTTModel):
status: Status of this StockItem (ref: InvenTree.status_codes.StockStatus) status: Status of this StockItem (ref: InvenTree.status_codes.StockStatus)
notes: Extra notes field notes: Extra notes field
build: Link to a Build (if this stock item was created from a build) 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) purchase_order: Link to a PurchaseOrder (if this stock item was created from a PurchaseOrder)
infinite: If True this StockItem can never be exhausted 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) 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 %} {% block pre_content %}
{% include 'stock/loc_link.html' with location=item.location %} {% 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 %} {% if item.hasRequiredTests and not item.passedAllRequiredTests %}
<div class='alert alert-block alert-danger'> <div class='alert alert-block alert-danger'>
{% trans "This stock item has not passed all required tests" %} {% 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 class='btn-group' role='group'>
</div> </div>
<div class='btn-group action-buttons' role='group'> <div class='btn-group action-buttons' role='group'>
@ -99,7 +112,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</ul> </ul>
</div> </div>
<!-- Stock adjustment menu --> <!-- Stock adjustment menu -->
{% if roles.stock.change %} {% if roles.stock.change and not item.is_building %}
<div class='btn-group'> <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> <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'> <ul class='dropdown-menu' role='menu'>
@ -129,7 +142,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</div> </div>
{% endif %} {% endif %}
<!-- Edit stock item --> <!-- Edit stock item -->
{% if roles.stock.change %} {% if roles.stock.change and not item.is_building %}
<div class='btn-group'> <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> <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'> <ul class='dropdown-menu' role='menu'>
@ -221,7 +234,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% if item.location %} {% if item.location %}
<td><a href="{% url 'stock-location-detail' item.location.id %}">{{ item.location.name }}</a></td> <td><a href="{% url 'stock-location-detail' item.location.id %}">{{ item.location.name }}</a></td>
{% else %} {% else %}
<td>{% trans "No location set" %}</td> <td><i>{% trans "No location set" %}</i></td>
{% endif %} {% endif %}
</tr> </tr>
{% endif %} {% endif %}
@ -290,7 +303,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% if item.stocktake_date %} {% if item.stocktake_date %}
<td>{{ item.stocktake_date }} <span class='badge'>{{ item.stocktake_user }}</span></td> <td>{{ item.stocktake_date }} <span class='badge'>{{ item.stocktake_user }}</span></td>
{% else %} {% else %}
<td>{% trans "No stocktake performed" %}</td> <td><i>{% trans "No stocktake performed" %}</i></td>
{% endif %} {% endif %}
</tr> </tr>
<tr> <tr>