Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2020-04-28 10:51:55 +10:00
commit 351e825ba8
46 changed files with 3000 additions and 1688 deletions

View File

@ -384,6 +384,10 @@
padding-bottom: 2px;
}
.action-button {
font-size: 125%;
}
.action-buttons .btn {
font-size: 175%;
align-content: center;

View File

@ -237,11 +237,11 @@ function loadBomTable(table, options) {
cols.push({
formatter: function(value, row, index, field) {
var bValidate = "<button title='Validate BOM Item' class='bom-validate-button btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='glyphicon glyphicon-check'/></button>";
var bValid = "<span class='glyphicon glyphicon-ok'/>";
var bValidate = "<button title='Validate BOM Item' class='bom-validate-button btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-check-circle icon-blue'/></button>";
var bValid = "<span title='This line has been validated' class='fas fa-check-double icon-green'/>";
var bEdit = "<button title='Edit BOM Item' class='bom-edit-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/edit'><span class='glyphicon glyphicon-edit'/></button>";
var bDelt = "<button title='Delete BOM Item' class='bom-delete-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/delete'><span class='glyphicon glyphicon-trash'/></button>";
var bEdit = "<button title='Edit BOM Item' class='bom-edit-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/edit'><span class='fas fa-edit'/></button>";
var bDelt = "<button title='Delete BOM Item' class='bom-delete-button btn btn-default btn-glyph' type='button' url='/part/bom/" + row.pk + "/delete'><span class='fas fa-trash-alt icon-red'/></button>";
var html = "<div class='btn-group' role='group'>";

View File

@ -119,8 +119,8 @@ function loadAllocationTable(table, part_id, part, url, required, button) {
formatter: function(value, row, index, field) {
var html = parseFloat(value);
var bEdit = "<button class='btn item-edit-button btn-sm' type='button' title='Edit stock allocation' url='/build/item/" + row.pk + "/edit/'><span class='glyphicon glyphicon-small glyphicon-edit'></span></button>";
var bDel = "<button class='btn item-del-button btn-sm' type='button' title='Delete stock allocation' url='/build/item/" + row.pk + "/delete/'><span class='glyphicon glyphicon-small glyphicon-trash'></span></button>";
var bEdit = "<button class='btn item-edit-button btn-sm' type='button' title='Edit stock allocation' url='/build/item/" + row.pk + "/edit/'><span class='fas fa-edit'></span></button>";
var bDel = "<button class='btn item-del-button btn-sm' type='button' title='Delete stock allocation' url='/build/item/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'></span></button>";
html += "<div class='btn-group' style='float: right;'>" + bEdit + bDel + "</div>";

View File

@ -148,7 +148,7 @@ function loadSupplierPartTable(table, url, options) {
field: 'SKU',
title: "Supplier Part",
formatter: function(value, row, index, field) {
return renderLink(value, row.url);
return renderLink(value, `/supplier-part/${row.pk}/`);
}
},
{

View File

@ -475,8 +475,8 @@ function loadStockTrackingTable(table, options) {
formatter: function(value, row, index, field) {
// Manually created entries can be edited or deleted
if (!row.system) {
var bEdit = "<button title='Edit tracking entry' class='btn btn-entry-edit btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='glyphicon glyphicon-edit'/></button>";
var bDel = "<button title='Delete tracking entry' class='btn btn-entry-delete btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='glyphicon glyphicon-trash'/></button>";
var bEdit = "<button title='Edit tracking entry' class='btn btn-entry-edit btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
var bDel = "<button title='Delete tracking entry' class='btn btn-entry-delete btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
return "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
} else {

View File

@ -25,8 +25,8 @@ from InvenTree.status_codes import BuildStatus, StockStatus
from InvenTree.fields import InvenTreeURLField
from InvenTree.helpers import decimal2string
from stock.models import StockItem
from part.models import Part, BomItem
from stock import models as StockModels
from part import models as PartModels
class Build(MPTTModel):
@ -189,7 +189,11 @@ class Build(MPTTModel):
# How many parts required for this build?
q_required = item.quantity * self.quantity
stock = StockItem.objects.filter(part=item.sub_part)
# Grab a list of StockItem objects which are "in stock"
stock = StockModels.StockItem.objects.filter(StockModels.StockItem.IN_STOCK_FILTER)
# Filter by part reference
stock = stock.filter(part=item.sub_part)
# Ensure that the available stock items are in the correct location
if self.take_from is not None:
@ -278,7 +282,7 @@ class Build(MPTTModel):
if self.part.trackable and serial_numbers:
# Add new serial numbers
for serial in serial_numbers:
item = StockItem.objects.create(
item = StockModels.StockItem.objects.create(
part=self.part,
build=self,
location=location,
@ -292,7 +296,7 @@ class Build(MPTTModel):
else:
# Add stock of the newly created item
item = StockItem.objects.create(
item = StockModels.StockItem.objects.create(
part=self.part,
build=self,
location=location,
@ -338,9 +342,9 @@ class Build(MPTTModel):
"""
try:
item = BomItem.objects.get(part=self.part.id, sub_part=part.id)
item = PartModels.BomItem.objects.get(part=self.part.id, sub_part=part.id)
q = item.quantity
except BomItem.DoesNotExist:
except PartModels.BomItem.DoesNotExist:
q = 0
return q * self.quantity
@ -461,7 +465,7 @@ class BuildItem(models.Model):
if self.stock_item.serial and not self.quantity == 1:
errors['quantity'] = _('Quantity must be 1 for serialized stock')
except (StockItem.DoesNotExist, Part.DoesNotExist):
except (StockModels.StockItem.DoesNotExist, PartModels.Part.DoesNotExist):
pass
if len(errors) > 0:

View File

@ -1,8 +1,9 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block page_title %}
InvenTree | Build List
InvenTree | {% trans "Build Orders" %}
{% endblock %}
{% block content %}
@ -10,7 +11,7 @@ InvenTree | Build List
<div class='row'>
<div class='col-sm-6'>
<h3>Part Builds</h3>
<h3>{% trans "Build Orders" %}</h3>
</div>
<div class='col-sm-6'>
@ -20,7 +21,7 @@ InvenTree | Build List
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style='float: right;'>
<button type='button' class="btn btn-success" id='new-build'>Start New Build</button>
<button type='button' class="btn btn-success" id='new-build'>{% trans "New Build Order" %}</button>
<div class='filter-list' id='filter-list-build'>
<!-- An empty div in which the filter list will be constructed -->
</div>

View File

@ -30,7 +30,7 @@
<h4>{% trans "Build Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -11,6 +11,6 @@
<a href="{% url 'build-output' build.id %}">{% trans "Build Outputs" %}{% if build.output_count > 0%}<span class='badge'>{{ build.output_count }}</span>{% endif %}</a>
</li>
<li{% if tab == 'notes' %} class='active'{% endif %}>
<a href="{% url 'build-notes' build.id %}">{% trans "Notes" %}{% if build.notes %} <span class='glyphicon glyphicon-small glyphicon-info-sign'></span>{% endif %}</a>
<a href="{% url 'build-notes' build.id %}">{% trans "Notes" %}{% if build.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a>
</li>
</ul>

View File

@ -141,10 +141,6 @@ class TestBuildViews(TestCase):
response = self.client.get(reverse('build-index'))
self.assertEqual(response.status_code, 200)
content = str(response.content)
self.assertIn("Part Builds", content)
def test_build_detail(self):
""" Test the detail view for a Build object """

View File

@ -27,7 +27,7 @@
<h4>{% trans "Company Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -19,12 +19,12 @@ src="{% static 'img/blank_image.png' %}"
<h3>{% trans "Supplier Part" %}</h3>
<p>{{ part.supplier.name }} - {{ part.SKU }}</p>
<div class='btn-row'>
<div class='btn-group'>
<button type='button' class='btn btn-default btn-glyph' id='edit-part' title='Edit supplier part'>
<span class='glyphicon glyphicon-edit'/>
<div class='btn-group action-buttons' role='group'>
<button type='button' class='btn btn-default btn-glyph' id='edit-part' title='{% trans "Edit supplier part" %}'>
<span class='fas fa-edit icon-green'/>
</button>
<button type='button' class='btn btn-default btn-glyph' id='delete-part' title='Delete supplier part'>
<span class='glyphicon glyphicon-trash'/>
<button type='button' class='btn btn-default btn-glyph' id='delete-part' title='{% trans "Delete supplier part" %}'>
<span class='fas fa-trash-alt icon-red'/>
</button>
</div>
</div>

View File

@ -36,8 +36,8 @@
{% decimal pb.cost %}
{% if pb.currency %}{{ pb.currency.suffix }}{% endif %}
<div class='btn-group' style='float: right;'>
<button title='Edit Price Break' class='btn btn-default btn-sm pb-edit-button' type='button' url="{% url 'price-break-edit' pb.id %}"><span class='glyphicon glyphicon-edit'></span></button>
<button title='Delete Price Break' class='btn btn-default btn-sm pb-delete-button' type='button' url="{% url 'price-break-delete' pb.id %}"><span class='glyphicon glyphicon-trash'></span></button>
<button title='Edit Price Break' class='btn btn-default btn-sm pb-edit-button' type='button' url="{% url 'price-break-edit' pb.id %}"><span class='fas fa-edit icon-green'></span></button>
<button title='Delete Price Break' class='btn btn-default btn-sm pb-delete-button' type='button' url="{% url 'price-break-delete' pb.id %}"><span class='fas fa-trash-alt icon-red'></span></button>
</div>
</td>
</tr>

View File

@ -23,6 +23,6 @@
</li>
{% endif %}
<li{% if tab == 'notes' %} class='active'{% endif %}>
<a href="{% url 'company-notes' company.id %}">{% trans "Notes" %}{% if company.notes %} <span class='glyphicon glyphicon-small glyphicon-info-sign'></span>{% endif %}</a>
<a href="{% url 'company-notes' company.id %}">{% trans "Notes" %}{% if company.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a>
</li>
</ul>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@
<h4>{% trans "Order Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -40,7 +40,7 @@
</td>
<td>
<button class='btn btn-default btn-create' onClick='newSupplierPartFromOrderWizard()' id='new_supplier_part_{{ part.id }}' title='Create new supplier part for {{ part }}' type='button'>
<span part-id='{{ part.id }}' class='glyphicon glyphicon-small glyphicon-plus'></span>
<span part-id='{{ part.id }}' class='fas fa-plus-circle'></span>
</button>
</td>
<td>
@ -67,7 +67,7 @@
</td>
<td>
<button class='btn btn-default btn-remove' onclick='removeOrderRowFromOrderWizard()' id='del_item_{{ part.id }}' title='Remove part' type='button'>
<span row='part_row_{{ part.id }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<span row='part_row_{{ part.id }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
</tr>

View File

@ -45,7 +45,7 @@
title='Create new purchase order for {{ supplier.name }}'
type='button'
onclick='newPurchaseOrderFromOrderWizard()'>
<span supplier-id='{{ supplier.id }}' class='glyphicon glyphicon-small glyphicon-plus'></span>
<span supplier-id='{{ supplier.id }}' class='fas fa-plus-circle'></span>
</button>
</td>
<td>

View File

@ -8,7 +8,7 @@
{% include 'order/po_tabs.html' with tab='attachments' %}
<h4>{% trans "Purchase Order Attachments" %}
<h4>{% trans "Purchase Order Attachments" %}</h4>
<hr>
@ -34,10 +34,10 @@
<td>
<div class='btn-group' style='float: right;'>
<button type='button' class='btn btn-default btn-glyph attachment-edit-button' url="{% url 'po-attachment-edit' attachment.id %}" data-toggle='tooltip' title='{% trans "Edit attachment" %}'>
<span class='glyphicon glyphicon-edit'/>
<span class='fas fa-edit'/>
</button>
<button type='button' class='btn btn-default btn-glyph attachment-delete-button' url="{% url 'po-attachment-delete' attachment.id %}" data-toggle='tooltip' title='{% trans "Delete attachment" %}'>
<span class='glyphicon glyphicon-trash'/>
<span class='fas fa-trash-alt icon-red'/>
</button>
</div>
</td>

View File

@ -12,6 +12,6 @@
</a>
</li>
<li{% ifequal tab 'notes' %} class='active'{% endifequal %}>
<a href="{% url 'po-notes' order.id %}">{% trans "Notes" %}{% if order.notes %} <span class='glyphicon glyphicon-small glyphicon-info-sign'></span>{% endif %}</a>
<a href="{% url 'po-notes' order.id %}">{% trans "Notes" %}{% if order.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a>
</li>
</ul>

View File

@ -41,7 +41,7 @@ Receive outstanding parts for <b>{{ order }}</b> - <i>{{ order.description }}</i
</td>
<td>
<button class='btn btn-default btn-remove' onClick="removeOrderRowFromOrderWizard()" id='del_item_{{ line.id }}' title='Remove line' type='button'>
<span row='line_row_{{ line.id }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<span row='line_row_{{ line.id }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
</tr>

View File

@ -34,7 +34,7 @@ InvenTree | {% trans "Sales Order" %}
<h4>{% trans "Order Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -34,10 +34,10 @@
<td>
<div class='btn-group' style='float: right;'>
<button type='button' class='btn btn-default btn-glyph attachment-edit-button' url="{% url 'so-attachment-edit' attachment.id %}" data-toggle='tooltip' title='{% trans "Edit attachment" %}'>
<span class='glyphicon glyphicon-edit'/>
<span class='fas fa-edit'/>
</button>
<button type='button' class='btn btn-default btn-glyph attachment-delete-button' url="{% url 'so-attachment-delete' attachment.id %}" data-toggle='tooltip' title='{% trans "Delete attachment" %}'>
<span class='glyphicon glyphicon-trash'/>
<span class='fas fa-trash-alt icon-red'/>
</button>
</div>
</td>

View File

@ -20,6 +20,6 @@
</a>
</li>
<li{% ifequal tab 'notes' %} class='active'{% endifequal %}>
<a href="{% url 'so-notes' order.id %}">{% trans "Notes" %}{% if order.notes %} <span class='glyphicon glyphicon-small glyphicon-info-sign'></span>{% endif %}</a>
<a href="{% url 'so-notes' order.id %}">{% trans "Notes" %}{% if order.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a>
</li>
</ul>

View File

@ -234,7 +234,7 @@ class PurchaseOrderNotes(UpdateView):
def get_success_url(self):
return reverse('purchase-order-notes', kwargs={'pk': self.get_object().id})
return reverse('po-notes', kwargs={'pk': self.get_object().id})
def get_context_data(self, **kwargs):

View File

@ -13,7 +13,7 @@ from django.urls import reverse
from django.db import models, transaction
from django.db.models import Sum
from django.db.models import prefetch_related_objects
from django.db.models.functions import Coalesce
from django.core.validators import MinValueValidator
from django.contrib.auth.models import User
@ -41,6 +41,8 @@ from InvenTree.helpers import decimal2string, normalize
from InvenTree.status_codes import BuildStatus, StockStatus, PurchaseOrderStatus
from build import models as BuildModels
from order import models as OrderModels
from company.models import SupplierPart
from stock import models as StockModels
@ -502,8 +504,7 @@ class Part(models.Model):
"""
total = self.total_stock
total -= self.allocation_count
total -= self.allocation_count()
return max(total, 0)
@ -594,46 +595,47 @@ class Part(models.Model):
return quantity
@property
def build_allocation(self):
""" Return list of builds to which this part is allocated
def build_order_allocations(self):
"""
Return all 'BuildItem' objects which allocate this part to Build objects
"""
builds = []
return BuildModels.BuildItem.objects.filter(stock_item__part__id=self.id)
for item in self.used_in.all().prefetch_related('part__builds'):
active = item.part.active_builds
for build in active:
b = {}
b['build'] = build
b['quantity'] = item.quantity * build.quantity
builds.append(b)
prefetch_related_objects(builds, 'build_items')
return builds
@property
def allocated_build_count(self):
""" Return the total number of this part that are allocated for builds
def build_order_allocation_count(self):
"""
Return the total amount of this part allocated to build orders
"""
return sum([a['quantity'] for a in self.build_allocation])
query = self.build_order_allocations().aggregate(total=Coalesce(Sum('quantity'), 0))
return query['total']
def sales_order_allocations(self):
"""
Return all sales-order-allocation objects which allocate this part to a SalesOrder
"""
return OrderModels.SalesOrderAllocation.objects.filter(item__part__id=self.id)
def sales_order_allocation_count(self):
"""
Return the tutal quantity of this part allocated to sales orders
"""
query = self.sales_order_allocations().aggregate(total=Coalesce(Sum('quantity'), 0))
return query['total']
@property
def allocation_count(self):
""" Return true if any of this part is allocated:
- To another build
- To a customer order
"""
Return the total quantity of stock allocated for this part,
against both build orders and sales orders.
"""
return sum([
self.allocated_build_count,
self.build_order_allocation_count(),
self.sales_order_allocation_count(),
])
@property
@ -645,7 +647,7 @@ class Part(models.Model):
- belongs_to is None
"""
return self.stock_items.filter(StockModels.StockItem.IN_STOCK_FILTER).exclude(status__in=StockStatus.UNAVAILABLE_CODES)
return self.stock_items.filter(StockModels.StockItem.IN_STOCK_FILTER)
@property
def total_stock(self):

View File

@ -1,24 +1,32 @@
{% extends "part/part_base.html" %}
{% block details %}
{% load status_codes %}
{% load i18n %}
{% load inventree_extras %}
{% block details %}
{% include "part/tabs.html" with tab="allocation" %}
<h4>Part Allocation</h4>
<h4>{% trans "Part Stock Allocations" %}</h4>
<table class='table table-striped table-condensed' id='build-table'>
<tr>
<th>Build</th>
<th>Making</th>
<th>Allocated</th>
<th>Status</th>
<th>{% trans "Order" %}</th>
<th>{% trans "Stock Item" %}</th>
<th>{% trans "Quantity" %}</th>
</tr>
{% for allocation in part.build_allocation %}
{% for allocation in part.build_order_allocations %}
<tr>
<td><a href="{% url 'build-detail' allocation.build.id %}">{{ allocation.build.title }}</a></td>
<td>{{ allocation.build.quantity }} &times <a href="{% url 'part-detail' allocation.build.part.id %}">{{ allocation.build.part.full_name }}</a></td>
<td>{{ allocation.quantity }}</td>
<td>{% build_status_label allocation.build.status %}</td>
<td><a href="{% url 'build-detail' allocation.build.id %}">{% trans "Build Order" %}: {{ allocation.build.pk }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.stock_item.id %}">{% trans "Stock Item" %}: {{ allocation.stock_item.id }}</a></td>
<td>{% decimal allocation.quantity %}</td>
</tr>
{% endfor %}
{% for allocation in part.sales_order_allocations %}
<tr>
<td><a href="{% url 'so-detail' allocation.line.order.id %}">{% trans "Sales Order" %}: {{ allocation.line.order.pk }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.item.id %}">{% trans "Stock Item" %}: {{ allocation.item.id }}</a></td>
<td>{% decimal allocation.quantity %}</td>
</tr>
{% endfor %}
</table>
@ -30,23 +38,16 @@
$("#build-table").inventreeTable({
columns: [
{
title: 'Build',
title: '{% trans "Order" %}',
sortable: true,
},
{
title: 'Making',
title: '{% trans "Stock Item" %}',
sortable: true,
},
{
title: 'Allocated',
sortable: false,
formatter: function(value, row, index, field) {
return parseFloat(value);
},
},
{
title: 'Status',
sortable: false,
title: '{% trans "Quantity" %}',
sortable: true,
}
]
});

View File

@ -32,10 +32,10 @@
<td>
<div class='btn-group' style='float: right;'>
<button type='button' class='btn btn-default btn-glyph attachment-edit-button' url="{% url 'part-attachment-edit' attachment.id %}" data-toggle='tooltip' title='{% trans "Edit attachment" %}'>
<span class='glyphicon glyphicon-edit'/>
<span class='fas fa-edit'/>
</button>
<button type='button' class='btn btn-default btn-glyph attachment-delete-button' url="{% url 'part-attachment-delete' attachment.id %}" data-toggle='tooltip' title='{% trans "Delete attachment" %}'>
<span class='glyphicon glyphicon-trash'/>
<span class='fas fa-trash-alt icon-red'/>
</button>
</div>
</td>

View File

@ -1,5 +1,6 @@
{% extends "part/part_base.html" %}
{% load static %}
{% load i18n %}
{% block css %}
@ -9,7 +10,7 @@
{% include 'part/tabs.html' with tab='bom' %}
<h3>Bill of Materials</h3>
<h3>{% trans "Bill of Materials" %}</h3>
{% if part.has_complete_bom_pricing == False %}
<div class='alert alert-block alert-warning'>
@ -33,18 +34,16 @@
<div id='button-toolbar' class="btn-group" role="group" aria-label="...">
{% if editing_enabled %}
<button class='btn btn-default' type='button' title='Remove selected BOM items' id='bom-item-delete'><span class='glyphicon glyphicon-trash'></span></button>
<a href="{% url 'upload-bom' part.id %}">
<button class='btn btn-default' type='button' title='Import BOM data' id='bom-upload'><span class='glyphicon glyphicon-open-file'></span></button>
</a>
<button class='btn btn-default' type='button' title='New BOM Item' id='bom-item-new'><span class='glyphicon glyphicon-plus'></span></button>
<button class='btn btn-default' type='button' title='Finish Editing' id='editing-finished'><span class='glyphicon glyphicon-ok'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Remove selected BOM items" %}' id='bom-item-delete'><span class='fas fa-trash-alt'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Import BOM data" %}' id='bom-upload'><span class='fas fa-file-upload'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "New BOM Item" %}' id='bom-item-new'><span class='fas fa-plus-circle'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Finish Editing" %}' id='editing-finished'><span class='fas fa-check-circle'></span></button>
{% elif part.active %}
<button class='btn btn-default' type='button' title='Edit BOM' id='edit-bom'><span class='glyphicon glyphicon-edit'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Edit BOM" %}' id='edit-bom'><span class='fas fa-edit'></span></button>
{% if part.is_bom_valid == False %}
<button class='btn btn-default' id='validate-bom' type='button'><span class='glyphicon glyphicon-check'></span></button>
<button class='btn btn-default action-button' id='validate-bom' title='{% trans "Validate Bill of Materials" %}' type='button'><span class='fas fa-clipboard-check'></span></button>
{% endif %}
<button title='Export BOM' class='btn btn-default' id='download-bom' type='button'><span class='glyphicon glyphicon-download-alt'></span></button>
<button title='{% trans "Export Bill of Materials" %}' class='btn btn-default action-button' id='download-bom' type='button'><span class='fas fa-file-download'></span></button>
{% endif %}
</div>
@ -76,6 +75,10 @@
location.href = "{% url 'part-bom' part.id %}";
});
$('#bom-upload').click(function() {
location.href = "{% url 'upload-bom' part.id %}";
});
$("#bom-item-new").click(function () {
launchModalForm(
"{% url 'bom-item-create' %}?parent={{ part.id }}",

View File

@ -38,7 +38,7 @@
<input type='hidden' name='col_name_{{ forloop.counter0 }}' value='{{ col.name }}'/>
{{ col.name }}
<button class='btn btn-default btn-remove' onClick='removeColFromBomWizard()' id='del_col_{{ forloop.counter0 }}' style='display: inline; float: right;' title='Remove column'>
<span col_id='{{ forloop.counter0 }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<span col_id='{{ forloop.counter0 }}' class='fas fa-trash-alt icon-red'></span>
</button>
</div>
</th>
@ -67,7 +67,7 @@
<tr>
<td>
<button class='btn btn-default btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ forloop.counter }}' style='display: inline; float: right;' title='Remove row'>
<span row_id='{{ forloop.counter }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<span row_id='{{ forloop.counter }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
<td>{{ forloop.counter }}</td>

View File

@ -48,7 +48,7 @@
<tr {% if row.errors %} style='background: #ffeaea;'{% endif %} part-name='{{ row.part_name }}' part-description='{{ row.description }}' part-select='#select_part_{{ row.index }}'>
<td>
<button class='btn btn-default btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ forloop.counter }}' style='display: inline; float: right;' title='Remove row'>
<span row_id='{{ forloop.counter }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<span row_id='{{ forloop.counter }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
<td>
@ -58,7 +58,7 @@
<td>
{% if item.column.guess == 'Part' %}
<button class='btn btn-default btn-create' onClick='newPartFromBomWizard()' id='new_part_row_{{ row.index }}' title='Create new part' type='button'>
<span row_id='{{ row.index }}' class='glyphicon glyphicon-small glyphicon-plus'/>
<span row_id='{{ row.index }}' class='fas fa-trash-alt icon-red'/>
</button>
<select class='select bomselect' id='select_part_{{ row.index }}' name='part_{{ row.index }}'>

View File

@ -29,7 +29,7 @@
<h4>{% trans "Part Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -1,24 +1,25 @@
{% extends "part/part_base.html" %}
{% load static %}
{% load i18n %}
{% block details %}
{% include "part/tabs.html" with tab='params' %}
<h4>Part Parameters</h4>
<h4>{% trans "Part Parameters" %}</h4>
<hr>
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-success' id='param-create'>New Parameter</button>
<button title='{% trans "Add new parameter" %}' class='btn btn-success' id='param-create'>{% trans "New Parameter" %}</button>
</div>
</div>
<table id='param-table' class='table table-condensed table-striped' data-toolbar='#button-toolbar'>
<thead>
<tr>
<th data-field='name' data-serachable='true'>Name</th>
<th data-field='value' data-searchable='true'>Value</th>
<th data-field='units' data-searchable='true'>Units</th>
<th data-field='name' data-serachable='true'>{% trans "Name" %}</th>
<th data-field='value' data-searchable='true'>{% trans "Value" %}</th>
<th data-field='units' data-searchable='true'>{% trans "Units" %}</th>
</tr>
</thead>
<tbody>
@ -29,8 +30,8 @@
<td>
{{ param.template.units }}
<div class='btn-group' style='float: right;'>
<button title='Edit' class='btn btn-default btn-glyph param-edit' url="{% url 'part-param-edit' param.id %}" type='button'><span class='glyphicon glyphicon-edit'/></button>
<button title='Delete' class='btn btn-default btn-glyph param-delete' url="{% url 'part-param-delete' param.id %}" type='button'><span class='glyphicon glyphicon-trash'/></button>
<button title='{% trans "Edit" %}' class='btn btn-default btn-glyph param-edit' url="{% url 'part-param-edit' param.id %}" type='button'><span class='fas fa-edit'/></button>
<button title='{% trans "Delete" %}' class='btn btn-default btn-glyph param-delete' url="{% url 'part-param-delete' param.id %}" type='button'><span class='fas fa-trash-alt icon-red'/></button>
</div>
</td>
</tr>

View File

@ -13,8 +13,8 @@
</div>
<div class='btn-row part-thumb-overlay'>
<div class='btn-group'>
<button type='button' class='btn btn-default btn-glyph' title="{% trans 'Select from existing images' %}" id='part-image-select'><span class='glyphicon glyphicon-th'></span></button>
<button type='button' class='btn btn-default btn-glyph' title="{% trans 'Upload new image' %}" id='part-image-upload'><span class='glyphicon glyphicon-upload'></span></button>
<button type='button' class='btn btn-default btn-glyph' title="{% trans 'Select from existing images' %}" id='part-image-select'><span class='fas fa-th'></span></button>
<button type='button' class='btn btn-default btn-glyph' title="{% trans 'Upload new image' %}" id='part-image-upload'><span class='fas fa-file-image'></span></button>
</div>
</div>
</div>

View File

@ -1,17 +1,18 @@
{% extends "modal_form.html" %}
{% load i18n %}
{% block form %}
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
{% load crispy_forms_tags %}
<label class='control-label'>Parts</label>
<p class='help-block'>Set category for the following parts</p>
<p class='help-block'>{% trans "Set category for the following parts" %}</p>
<table class='table table-striped'>
<tr>
<th>Part</th>
<th>Description</th>
<th>Category</th>
<th>{% trans "Part" %}</th>
<th>{% trans "Description" %}</th>
<th>{% trans "Category" %}</th>
<th>
</tr>
{% for part in parts %}
@ -28,8 +29,8 @@
{{ part.category.pathstring }}
</td>
<td>
<button class='btn btn-default btn-remove' onClick='removeRowFromModalForm()' title='Remove part' type='button'>
<span row='part_row_{{ part.id }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
<button class='btn btn-default btn-remove' onClick='removeRowFromModalForm()' title='{% trans "Remove part" %}' type='button'>
<span row='part_row_{{ part.id }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
</tr>

View File

@ -31,7 +31,6 @@ from InvenTree.models import InvenTreeTree
from InvenTree.fields import InvenTreeURLField
from part import models as PartModels
from order.models import PurchaseOrder, SalesOrder
class StockLocation(InvenTreeTree):
@ -134,7 +133,12 @@ class StockItem(MPTTModel):
"""
# A Query filter which will be re-used in multiple places to determine if a StockItem is actually "in stock"
IN_STOCK_FILTER = Q(sales_order=None, build_order=None, belongs_to=None)
IN_STOCK_FILTER = Q(
sales_order=None,
build_order=None,
belongs_to=None,
status__in=StockStatus.AVAILABLE_CODES
)
def save(self, *args, **kwargs):
if not self.pk:
@ -393,7 +397,7 @@ class StockItem(MPTTModel):
)
purchase_order = models.ForeignKey(
PurchaseOrder,
'order.PurchaseOrder',
on_delete=models.SET_NULL,
verbose_name=_('Source Purchase Order'),
related_name='stock_items',
@ -402,7 +406,7 @@ class StockItem(MPTTModel):
)
sales_order = models.ForeignKey(
SalesOrder,
'order.SalesOrder',
on_delete=models.SET_NULL,
verbose_name=_("Destination Sales Order"),
related_name='stock_items',

View File

@ -29,7 +29,7 @@
<h4>{% trans "Stock Item Notes" %}</h4>
</div>
<div class='col-sm-6'>
<button title='{% trans "Edit notes" %}' class='btn btn-default btn-glyph float-right' id='edit-notes'><span class='glyphicon glyphicon-edit'></span></button>
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
</div>
</div>
<hr>

View File

@ -9,24 +9,24 @@
<h3>{{ location.name }}</h3>
<p>{{ location.description }}</p>
{% else %}
<h3>Stock</h3>
<p>All stock items</p>
<h3>{% trans "Stock" %}</h3>
<p>{% trans "All stock items" %}</p>
{% endif %}
<p>
<div class='btn-group action-buttons'>
<button class='btn btn-default' id='location-create' title='Create new stock location'>
<button class='btn btn-default' id='location-create' title='{% trans "Create new stock location" %}'>
<span class='fas fa-plus-circle icon-green'/>
</button>
{% if location %}
{% include "qr_button.html" %}
<button class='btn btn-default' id='location-count' title='Count stock items'>
<button class='btn btn-default' id='location-count' title='{% trans "Count stock items" %}'>
<span class='fas fa-clipboard-list'/>
</button>
<button class='btn btn-default btn-glyph' id='location-edit' title='Edit stock location'>
<button class='btn btn-default btn-glyph' id='location-edit' title='{% trans "Edit stock location" %}'>
<span class='fas fa-edit icon-blue'/>
</button>
<button class='btn btn-default btn-glyph' id='location-delete' title='Delete stock location'>
<span class='glyphicon glyphicon-trash icon-red'/>
<button class='btn btn-default btn-glyph' id='location-delete' title='{% trans "Delete stock location" %}'>
<span class='fas fa-trash-alt icon-red'/>
</button>
{% endif %}
</div>

View File

@ -40,7 +40,7 @@
<input type='hidden' name='stock-id-{{ item.id }}' value='{{ item.new_quantity }}'/>
{% endif %}
</td>
<td><button class='btn btn-default btn-remove' onclick='removeStockRow()' id='del-{{ item.id }}' title='Remove item' type='button'><span row='stock-row-{{ item.id }}' class='glyphicon glyphicon-small glyphicon-remove'></span></button></td>
<td><button class='btn btn-default btn-remove' onclick='removeStockRow()' id='del-{{ item.id }}' title='Remove item' type='button'><span row='stock-row-{{ item.id }}' class='fas fa-trash-alt icon-red'></span></button></td>
</tr>
{% endfor %}
</table>

View File

@ -14,6 +14,6 @@
</li>
{% endif %}
<li{% ifequal tab 'notes' %} class='active'{% endifequal %}>
<a href="{% url 'stock-item-notes' item.id %}">{% trans "Notes" %}{% if item.notes %} <span class='glyphicon glyphicon-small glyphicon-info-sign'></span>{% endif %}</a>
<a href="{% url 'stock-item-notes' item.id %}">{% trans "Notes" %}{% if item.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a>
</li>
</ul>

View File

@ -67,8 +67,8 @@
{
formatter: function(value, row, index, field) {
var bEdit = "<button title='Edit Currency' class='cur-edit btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='glyphicon glyphicon-edit'></span></button>";
var bDel = "<button title='Delete Currency' class='cur-delete btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='glyphicon glyphicon-trash'></span></button>";
var bEdit = "<button title='Edit Currency' class='cur-edit btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-edit'></span></button>";
var bDel = "<button title='Delete Currency' class='cur-delete btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-trash-alt icon-red'></span></button>";
var html = "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";

View File

@ -1,14 +1,15 @@
{% extends "InvenTree/settings/settings.html" %}
{% load i18n %}
{% block tabs %}
{% include "InvenTree/settings/tabs.html" with tab='part' %}
{% endblock %}
{% block settings %}
<h4>Part Parameter Templates</h4>
<h4>{% transa "Part Parameter Templates" %}</h4>
<div id='param-buttons'>
<button class='btn btn-success' id='new-param'>New Parameter</button>
<button class='btn btn-success' id='new-param'>{% trans "New Parameter" %}</button>
</div>
<table class='table table-striped table-condensed' id='param-table' data-toolbar='#param-buttons'>
@ -24,7 +25,7 @@
queryParams: {
ordering: 'name',
},
formatNoMatches: function() { return "No part parameter templates found"; },
formatNoMatches: function() { return '{% trans "No part parameter templates found" %}'; },
columns: [
{
field: 'pk',
@ -43,8 +44,8 @@
},
{
formatter: function(value, row, index, field) {
var bEdit = "<button title='Edit Template' class='template-edit btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='glyphicon glyphicon-edit'></span></button>";
var bDel = "<button title='Delete Template' class='template-delete btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='glyphicon glyphicon-trash'></span></button>";
var bEdit = "<button title='{% trans "Edit Template" %}' class='template-edit btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-edit'></span></button>";
var bDel = "<button title='{% trans "Delete Template" %}' class='template-delete btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-trash-alt icon-red'></span></button>";
var html = "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";

View File

@ -1,16 +1,16 @@
<ul class='nav nav-pills nav-stacked'>
<li{% ifequal tab 'user' %} class='active'{% endifequal %}>
<a href="{% url 'settings-user' %}"><span class='glyphicon glyphicon-user'></span> User</a>
<a href="{% url 'settings-user' %}"><span class='fas fa-user'></span> User</a>
</li>
<li{% ifequal tab 'currency' %} class='active'{% endifequal %}>
<a href="{% url 'settings-currency' %}"><span class='glyphicon glyphicon-usd'></span> Currency</a>
<a href="{% url 'settings-currency' %}"><span class='fas fa-dollar-sign'></span> Currency</a>
</li>
<li{% ifequal tab 'part' %} class='active'{% endifequal %}>
<a href="{% url 'settings-part' %}"><span class='glyphicon glyphicon-briefcase'></span> Part</a>
<a href="{% url 'settings-part' %}"><span class='fas fa-shapes'></span> Part</a>
</li>
{% if user.is_staff %}
<li{% ifequal tab 'other' %} class='active'{% endifequal %}>
<a href="{% url 'settings-other' %}"><span class='glyphicon glyphicon-cog'></span>Other</a>
<a href="{% url 'settings-other' %}"><span class='fas fa-cogs'></span> Other</a>
</li>
{% endif %}
</ul>