mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
0a7ea27e9f
@ -1,3 +1,11 @@
|
||||
:root {
|
||||
--primary-color: #335d88;
|
||||
--secondary-color: #b69c80;
|
||||
--highlight-color: #f5efe8;
|
||||
--basic-color: #333;
|
||||
}
|
||||
|
||||
|
||||
.qr-code {
|
||||
max-width: 400px;
|
||||
max-height: 400px;
|
||||
@ -98,11 +106,11 @@
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.bomrowvalid {
|
||||
.rowvalid {
|
||||
color: #050;
|
||||
}
|
||||
|
||||
.bomrowinvalid {
|
||||
.rowinvalid {
|
||||
color: #A00;
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -280,9 +280,9 @@ function loadBomTable(table, options) {
|
||||
search: true,
|
||||
rowStyle: function(row, index) {
|
||||
if (row.validated) {
|
||||
return {classes: 'bomrowvalid'};
|
||||
return {classes: 'rowvalid'};
|
||||
} else {
|
||||
return {classes: 'bomrowinvalid'};
|
||||
return {classes: 'rowinvalid'};
|
||||
}
|
||||
},
|
||||
formatNoMatches: function() { return "No BOM items found"; },
|
||||
|
@ -21,7 +21,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in build.required_parts %}
|
||||
<tr>
|
||||
<tr {% if build.status == BuildStatus.PENDING %}class='{% if item.part.total_stock > item.quantity %}rowvalid{% else %}rowinvalid{% endif %}'{% endif %}>
|
||||
<td>
|
||||
{% include "hover_image.html" with image=item.part.image hover=True %}
|
||||
<a class='hover-icon'a href="{% url 'part-detail' item.part.id %}">{{ item.part.full_name }}</a>
|
||||
|
@ -34,7 +34,7 @@ InvenTree | Build - {{ build }}
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-complete' title="Complete Build">
|
||||
<span class='glyphicon glyphicon-send'/>
|
||||
</button>
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-cancel'>
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-cancel' title='Cancel Build'>
|
||||
<span class='glyphicon glyphicon-remove'/>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
@ -38,8 +38,12 @@ class SupplierPartResource(ModelResource):
|
||||
|
||||
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
||||
|
||||
part_name = Field(attribute='part__full_name', readonly=True)
|
||||
|
||||
supplier = Field(attribute='supplier', widget=widgets.ForeignKeyWidget(Company))
|
||||
|
||||
supplier_name = Field(attribute='supplier__name', readonly=True)
|
||||
|
||||
class Meta:
|
||||
model = SupplierPart
|
||||
skip_unchanged = True
|
||||
@ -61,6 +65,16 @@ class SupplierPriceBreakResource(ModelResource):
|
||||
|
||||
currency = Field(attribute='currency', widget=widgets.ForeignKeyWidget(Currency))
|
||||
|
||||
supplier_id = Field(attribute='part__supplier__pk', readonly=True)
|
||||
|
||||
supplier_name = Field(attribute='part__supplier__name', readonly=True)
|
||||
|
||||
part_name = Field(attribute='part__part__full_name', readonly=True)
|
||||
|
||||
SKU = Field(attribute='part__SKU', readonly=True)
|
||||
|
||||
MPN = Field(attribute='part__MPN', readonly=True)
|
||||
|
||||
class Meta:
|
||||
model = SupplierPriceBreak
|
||||
skip_unchanged = True
|
||||
|
@ -93,8 +93,8 @@ InvenTree | {{ company.name }} - Parts
|
||||
{{ 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' 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' 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='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>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<table class='table table-striped table-condensed' id='po-table' {% if toolbar %}data-toolbar='{{ toolbar }}'{% endif %}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field='company' data-searchable='true'>Company</th>
|
||||
<th data-field='reference' data-searchable='true'>Order Reference</th>
|
||||
<th data-field='description' data-searchable='true'>Description</th>
|
||||
<th data-field='status'>Status</th>
|
||||
<th data-field='items'>Items</th>
|
||||
<th data-field='company' data-sortable='true' data-searchable='true'>Company</th>
|
||||
<th data-field='reference' data-sortable='true' data-searchable='true'>Order Reference</th>
|
||||
<th data-field='description' data-sortable='true' data-searchable='true'>Description</th>
|
||||
<th data-field='status' data-sortable='true'>Status</th>
|
||||
<th data-field='items' data-sortable='true'>Items</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -7,6 +7,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from InvenTree.forms import HelperForm
|
||||
|
||||
from mptt.fields import TreeNodeChoiceField
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
@ -66,6 +67,12 @@ class EditPartAttachmentForm(HelperForm):
|
||||
]
|
||||
|
||||
|
||||
class SetPartCategoryForm(forms.Form):
|
||||
""" Form for setting the category of multiple Part objects """
|
||||
|
||||
part_category = TreeNodeChoiceField(queryset=PartCategory.objects.all(), required=True, help_text=_('Select part category'))
|
||||
|
||||
|
||||
class EditPartForm(HelperForm):
|
||||
""" Form for editing a Part object """
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
<div class='dropdown' style='float: right;'>
|
||||
<button id='part-options' class='btn btn-primary dropdown-toggle' type='button' data-toggle="dropdown">Options<span class='caret'></span></button>
|
||||
<ul class='dropdown-menu'>
|
||||
<li><a href='#' id='multi-part-category' title='Set category'>Set Category</a></li>
|
||||
<li><a href='#' id='multi-part-order' title='Order parts'>Order Parts</a></li>
|
||||
<li><a href='#' id='multi-part-export' title='Export'>Export Data</a></li>
|
||||
</ul>
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<div id='button-bar'>
|
||||
<div class='btn-group'>
|
||||
<button class='btn btn-primary' type='button' id='part-order-2' title='Order part'>Order Part</button>
|
||||
<button class='btn btn-primary' type='button' id='part-order2' title='Order part'>Order Part</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -31,11 +31,12 @@ $("#po-table").bootstrapTable({
|
||||
sortable: true,
|
||||
});
|
||||
|
||||
$("#part-order-2").click(function() {
|
||||
launchModalForm("/order/purchase-order/order-parts/", {
|
||||
$("#part-order2").click(function() {
|
||||
launchModalForm("{% url 'order-parts' %}", {
|
||||
data: {
|
||||
part: {{ part.id }},
|
||||
},
|
||||
reload: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -184,8 +184,8 @@
|
||||
data: {
|
||||
action: "count",
|
||||
part: {{ part.id }},
|
||||
},
|
||||
reload: true,
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -225,10 +225,10 @@
|
||||
});
|
||||
|
||||
$("#part-order").click(function() {
|
||||
launchModalForm("/order/purchase-order/order-parts/", {
|
||||
launchModalForm("{% url 'order-parts' %}", {
|
||||
data: {
|
||||
part: {{ part.id }},
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2,26 +2,8 @@
|
||||
|
||||
{% block form %}
|
||||
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
<div class='control-group'>
|
||||
<label class='control-label requiredField'>Location</label>
|
||||
<div class='controls'>
|
||||
<select class='select' name='part_category'>
|
||||
<option value=''>---------</option>
|
||||
{% for cat in categories %}
|
||||
<option value='{{ cat.id }}' {% if category and category.id == cat.id %}selected='selected'{% endif %}>{{ cat.pathstring }} - {{ cat.description }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if category %}
|
||||
<p class='help-block'>Select Part Category</p>
|
||||
{% else %}
|
||||
<p class='help-inline'>Select Part Category</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class='control-label'>Parts</label>
|
||||
<p class='help-block'>Set category for the following parts</p>
|
||||
|
||||
@ -54,5 +36,7 @@
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -46,6 +46,12 @@ def inventree_commit(*args, **kwargs):
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_github(*args, **kwargs):
|
||||
def inventree_github_url(*args, **kwargs):
|
||||
""" Return URL for InvenTree github site """
|
||||
return "https://github.com/InvenTree"
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_docs_url(*args, **kwargs):
|
||||
""" Return URL for InvenTree documenation site """
|
||||
return "https://inventree.github.io"
|
||||
|
@ -26,7 +26,10 @@ class TemplateTagTest(TestCase):
|
||||
self.assertEqual(len(hash), 7)
|
||||
|
||||
def test_github(self):
|
||||
self.assertIn('github.com', inventree_extras.inventree_github())
|
||||
self.assertIn('github.com', inventree_extras.inventree_github_url())
|
||||
|
||||
def test_docs(self):
|
||||
self.assertIn('inventree.github.io', inventree_extras.inventree_docs_url())
|
||||
|
||||
|
||||
class PartTest(TestCase):
|
||||
|
@ -6,6 +6,7 @@ Django views for interacting with Part app
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import transaction
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.shortcuts import HttpResponseRedirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -138,11 +139,12 @@ class PartAttachmentDelete(AjaxDeleteView):
|
||||
}
|
||||
|
||||
|
||||
class PartSetCategory(AjaxView):
|
||||
class PartSetCategory(AjaxUpdateView):
|
||||
""" View for settings the part category for multiple parts at once """
|
||||
|
||||
ajax_template_name = 'part/set_category.html'
|
||||
ajax_form_title = 'Set Part Category'
|
||||
form_class = part_forms.SetPartCategoryForm
|
||||
|
||||
category = None
|
||||
parts = []
|
||||
@ -157,7 +159,7 @@ class PartSetCategory(AjaxView):
|
||||
else:
|
||||
self.parts = []
|
||||
|
||||
return self.renderJsonResponse(request, context=self.get_context_data())
|
||||
return self.renderJsonResponse(request, form=self.get_form(), context=self.get_context_data())
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
""" Respond to a POST request to this view """
|
||||
@ -193,11 +195,15 @@ class PartSetCategory(AjaxView):
|
||||
}
|
||||
|
||||
if valid:
|
||||
self.set_category()
|
||||
|
||||
return self.renderJsonResponse(request, data=data, form=self.get_form(), context=self.get_context_data())
|
||||
|
||||
@transaction.atomic
|
||||
def set_category(self):
|
||||
for part in self.parts:
|
||||
part.set_category(self.category)
|
||||
|
||||
return self.renderJsonResponse(request, data=data, context=self.get_context_data())
|
||||
|
||||
def get_context_data(self):
|
||||
""" Return context data for rendering in the form """
|
||||
ctx = {}
|
||||
|
@ -26,7 +26,11 @@
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>View Code on GitHub</td><td><a href="{% inventree_github %}">{% inventree_github %}</a></td>
|
||||
<td>InvenTree Documenation</td>
|
||||
<td><a href="{% inventree_docs_url %}">{% inventree_docs_url %}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>View Code on GitHub</td><td><a href="{% inventree_github_url %}">{% inventree_github_url %}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
|
Loading…
Reference in New Issue
Block a user