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): class PartAdmin(ImportExportModelAdmin):
list_display = ('name', 'IPN', 'description', 'stock', 'category') list_display = ('name', 'IPN', 'description', 'total_stock', 'category')
class PartCategoryAdmin(admin.ModelAdmin): class PartCategoryAdmin(admin.ModelAdmin):

View File

@ -25,6 +25,7 @@ class EditPartForm(forms.ModelForm):
'IPN', 'IPN',
'URL', 'URL',
'minimum_stock', 'minimum_stock',
'buildable',
'trackable', 'trackable',
'purchaseable', 'purchaseable',
] ]

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

View File

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

View File

@ -41,12 +41,24 @@
{% endif %} {% endif %}
<tr> <tr>
<td>Available Stock</td> <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> </tr>
{% if part.has_bom %} {% if part.buildable %}
<tr> <tr>
<td>Can Build</td> <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> </tr>
{% endif %} {% endif %}
</table> </table>

View File

@ -1,18 +1,16 @@
<ul class="nav nav-tabs"> <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 '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.buildable %}
{% if part.has_bom %} <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</a></li> <li{% ifequal tab 'build' %} class "active"{% endifequal %}><a href="#">Build<span class='badge'>{{ part.can_build }}</span></a></li>
{% endif %} {% endif %}
{% if part.used_in_count > 0 %} {% 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> <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 %} {% 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 %} {% if part.purchaseable %}
<li{% ifequal tab 'suppliers' %} class="active"{% endifequal %}><a href="{% url 'part-suppliers' part.id %}">Suppliers <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_count }}<span>
<span class="badge">{{ part.supplier_parts.all|length }}<span>
{% endif %}
</a></li> </a></li>
{% endif %} {% endif %}
{% if part.trackable %} {% if part.trackable %}