Improved part logic

- Added field 'buildable' - can this part be made from other parts?
- Added @propery 'supplier_count'
- Improved part detail page with new features
This commit is contained in:
Oliver 2018-04-16 22:13:31 +10:00
parent e43439ef5b
commit 118d045e50
7 changed files with 61 additions and 16 deletions

View File

@ -8,7 +8,7 @@ from .models import PartAttachment
class PartAdmin(ImportExportModelAdmin):
list_display = ('name', 'IPN', 'description', 'stock', 'category')
list_display = ('name', 'IPN', 'description', 'total_stock', 'category')
class PartCategoryAdmin(admin.ModelAdmin):

View File

@ -25,6 +25,7 @@ class EditPartForm(forms.ModelForm):
'IPN',
'URL',
'minimum_stock',
'buildable',
'trackable',
'purchaseable',
]
@ -58,7 +59,7 @@ class EditBomItemForm(forms.ModelForm):
self.helper.form_id = 'id-edit-part-form'
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-16 12:08
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0017_part_purchaseable'),
]
operations = [
migrations.AddField(
model_name='part',
name='buildable',
field=models.BooleanField(default=False),
),
]

View File

@ -110,6 +110,9 @@ class Part(models.Model):
# Units of quantity for this part. Default is "pcs"
units = models.CharField(max_length=20, default="pcs", blank=True)
# Can this part be built?
buildable = models.BooleanField(default=False)
# Is this part "trackable"?
# Trackable parts can have unique instances
# which are assigned serial numbers (or batch numbers)
@ -139,7 +142,8 @@ class Part(models.Model):
"""
# TODO - For now, just return total stock count
return self.stock
# TODO - In future must take account of allocated stock
return self.total_stock
@property
def can_build(self):
@ -152,6 +156,7 @@ class Part(models.Model):
total = None
# Calculate the minimum number of parts that can be built using each sub-part
for item in self.bom_items.all():
stock = item.sub_part.available_stock
n = int(1.0 * stock / item.quantity)
@ -162,7 +167,7 @@ class Part(models.Model):
return total
@property
def stock(self):
def total_stock(self):
""" Return the total stock quantity for this part.
Part may be stored in multiple locations
"""
@ -176,16 +181,21 @@ class Part(models.Model):
@property
def has_bom(self):
return self.bom_item_count > 0
return self.bom_count > 0
@property
def bom_item_count(self):
def bom_count(self):
return self.bom_items.all().count()
@property
def used_in_count(self):
return self.used_in.all().count()
@property
def supplier_count(self):
# Return the number of supplier parts available for this part
return self.supplier_parts.all().count()
"""
@property
def projects(self):

View File

@ -25,6 +25,10 @@
<td>Units</td>
<td>{{ part.units }}</td>
</tr>
<tr>
<td>Buildable</td>
<td>{{ part.buildable }}</td>
</tr>
<tr>
<td>Trackable</td>
<td>{{ part.trackable }}</td>

View File

@ -41,12 +41,24 @@
{% endif %}
<tr>
<td>Available Stock</td>
<td>{{ part.available_stock }}</td>
<td>
{% if part.available_stock == 0 or part.available_stock < part.minimum_stock %}
<span class='label label-danger'>{{ part.available_stock }}</span>
{% else %}
{{ part.available_stock }}
{% endif %}
</td>
</tr>
{% if part.has_bom %}
{% if part.buildable %}
<tr>
<td>Can Build</td>
<td>{{ part.can_build }}</td>
<td>
{% if part.can_build == 0 %}
<span class='label label-danger'>0</span>
{% else %}
{{ part.can_build }}
{% endif %}
</td>
</tr>
{% endif %}
</table>

View File

@ -1,18 +1,16 @@
<ul class="nav nav-tabs">
<li{% ifequal tab 'detail' %} class="active"{% endifequal %}><a href="{% url 'part-detail' part.id %}">Details</a></li>
<li{% ifequal tab 'bom' %} class="active"{% endifequal %}><a href="{% url 'part-bom' part.id %}">BOM{% if part.has_bom > 0 %}<span class="badge">{{ part.bom_item_cout }}</span>{% endif %}</a></li>
{% if part.has_bom %}
<li{% ifequal tab 'build' %} class "active"{% endifequal %}><a href="#">Build</a></li>
{% if part.buildable %}
<li{% ifequal tab 'bom' %} class="active"{% endifequal %}><a href="{% url 'part-bom' part.id %}">BOM<span class="badge">{{ part.bom_count }}</span></a></li>
<li{% ifequal tab 'build' %} class "active"{% endifequal %}><a href="#">Build<span class='badge'>{{ part.can_build }}</span></a></li>
{% endif %}
{% if part.used_in_count > 0 %}
<li{% ifequal tab 'used' %} class="active"{% endifequal %}><a href="{% url 'part-used-in' part.id %}">Used In{% if part.used_in_count > 0 %}<span class="badge">{{ part.used_in_count }}</span>{% endif %}</a></li>
{% endif %}
<li{% ifequal tab 'stock' %} class="active"{% endifequal %}><a href="{% url 'part-stock' part.id %}">Stock <span class="badge">{{ part.stock }}</span></a></li>
<li{% ifequal tab 'stock' %} class="active"{% endifequal %}><a href="{% url 'part-stock' part.id %}">Stock <span class="badge">{{ part.available_stock }}</span></a></li>
{% if part.purchaseable %}
<li{% ifequal tab 'suppliers' %} class="active"{% endifequal %}><a href="{% url 'part-suppliers' part.id %}">Suppliers
{% if part.supplier_parts.all|length > 0 %}
<span class="badge">{{ part.supplier_parts.all|length }}<span>
{% endif %}
<span class="badge">{{ part.supplier_count }}<span>
</a></li>
{% endif %}
{% if part.trackable %}