Parts now know how many builds they are allocated to

- allocated_builds returns lists of active builds this part is allocated to
- allocated_build_count returns the total number of this part allocated to builds
- allocation_count returns total number of allocated parts (in the future this will also include those parts allocated to customer orders)
This commit is contained in:
Oliver 2018-04-17 22:26:57 +10:00
parent 0b40197cd2
commit 11b9fb10d8
8 changed files with 123 additions and 28 deletions

View File

@ -158,9 +158,11 @@ class Part(models.Model):
This subtracts stock which is already allocated This subtracts stock which is already allocated
""" """
# TODO - For now, just return total stock count total = self.total_stock
# TODO - In future must take account of allocated stock
return self.total_stock total -= self.allocation_count
return max(total, 0)
@property @property
def can_build(self): def can_build(self):
@ -181,7 +183,7 @@ class Part(models.Model):
if total is None or n < total: if total is None or n < total:
total = n total = n
return total return max(total, 0)
@property @property
def active_builds(self): def active_builds(self):
@ -205,6 +207,44 @@ class Part(models.Model):
return sum([b.quantity for b in self.active_builds]) return sum([b.quantity for b in self.active_builds])
@property
def allocated_builds(self):
""" Return list of builds to which this part is allocated
"""
builds = []
for item in self.used_in.all():
for build in item.part.active_builds:
builds.append(build)
return builds
@property
def allocated_build_count(self):
""" Return the total number of this that are allocated for builds
"""
total = 0
for item in self.used_in.all():
for build in item.part.active_builds:
n = build.quantity * item.quantity
total += n
return total
@property
def allocation_count(self):
""" Return true if any of this part is allocated
- To another build
- To a customer order
"""
return sum([
self.allocated_build_count,
])
@property @property
def total_stock(self): def total_stock(self):
""" Return the total stock quantity for this part. """ Return the total stock quantity for this part.

View File

@ -0,0 +1,29 @@
{% extends "part/part_base.html" %}
{% block details %}
{% include "part/tabs.html" with tab="allocation" %}
<h3>Part Allocation</h3>
{% if part.allocated_build_count > 0 %}
<h4>Allocated to Part Builds</h4>
<table class='table table-striped'>
<tr>
<th>Build</th>
<th>Making</th>
<th>Allocted</th>
<th>Status</th>
</tr>
{% for build in part.allocated_builds %}
<tr>
<td><a href="{% url 'build-detail' build.id %}">{{ build.title }}</a></td>
<td><a href="{% url 'part-detail' build.part.id %}">{{ build.part.name }}</a></td>
<td>Quantity</td>
<td>{% include "part/build_status.html" with build=build %}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endblock %}

View File

@ -3,18 +3,8 @@
<td><a href="{% url 'build-detail' build.id %}">{{ build.title }}</a></td> <td><a href="{% url 'build-detail' build.id %}">{{ build.title }}</a></td>
<td>{{ build.quantity }}</td> <td>{{ build.quantity }}</td>
<td> <td>
{% if build.status == build.PENDING %} {% include "part/build_status.html" with build=build %}
<span class='label label-info'>
{% elif build.status == build.HOLDING %}
<span class='label label-warning'>
{% elif build.status == build.CANCELLED %}
<span class='label label-danger'>
{% elif build.status == build.COMPLETE %}
<span class='label label-success'>
{% endif %}
{{ build.get_status_display }}
</span>
</td> </td>
<td>{{ build.completion_date }}</td> <td>{% if build.completion_date %}{{ build.completion_date }}{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,11 @@
{% if build.status == build.PENDING %}
<span class='label label-info'>
{% elif build.status == build.HOLDING %}
<span class='label label-warning'>
{% elif build.status == build.CANCELLED %}
<span class='label label-danger'>
{% elif build.status == build.COMPLETE %}
<span class='label label-success'>
{% endif %}
{{ build.get_status_display }}
</span>

View File

@ -22,11 +22,6 @@
{% if part.description %} {% if part.description %}
<p><i>{{ part.description }}</i></p> <p><i>{{ part.description }}</i></p>
{% endif %} {% endif %}
</div>
</div>
</div>
<div class="col-sm-6">
<table class="table table-striped">
{% if part.IPN %} {% if part.IPN %}
<tr> <tr>
<td>IPN</td> <td>IPN</td>
@ -39,15 +34,22 @@
<td><a href="{{ part.URL }}">{{ part.URL }}</a></td> <td><a href="{{ part.URL }}">{{ part.URL }}</a></td>
</tr> </tr>
{% endif %} {% endif %}
</div>
</div>
</div>
<div class="col-sm-6">
<h4>Stock Status - {{ part.available_stock }} available</h4>
<table class="table table-striped">
<tr> <tr>
<td>Available Stock</td> <td>In Stock</td>
<td> <td>
{% if part.available_stock == 0 %} {% if part.stock == 0 %}
<span class='label label-danger'>{{ part.available_stock }}</span> <span class='label label-danger'>{{ part.total_stock }}</span>
{% elif part.available_stock < part.minimum_stock %} {% elif part.stock < part.minimum_stock %}
<span class='label label-warning'>{{ part.available_stock }}</span> <span class='label label-warning'>{{ part.total_stock }}</span>
{% else %} {% else %}
{{ part.available_stock }} {{ part.total_stock }}
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@ -62,6 +64,23 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% if part.quantity_being_built > 0 %}
<tr>
<td>Underway</td>
<td>{{ part.quantity_being_built }}</td>
</tr>
{% endif %}
{% endif %}
{% if part.allocation_count > 0 %}
<tr>
<td>Allocated</td>
{% if part.allocation_count > part.total_stock %}
<td><span class='label label-danger'>{{ part.allocation_count }}</span>
{% else %}
{{ part.allocation_count }} {{ part.total_stock }}
{% endif %}
</td>
</tr>
{% endif %} {% endif %}
</table> </table>
</div> </div>

View File

@ -7,7 +7,10 @@
{% 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.available_stock }}</span></a></li> <li{% ifequal tab 'stock' %} class="active"{% endifequal %}><a href="{% url 'part-stock' part.id %}">Stock <span class="badge">{{ part.total_stock }}</span></a></li>
{% if part.allocation_count > 0 %}
<li{% ifequal tab 'allocation' %} class="active"{% endifequal %}><a href="{% url 'part-allocation' part.id %}">Allocated <span class="badge">{{ part.allocation_count }}</span></a></li>
{% endif %}
{% 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
<span class="badge">{{ part.supplier_count }}<span> <span class="badge">{{ part.supplier_count }}<span>

View File

@ -9,11 +9,13 @@
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Part</th> <th>Part</th>
<th>Uses</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
{% for item in part.used_in.all %} {% for item in part.used_in.all %}
<tr> <tr>
<td><a href="{% url 'part-bom' item.part.id %}">{{ item.part.name }}</a></td> <td><a href="{% url 'part-bom' item.part.id %}">{{ item.part.name }}</a></td>
<td>{{ item.quantity }}</td>
<td>{{ item.part.description }}</td> <td>{{ item.part.description }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -44,6 +44,7 @@ part_detail_urls = [
url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'),
url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'), url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'),
url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'),
url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'),
url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'), url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'),
# Any other URLs go to the part detail page # Any other URLs go to the part detail page