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 {
|
.qr-code {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
@ -98,11 +106,11 @@
|
|||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bomrowvalid {
|
.rowvalid {
|
||||||
color: #050;
|
color: #050;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bomrowinvalid {
|
.rowinvalid {
|
||||||
color: #A00;
|
color: #A00;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
@ -280,9 +280,9 @@ function loadBomTable(table, options) {
|
|||||||
search: true,
|
search: true,
|
||||||
rowStyle: function(row, index) {
|
rowStyle: function(row, index) {
|
||||||
if (row.validated) {
|
if (row.validated) {
|
||||||
return {classes: 'bomrowvalid'};
|
return {classes: 'rowvalid'};
|
||||||
} else {
|
} else {
|
||||||
return {classes: 'bomrowinvalid'};
|
return {classes: 'rowinvalid'};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatNoMatches: function() { return "No BOM items found"; },
|
formatNoMatches: function() { return "No BOM items found"; },
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in build.required_parts %}
|
{% 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>
|
<td>
|
||||||
{% include "hover_image.html" with image=item.part.image hover=True %}
|
{% 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>
|
<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">
|
<button type='button' class='btn btn-default btn-glyph' id='build-complete' title="Complete Build">
|
||||||
<span class='glyphicon glyphicon-send'/>
|
<span class='glyphicon glyphicon-send'/>
|
||||||
</button>
|
</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'/>
|
<span class='glyphicon glyphicon-remove'/>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -38,8 +38,12 @@ class SupplierPartResource(ModelResource):
|
|||||||
|
|
||||||
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
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 = Field(attribute='supplier', widget=widgets.ForeignKeyWidget(Company))
|
||||||
|
|
||||||
|
supplier_name = Field(attribute='supplier__name', readonly=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SupplierPart
|
model = SupplierPart
|
||||||
skip_unchanged = True
|
skip_unchanged = True
|
||||||
@ -61,6 +65,16 @@ class SupplierPriceBreakResource(ModelResource):
|
|||||||
|
|
||||||
currency = Field(attribute='currency', widget=widgets.ForeignKeyWidget(Currency))
|
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:
|
class Meta:
|
||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
skip_unchanged = True
|
skip_unchanged = True
|
||||||
|
@ -93,8 +93,8 @@ InvenTree | {{ company.name }} - Parts
|
|||||||
{{ pb.cost }}
|
{{ pb.cost }}
|
||||||
{% if pb.currency %}{{ pb.currency.suffix }}{% endif %}
|
{% if pb.currency %}{{ pb.currency.suffix }}{% endif %}
|
||||||
<div class='btn-group' style='float: right;'>
|
<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='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' type='button' url="{% url 'price-break-delete' pb.id %}"><span class='glyphicon glyphicon-trash'></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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<table class='table table-striped table-condensed' id='po-table' {% if toolbar %}data-toolbar='{{ toolbar }}'{% endif %}>
|
<table class='table table-striped table-condensed' id='po-table' {% if toolbar %}data-toolbar='{{ toolbar }}'{% endif %}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-field='company' data-searchable='true'>Company</th>
|
<th data-field='company' data-sortable='true' data-searchable='true'>Company</th>
|
||||||
<th data-field='reference' data-searchable='true'>Order Reference</th>
|
<th data-field='reference' data-sortable='true' data-searchable='true'>Order Reference</th>
|
||||||
<th data-field='description' data-searchable='true'>Description</th>
|
<th data-field='description' data-sortable='true' data-searchable='true'>Description</th>
|
||||||
<th data-field='status'>Status</th>
|
<th data-field='status' data-sortable='true'>Status</th>
|
||||||
<th data-field='items'>Items</th>
|
<th data-field='items' data-sortable='true'>Items</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -7,6 +7,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from InvenTree.forms import HelperForm
|
from InvenTree.forms import HelperForm
|
||||||
|
|
||||||
|
from mptt.fields import TreeNodeChoiceField
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext as _
|
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):
|
class EditPartForm(HelperForm):
|
||||||
""" Form for editing a Part object """
|
""" Form for editing a Part object """
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
<div class='dropdown' style='float: right;'>
|
<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>
|
<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'>
|
<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-order' title='Order parts'>Order Parts</a></li>
|
||||||
<li><a href='#' id='multi-part-export' title='Export'>Export Data</a></li>
|
<li><a href='#' id='multi-part-export' title='Export'>Export Data</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<div id='button-bar'>
|
<div id='button-bar'>
|
||||||
<div class='btn-group'>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -31,11 +31,12 @@ $("#po-table").bootstrapTable({
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#part-order-2").click(function() {
|
$("#part-order2").click(function() {
|
||||||
launchModalForm("/order/purchase-order/order-parts/", {
|
launchModalForm("{% url 'order-parts' %}", {
|
||||||
data: {
|
data: {
|
||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
},
|
},
|
||||||
|
reload: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -184,8 +184,8 @@
|
|||||||
data: {
|
data: {
|
||||||
action: "count",
|
action: "count",
|
||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
reload: true,
|
},
|
||||||
}
|
reload: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -225,10 +225,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#part-order").click(function() {
|
$("#part-order").click(function() {
|
||||||
launchModalForm("/order/purchase-order/order-parts/", {
|
launchModalForm("{% url 'order-parts' %}", {
|
||||||
data: {
|
data: {
|
||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,26 +2,8 @@
|
|||||||
|
|
||||||
{% block form %}
|
{% block form %}
|
||||||
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
|
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
|
||||||
{% load crispy_forms_tags %}
|
{% 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>
|
<label class='control-label'>Parts</label>
|
||||||
<p class='help-block'>Set category for the following parts</p>
|
<p class='help-block'>Set category for the following parts</p>
|
||||||
|
|
||||||
@ -31,28 +13,30 @@
|
|||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Category</th>
|
<th>Category</th>
|
||||||
<th>
|
<th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for part in parts %}
|
{% for part in parts %}
|
||||||
<tr id='part_row_{{ part.id }}'>
|
<tr id='part_row_{{ part.id }}'>
|
||||||
<input type='hidden' name='part_id_{{ part.id }}' value='1'/>
|
<input type='hidden' name='part_id_{{ part.id }}' value='1'/>
|
||||||
<td>
|
<td>
|
||||||
{% include "hover_image.html" with image=part.image hover=False %}
|
{% include "hover_image.html" with image=part.image hover=False %}
|
||||||
{{ part.full_name }}
|
{{ part.full_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ part.description }}
|
{{ part.description }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ part.category.pathstring }}
|
{{ part.category.pathstring }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class='btn btn-default btn-remove' onClick='removeRowFromModalForm()' title='Remove part' type='button'>
|
<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>
|
<span row='part_row_{{ part.id }}' class='glyphicon glyphicon-small glyphicon-remove'></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</form>
|
{% crispy form %}
|
||||||
{% endblock %}
|
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@ -46,6 +46,12 @@ def inventree_commit(*args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def inventree_github(*args, **kwargs):
|
def inventree_github_url(*args, **kwargs):
|
||||||
""" Return URL for InvenTree github site """
|
""" Return URL for InvenTree github site """
|
||||||
return "https://github.com/InvenTree"
|
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)
|
self.assertEqual(len(hash), 7)
|
||||||
|
|
||||||
def test_github(self):
|
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):
|
class PartTest(TestCase):
|
||||||
|
@ -6,6 +6,7 @@ Django views for interacting with Part app
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import transaction
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.shortcuts import HttpResponseRedirect
|
from django.shortcuts import HttpResponseRedirect
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 """
|
""" View for settings the part category for multiple parts at once """
|
||||||
|
|
||||||
ajax_template_name = 'part/set_category.html'
|
ajax_template_name = 'part/set_category.html'
|
||||||
ajax_form_title = 'Set Part Category'
|
ajax_form_title = 'Set Part Category'
|
||||||
|
form_class = part_forms.SetPartCategoryForm
|
||||||
|
|
||||||
category = None
|
category = None
|
||||||
parts = []
|
parts = []
|
||||||
@ -157,7 +159,7 @@ class PartSetCategory(AjaxView):
|
|||||||
else:
|
else:
|
||||||
self.parts = []
|
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):
|
def post(self, request, *args, **kwargs):
|
||||||
""" Respond to a POST request to this view """
|
""" Respond to a POST request to this view """
|
||||||
@ -193,10 +195,14 @@ class PartSetCategory(AjaxView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if valid:
|
if valid:
|
||||||
for part in self.parts:
|
self.set_category()
|
||||||
part.set_category(self.category)
|
|
||||||
|
|
||||||
return self.renderJsonResponse(request, data=data, context=self.get_context_data())
|
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)
|
||||||
|
|
||||||
def get_context_data(self):
|
def get_context_data(self):
|
||||||
""" Return context data for rendering in the form """
|
""" Return context data for rendering in the form """
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
<td colspan="2"></td>
|
<td colspan="2"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
Loading…
Reference in New Issue
Block a user