mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'bootstrap-table'
This commit is contained in:
commit
ffdcfdf51f
@ -34,8 +34,6 @@ apipatterns = [
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# API URL
|
||||
url(r'^api/', include(apipatterns)),
|
||||
# url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
||||
|
||||
url(r'^part/', include(part_urls)),
|
||||
@ -50,6 +48,8 @@ urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
|
||||
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
|
||||
url(r'^api/', include(apipatterns)),
|
||||
]
|
||||
|
||||
# Static file access
|
||||
|
@ -81,14 +81,11 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
|
||||
$("#build-list").footable();
|
||||
|
||||
$("#edit-build").click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
"{% url 'build-edit' build.id %}",
|
||||
|
@ -29,12 +29,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#build-list').footable();
|
||||
|
||||
|
||||
$("#new-build").click(function() {
|
||||
launchModalForm("#modal-form",
|
||||
"{% url 'build-create' %}",
|
||||
|
@ -3,7 +3,21 @@ from rest_framework import serializers
|
||||
from .models import Company
|
||||
|
||||
|
||||
class CompanySerializer(serializers.HyperlinkedModelSerializer):
|
||||
class CompanyBriefSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Company
|
||||
fields = [
|
||||
'pk',
|
||||
'url',
|
||||
'name'
|
||||
]
|
||||
|
||||
class CompanySerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Company
|
||||
|
@ -6,29 +6,7 @@
|
||||
|
||||
<h3>Company Parts</h3>
|
||||
|
||||
<table class='table table-striped' id='part-list' data-sorting='true' data-filtering='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>SKU</th>
|
||||
<th>Part</th>
|
||||
<th>MPN</th>
|
||||
<th>URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for part in company.parts.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'supplier-part-detail' part.id %}">{{ part.SKU }}</a></td>
|
||||
<td>
|
||||
{% if part.part %}
|
||||
<a href="{% url 'part-suppliers' part.part.id %}">{{ part.part.name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ part.manufacturer_string }}</td>
|
||||
<td>{{ part.URL }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<table clas='table table-striped table-condensed' id='part-table'>
|
||||
</table>
|
||||
|
||||
<div class='container-fluid'>
|
||||
@ -40,11 +18,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$("#part-list").footable();
|
||||
|
||||
$("#part-create").click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -56,4 +32,39 @@
|
||||
reload: true,
|
||||
});
|
||||
});
|
||||
|
||||
$("#part-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
supplier: {{ company.id }}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
sortable: true,
|
||||
field: 'part',
|
||||
title: 'Part',
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value.name, value.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'SKU',
|
||||
title: 'SKU',
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'manufacturer',
|
||||
title: 'Manufacturer',
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-part-supplier-list' %}"
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -6,26 +6,7 @@
|
||||
|
||||
<h3>Companies</h3>
|
||||
|
||||
|
||||
<table class='table table-striped' id='company-table' data-sorting='true' data-filtering='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for company in companies %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'company-detail' company.id %}">
|
||||
{{ company.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ company.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<table class='table table-striped' id='company-table'>
|
||||
</table>
|
||||
|
||||
<div class='container-fluid'>
|
||||
@ -37,11 +18,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#company-table').footable();
|
||||
|
||||
$('#new-company').click(function () {
|
||||
launchModalForm('#modal-form',
|
||||
@ -50,4 +29,40 @@
|
||||
follow: true
|
||||
});
|
||||
});
|
||||
|
||||
$("#company-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
columns: [
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Company',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'description',
|
||||
title: 'Description',
|
||||
},
|
||||
{
|
||||
field: 'website',
|
||||
title: 'Website',
|
||||
formatter: function(value, row, index, field) {
|
||||
if (value) {
|
||||
return renderLink(value, value);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-company-list' %}"
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -7,8 +7,11 @@ from rest_framework import generics, permissions
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .models import Part, PartCategory
|
||||
from .serializers import PartSerializer
|
||||
from .models import Part, PartCategory, BomItem
|
||||
from .models import SupplierPart
|
||||
|
||||
from .serializers import PartSerializer, BomItemSerializer
|
||||
from .serializers import SupplierPartSerializer
|
||||
|
||||
from InvenTree.views import TreeSerializer
|
||||
|
||||
@ -49,9 +52,53 @@ class PartList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class BomList(generics.ListAPIView):
|
||||
|
||||
queryset = BomItem.objects.all()
|
||||
serializer_class = BomItemSerializer
|
||||
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticatedOrReadOnly,
|
||||
]
|
||||
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
filters.SearchFilter,
|
||||
filters.OrderingFilter,
|
||||
]
|
||||
|
||||
filter_fields = [
|
||||
'part',
|
||||
'sub_part'
|
||||
]
|
||||
|
||||
|
||||
class SupplierPartList(generics.ListAPIView):
|
||||
|
||||
queryset = SupplierPart.objects.all()
|
||||
serializer_class = SupplierPartSerializer
|
||||
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticatedOrReadOnly,
|
||||
]
|
||||
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
filters.SearchFilter,
|
||||
filters.OrderingFilter,
|
||||
]
|
||||
|
||||
filter_fields = [
|
||||
'part',
|
||||
'supplier'
|
||||
]
|
||||
|
||||
|
||||
part_api_urls = [
|
||||
|
||||
url(r'^tree/?', PartCategoryTree.as_view(), name='api-part-tree'),
|
||||
|
||||
url(r'^supplier/?', SupplierPartList.as_view(), name='api-part-supplier-list'),
|
||||
url(r'^bom/?', BomList.as_view(), name='api-bom-list'),
|
||||
url(r'^.*$', PartList.as_view(), name='api-part-list'),
|
||||
]
|
||||
|
@ -1,6 +1,37 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import Part
|
||||
from .models import Part, PartCategory, BomItem
|
||||
from .models import SupplierPart
|
||||
|
||||
from company.serializers import CompanyBriefSerializer
|
||||
|
||||
class CategoryBriefSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PartCategory
|
||||
fields = [
|
||||
'pk',
|
||||
'name',
|
||||
'description',
|
||||
'pathstring',
|
||||
'url',
|
||||
]
|
||||
|
||||
|
||||
class PartBriefSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Part
|
||||
fields = [
|
||||
'pk',
|
||||
'url',
|
||||
'name',
|
||||
'description',
|
||||
]
|
||||
|
||||
|
||||
class PartSerializer(serializers.ModelSerializer):
|
||||
@ -8,16 +39,19 @@ class PartSerializer(serializers.ModelSerializer):
|
||||
Used when displaying all details of a single component.
|
||||
"""
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
category = CategoryBriefSerializer(many=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Part
|
||||
fields = [
|
||||
'pk',
|
||||
'url', # Link to the part detail page
|
||||
'name',
|
||||
'IPN',
|
||||
'URL', # Link to an external URL (optional)
|
||||
'description',
|
||||
'category',
|
||||
'category_path',
|
||||
'total_stock',
|
||||
'available_stock',
|
||||
'units',
|
||||
@ -26,3 +60,41 @@ class PartSerializer(serializers.ModelSerializer):
|
||||
'trackable',
|
||||
'salable',
|
||||
]
|
||||
|
||||
|
||||
class BomItemSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
part = PartBriefSerializer(many=False, read_only=True)
|
||||
sub_part = PartBriefSerializer(many=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = BomItem
|
||||
fields = [
|
||||
'pk',
|
||||
'url',
|
||||
'part',
|
||||
'sub_part',
|
||||
'quantity'
|
||||
]
|
||||
|
||||
|
||||
class SupplierPartSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
part = PartBriefSerializer(many=False, read_only=True)
|
||||
supplier = CompanyBriefSerializer(many=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = SupplierPart
|
||||
fields = [
|
||||
'pk',
|
||||
'url',
|
||||
'part',
|
||||
'supplier',
|
||||
'SKU',
|
||||
'manufacturer',
|
||||
'MPN',
|
||||
]
|
@ -3,8 +3,6 @@
|
||||
|
||||
{% block css %}
|
||||
|
||||
<link rel='stylesheet' href="{% static 'css/footable.bootstrap.css' %}">
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block details %}
|
||||
@ -13,30 +11,7 @@
|
||||
|
||||
<h3>Bill of Materials</h3>
|
||||
|
||||
<table class="table table-striped" id='bom-table' data-filtering='true' data-sorting='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th>Description</th>
|
||||
<th data-type='number'>Quantity</th>
|
||||
<th data-sortable='false'></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for bom_item in part.bom_items.all %}
|
||||
{% with sub_part=bom_item.sub_part %}
|
||||
<tr>
|
||||
<td><a href="{% url 'part-detail' sub_part.id %}">{{ sub_part.name }}</a></td>
|
||||
<td>{{ sub_part.description }}</td>
|
||||
<td>{{ bom_item.quantity }}</td>
|
||||
<td>
|
||||
<button type='button' url="{% url 'bom-item-edit' bom_item.id %}" class='btn btn-success edit-row-button'>Edit</button>
|
||||
<button type='button' url="{% url 'bom-item-delete' bom_item.id %}" class='btn btn-danger delete-row-button'>Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<table class='table table-striped table-condensed' id='bom-table'>
|
||||
</table>
|
||||
|
||||
<div class='container-fluid'>
|
||||
@ -46,27 +21,32 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#bom-table').footable();
|
||||
|
||||
$('#bom-table').on('click', '.delete-row-button', function () {
|
||||
function reloadBom() {
|
||||
$("#bom-table").bootstrapTable('refresh');
|
||||
}
|
||||
|
||||
$('#bom-table').on('click', '.delete-button', function () {
|
||||
var button = $(this);
|
||||
|
||||
launchDeleteForm("#modal-delete",
|
||||
button.attr('url'),
|
||||
{
|
||||
reload: true
|
||||
success: reloadBom
|
||||
});
|
||||
});
|
||||
|
||||
$('#bom-table').on('click', '.edit-row-button', function () {
|
||||
$("#bom-table").on('click', '.edit-button', function () {
|
||||
var button = $(this);
|
||||
|
||||
launchModalForm("#modal-form",
|
||||
button.attr('url'));
|
||||
button.attr('url'),
|
||||
{
|
||||
success: reloadBom
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -80,4 +60,45 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#bom-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
part: {{ part.id }}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'sub_part',
|
||||
title: 'Part',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value.name, value.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'sub_part.description',
|
||||
title: 'Description',
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: 'Quantity',
|
||||
searchable: false,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
formatter: function(value, row, index, field) {
|
||||
return editButton(row.url + 'edit') + ' ' + deleteButton(row.url + 'delete');
|
||||
}
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-bom-list' %}"
|
||||
});
|
||||
{% endblock %}
|
@ -17,8 +17,8 @@
|
||||
{% endif %}
|
||||
|
||||
{% if category.has_parts %}
|
||||
<h4>Parts</h4>
|
||||
{% include "part/category_parts.html" with parts=category.parts.all %}
|
||||
<table class='table table-striped table-condensed' id='part-table'>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<div class='container-fluid'>
|
||||
@ -29,6 +29,7 @@
|
||||
<button class="btn btn-success" id='create-part'>New Part</button>
|
||||
<button class="btn btn-danger" id='delete-category'>Delete Category</button>
|
||||
|
||||
<button class='btn btn-primary' id='get-rows'>Do thing</button>
|
||||
</div>
|
||||
|
||||
{% include 'modals.html' %}
|
||||
@ -36,11 +37,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>``
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#part-list').footable();
|
||||
|
||||
$("#edit-category").click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -84,4 +83,11 @@
|
||||
follow: true
|
||||
});
|
||||
});
|
||||
|
||||
{% include "part/category_parts.html" with category=category %}
|
||||
|
||||
$("#get-rows").click( function() {
|
||||
alert($("#part-table").bootstrapTable('getSelections'));
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -1,24 +1,63 @@
|
||||
<table class="table table-striped" data-sorting='true' data-filtering='true' id="part-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th>Description</th>
|
||||
<th>Category</th>
|
||||
<th data-type='number'>Stock</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for part in parts %}
|
||||
<tr>
|
||||
<td><a href="{% url 'part-detail' part.id %}">{{ part.name }}</a></td>
|
||||
<td>{{ part.description }}</td>
|
||||
<td>
|
||||
{% if part.category %}
|
||||
<a href="{% url 'category-detail' part.category.id %}">{{ part.category_path }}</a>
|
||||
$("#part-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
sortName: 'description',
|
||||
idField: 'pk',
|
||||
method: 'get',
|
||||
pagination: true,
|
||||
rememberOrder: true,
|
||||
{% if category %}
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
category: {{ category.id }},
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><a href="{% url 'part-stock' part.id %}">{{ part.total_stock }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
columns: [
|
||||
{
|
||||
checkbox: true,
|
||||
title: 'Select',
|
||||
searchable: false,
|
||||
},
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Part',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'description',
|
||||
title: 'Description',
|
||||
},
|
||||
{% if category == None %}
|
||||
{
|
||||
sortable: true,
|
||||
field: 'category',
|
||||
title: 'Category',
|
||||
formatter: function(value, row, index, field) {
|
||||
if (row.category) {
|
||||
return renderLink(row.category.name, row.category.url);
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
{
|
||||
field: 'total_stock',
|
||||
title: 'Stock',
|
||||
searchable: false,
|
||||
sortable: true,
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-part-list' %}",
|
||||
});
|
@ -16,8 +16,7 @@
|
||||
{% include "part/category_subcategories.html" with children=children %}
|
||||
{% endif %}
|
||||
|
||||
<h4>Parts</h4>
|
||||
{% include "part/category_parts.html" with parts=parts %}
|
||||
<table class='table table-striped table-condensed' id='part-table'>
|
||||
|
||||
<div class='container-fluid'>
|
||||
<button type='button' class='btn btn-primary' id='create-cat'>
|
||||
@ -29,11 +28,9 @@
|
||||
|
||||
{% block js_load %}
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#part-list').footable();
|
||||
|
||||
$("#create-cat").click(function() {
|
||||
launchModalForm("#modal-form",
|
||||
@ -73,6 +70,8 @@
|
||||
launchModalForm("#modal-form", "{% url 'part-create' %}");
|
||||
});
|
||||
|
||||
{% include "part/category_parts.html" %}
|
||||
|
||||
loadTree();
|
||||
|
||||
{% endblock %}
|
||||
|
@ -6,50 +6,8 @@
|
||||
|
||||
<h3>Part Stock</h3>
|
||||
|
||||
<table class="table table-striped" id='stock-table' data-sorting='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-sortable='false'>Link</th>
|
||||
{% if part.trackable %}
|
||||
<th>Serial Number</th>
|
||||
{% else %}
|
||||
<th>Quantity</th>
|
||||
{% endif %}
|
||||
<th>Location</th>
|
||||
<th>Supplier part</th>
|
||||
<th>Stocktake</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stock in part.stock_entries %}
|
||||
<tr>
|
||||
<td><a href="{% url 'stock-item-detail' stock.id %}">Click</a></td>
|
||||
<td>
|
||||
{% if part.trackable %}
|
||||
{{ stock.serial }}
|
||||
{% else %}
|
||||
{{ stock.quantity }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if stock.location %}
|
||||
<a href="{% url 'stock-location-detail' stock.location.id %}">{{ stock.location.name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if stock.supplier_part %}
|
||||
<a href="{% url 'supplier-part-detail' stock.supplier_part.id %}">
|
||||
{{ stock.supplier_part.supplier.name }} | {{ stock.supplier_part.SKU }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% if stock.stocktake_date %}{{ stock.stocktake_date }}{% endif %}</td>
|
||||
<td>{{ stock.notes }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table
|
||||
<table class='table table-striped table-condensed' id='stock-table'>
|
||||
</table>
|
||||
|
||||
<div class='container-fluid'>
|
||||
<button class='btn btn-success' id='add-stock-item'>Add new Stock Item</button>
|
||||
@ -59,11 +17,9 @@
|
||||
|
||||
{% block js_load %}
|
||||
{{ block.super }}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
$('#stock-table').footable();
|
||||
|
||||
$('#add-stock-item').click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -75,4 +31,41 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#stock-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
part: {{ part.id }},
|
||||
in_stock: true,
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
checkbox: true,
|
||||
},
|
||||
{
|
||||
field: 'location',
|
||||
title: 'Location',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field){
|
||||
return renderLink(value.pathstring, value.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: 'Stock',
|
||||
searchable: false,
|
||||
sortable: true,
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-stock-list' %}"
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -6,30 +6,14 @@
|
||||
|
||||
<h3>Part Suppliers</h3>
|
||||
|
||||
<table class="table table-striped" id='supplier-table' data-sorting='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>SKU</th>
|
||||
<th>Supplier</th>
|
||||
<th>MPN</th>
|
||||
<th>URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for spart in part.supplier_parts.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'supplier-part-detail' spart.id %}">{{ spart.SKU }}</a></td>
|
||||
<td><a href="{% url 'company-detail' spart.supplier.id %}">{{ spart.supplier.name }}</a></td>
|
||||
<td>{{ spart.manufacturer_string }}</td>
|
||||
<td>
|
||||
{% if spart.URL %}
|
||||
<a href="{{ spart.URL }}">{{ spart.URL }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% if part.supplier_count > 0 %}
|
||||
<p><b>{{ part.name }}</b> is available from {{ part.supplier_count }} suppliers.</p>
|
||||
|
||||
<table class="table table-striped table-condensed" id='supplier-table'>
|
||||
</table>
|
||||
{% else %}
|
||||
<p><b>{{ part.name }}</b> is not available from any suppliers.</p>
|
||||
{% endif %}
|
||||
|
||||
<div class='container-fluid'>
|
||||
<button class="btn btn-success" id='supplier-create'>New Supplier Part</button>
|
||||
@ -39,11 +23,9 @@
|
||||
|
||||
{% block js_load %}
|
||||
{{ block.super }}
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>``
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
$('#supplier-table').footable();
|
||||
|
||||
$('#supplier-create').click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -53,4 +35,39 @@
|
||||
data: {part: {{ part.id }} }
|
||||
});
|
||||
});
|
||||
|
||||
$("#supplier-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
part: {{ part.id }}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
sortable: true,
|
||||
field: 'supplier',
|
||||
title: 'Supplier',
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value.name, value.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'SKU',
|
||||
title: 'SKU',
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'manufacturer',
|
||||
title: 'Manufacturer',
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-part-supplier-list' %}"
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -6,19 +6,58 @@
|
||||
|
||||
<h3>Used In</h3>
|
||||
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th>Uses</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
{% for item in part.used_in.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'part-bom' item.part.id %}">{{ item.part.name }}</a></td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.part.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if part.used_in_count > 0 %}
|
||||
|
||||
<p>
|
||||
<b>{{ part.name }}</b> is used to make {{ part.used_in_count }} other parts.
|
||||
</p>
|
||||
|
||||
<table class="table table-striped table-condensed" id='used-table'>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<p>
|
||||
{{ part.name }} is not used to make any other parts.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
|
||||
$("#used-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
sub_part: {{ part.id }}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'part',
|
||||
title: 'Part',
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value.name, value.url);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'part.description',
|
||||
title: 'Description',
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: 'Uses',
|
||||
}
|
||||
|
||||
],
|
||||
url: "{% url 'api-bom-list' %}"
|
||||
})
|
||||
|
||||
{% endblock %}
|
1
InvenTree/static/css/bootstrap-table.css
vendored
Normal file
1
InvenTree/static/css/bootstrap-table.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,341 +0,0 @@
|
||||
/*
|
||||
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
|
||||
* @version 3.1.5
|
||||
* @link http://fooplugins.com
|
||||
* @copyright Steven Usher & Brad Vincent 2015
|
||||
* @license Released under the GPLv3 license.
|
||||
*/
|
||||
table.footable,
|
||||
table.footable-details {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.footable-details {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table.footable-hide-fouc {
|
||||
display: none;
|
||||
}
|
||||
table > tbody > tr > td > span.footable-toggle {
|
||||
margin-right: 8px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
table > tbody > tr > td > span.footable-toggle.last-column {
|
||||
margin-left: 8px;
|
||||
float: right;
|
||||
}
|
||||
table.table-condensed > tbody > tr > td > span.footable-toggle {
|
||||
margin-right: 5px;
|
||||
}
|
||||
table.footable-details > tbody > tr > th:nth-child(1) {
|
||||
min-width: 40px;
|
||||
width: 120px;
|
||||
}
|
||||
table.footable-details > tbody > tr > td:nth-child(2) {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
table.footable-details > thead > tr:first-child > th,
|
||||
table.footable-details > thead > tr:first-child > td,
|
||||
table.footable-details > tbody > tr:first-child > th,
|
||||
table.footable-details > tbody > tr:first-child > td,
|
||||
table.footable-details > tfoot > tr:first-child > th,
|
||||
table.footable-details > tfoot > tr:first-child > td {
|
||||
border-top-width: 0;
|
||||
}
|
||||
table.footable-details.table-bordered > thead > tr:first-child > th,
|
||||
table.footable-details.table-bordered > thead > tr:first-child > td,
|
||||
table.footable-details.table-bordered > tbody > tr:first-child > th,
|
||||
table.footable-details.table-bordered > tbody > tr:first-child > td,
|
||||
table.footable-details.table-bordered > tfoot > tr:first-child > th,
|
||||
table.footable-details.table-bordered > tfoot > tr:first-child > td {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
div.footable-loader {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
div.footable-loader > span.fooicon {
|
||||
display: inline-block;
|
||||
opacity: 0.3;
|
||||
font-size: 30px;
|
||||
line-height: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-top: -16px;
|
||||
margin-left: -16px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-animation: fooicon-spin-r 2s infinite linear;
|
||||
animation: fooicon-spin-r 2s infinite linear;
|
||||
}
|
||||
table.footable > tbody > tr.footable-empty > td {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 30px;
|
||||
}
|
||||
table.footable > tbody > tr > td,
|
||||
table.footable > tbody > tr > th {
|
||||
display: none;
|
||||
}
|
||||
table.footable > tbody > tr.footable-empty > td,
|
||||
table.footable > tbody > tr.footable-empty > th,
|
||||
table.footable > tbody > tr.footable-detail-row > td,
|
||||
table.footable > tbody > tr.footable-detail-row > th {
|
||||
display: table-cell;
|
||||
}
|
||||
@-webkit-keyframes fooicon-spin-r {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fooicon-spin-r {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
.fooicon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
display: inline-block;
|
||||
font-family: 'Glyphicons Halflings' !important;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.fooicon:before,
|
||||
.fooicon:after {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.fooicon-loader:before {
|
||||
content: "\e030";
|
||||
}
|
||||
.fooicon-plus:before {
|
||||
content: "\2b";
|
||||
}
|
||||
.fooicon-minus:before {
|
||||
content: "\2212";
|
||||
}
|
||||
.fooicon-search:before {
|
||||
content: "\e003";
|
||||
}
|
||||
.fooicon-remove:before {
|
||||
content: "\e014";
|
||||
}
|
||||
.fooicon-sort:before {
|
||||
content: "\e150";
|
||||
}
|
||||
.fooicon-sort-asc:before {
|
||||
content: "\e155";
|
||||
}
|
||||
.fooicon-sort-desc:before {
|
||||
content: "\e156";
|
||||
}
|
||||
.fooicon-pencil:before {
|
||||
content: "\270f";
|
||||
}
|
||||
.fooicon-trash:before {
|
||||
content: "\e020";
|
||||
}
|
||||
.fooicon-eye-close:before {
|
||||
content: "\e106";
|
||||
}
|
||||
.fooicon-flash:before {
|
||||
content: "\e162";
|
||||
}
|
||||
.fooicon-cog:before {
|
||||
content: "\e019";
|
||||
}
|
||||
.fooicon-stats:before {
|
||||
content: "\e185";
|
||||
}
|
||||
|
||||
table.footable > thead > tr.footable-filtering > th {
|
||||
border-bottom-width: 1px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-right,
|
||||
table.footable > thead > tr.footable-filtering > th,
|
||||
table.footable.footable-filtering-right > thead > tr.footable-filtering > th {
|
||||
text-align: right;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-left,
|
||||
table.footable.footable-filtering-left > thead > tr.footable-filtering > th {
|
||||
text-align: left;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-center,
|
||||
table.footable.footable-filtering-center > thead > tr.footable-filtering > th {
|
||||
text-align: center;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group+div.form-group {
|
||||
margin-top: 5px;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
||||
width: 100%;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox,
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox {
|
||||
margin: 0;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox > label,
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox > label {
|
||||
display: block;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox input[type="checkbox"],
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox input[type="checkbox"] {
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
||||
width: auto;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group+div.form-group {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
table.footable > thead > tr > td.footable-sortable,
|
||||
table.footable > thead > tr > th.footable-sortable,
|
||||
table.footable > tbody > tr > td.footable-sortable,
|
||||
table.footable > tbody > tr > th.footable-sortable,
|
||||
table.footable > tfoot > tr > td.footable-sortable,
|
||||
table.footable > tfoot > tr > th.footable-sortable {
|
||||
position: relative;
|
||||
padding-right: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
td.footable-sortable > span.fooicon,
|
||||
th.footable-sortable > span.fooicon {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in;
|
||||
}
|
||||
td.footable-sortable:hover > span.fooicon,
|
||||
th.footable-sortable:hover > span.fooicon {
|
||||
opacity: 1;
|
||||
}
|
||||
td.footable-sortable.footable-asc > span.fooicon,
|
||||
th.footable-sortable.footable-asc > span.fooicon,
|
||||
td.footable-sortable.footable-desc > span.fooicon,
|
||||
th.footable-sortable.footable-desc > span.fooicon {
|
||||
opacity: 1;
|
||||
}
|
||||
/* hides the sort icons when sorting is not allowed */
|
||||
table.footable-sorting-disabled td.footable-sortable.footable-asc > span.fooicon,
|
||||
table.footable-sorting-disabled td.footable-sortable.footable-desc > span.fooicon,
|
||||
table.footable-sorting-disabled td.footable-sortable:hover > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable.footable-asc > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable.footable-desc > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable:hover > span.fooicon {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.footable-paging-external ul.pagination,
|
||||
table.footable > tfoot > tr.footable-paging > td > ul.pagination {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
.footable-paging-external span.label,
|
||||
table.footable > tfoot > tr.footable-paging > td > span.label {
|
||||
display: inline-block;
|
||||
margin: 0 0 10px 0;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
.footable-paging-external.footable-paging-center,
|
||||
table.footable > tfoot > tr.footable-paging > td,
|
||||
table.footable-paging-center > tfoot > tr.footable-paging > td {
|
||||
text-align: center;
|
||||
}
|
||||
.footable-paging-external.footable-paging-left,
|
||||
table.footable-paging-left > tfoot > tr.footable-paging > td {
|
||||
text-align: left;
|
||||
}
|
||||
.footable-paging-external.footable-paging-right,
|
||||
table.footable-paging-right > tfoot > tr.footable-paging > td {
|
||||
text-align: right;
|
||||
}
|
||||
ul.pagination > li.footable-page {
|
||||
display: none;
|
||||
}
|
||||
ul.pagination > li.footable-page.visible {
|
||||
display: inline;
|
||||
}
|
||||
td.footable-editing {
|
||||
width: 90px;
|
||||
max-width: 90px;
|
||||
}
|
||||
table.footable-editing-no-edit td.footable-editing,
|
||||
table.footable-editing-no-delete td.footable-editing,
|
||||
table.footable-editing-no-view td.footable-editing {
|
||||
width: 70px;
|
||||
max-width: 70px;
|
||||
}
|
||||
table.footable-editing-no-edit.footable-editing-no-delete td.footable-editing,
|
||||
table.footable-editing-no-edit.footable-editing-no-view td.footable-editing,
|
||||
table.footable-editing-no-delete.footable-editing-no-view td.footable-editing {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
|
||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view th.footable-editing {
|
||||
width: 0;
|
||||
max-width: 0;
|
||||
display: none !important;
|
||||
}
|
||||
table.footable-editing-right td.footable-editing,
|
||||
table.footable-editing-right tr.footable-editing {
|
||||
text-align: right;
|
||||
}
|
||||
table.footable-editing-left td.footable-editing,
|
||||
table.footable-editing-left tr.footable-editing {
|
||||
text-align: left;
|
||||
}
|
||||
table.footable-editing button.footable-add,
|
||||
table.footable-editing button.footable-hide,
|
||||
table.footable-editing-show button.footable-show,
|
||||
table.footable-editing.footable-editing-always-show button.footable-show,
|
||||
table.footable-editing.footable-editing-always-show button.footable-hide,
|
||||
table.footable-editing.footable-editing-always-show.footable-editing-no-add tr.footable-editing {
|
||||
display: none;
|
||||
}
|
||||
table.footable-editing.footable-editing-show button.footable-add,
|
||||
table.footable-editing.footable-editing-show button.footable-hide,
|
||||
table.footable-editing.footable-editing-always-show button.footable-add {
|
||||
display: inline-block;
|
||||
}
|
7
InvenTree/static/script/bootstrap-table-en-US.min.js
vendored
Normal file
7
InvenTree/static/script/bootstrap-table-en-US.min.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* bootstrap-table - v1.12.1 - 2018-03-12
|
||||
* https://github.com/wenzhixin/bootstrap-table
|
||||
* Copyright (c) 2018 zhixin wen
|
||||
* Licensed MIT License
|
||||
*/
|
||||
!function(a){"use strict";a.fn.bootstrapTable.locales["en-US"]={formatLoadingMessage:function(){return"Loading, please wait..."},formatRecordsPerPage:function(a){return a+" rows per page"},formatShowingRows:function(a,b,c){return"Showing "+a+" to "+b+" of "+c+" rows"},formatSearch:function(){return"Search"},formatNoMatches:function(){return"No matching records found"},formatPaginationSwitch:function(){return"Hide/Show pagination"},formatRefresh:function(){return"Refresh"},formatToggle:function(){return"Toggle"},formatColumns:function(){return"Columns"},formatAllRows:function(){return"All"},formatExport:function(){return"Export data"},formatClearFilters:function(){return"Clear filters"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["en-US"])}(jQuery);
|
9
InvenTree/static/script/bootstrap-table.min.js
vendored
Normal file
9
InvenTree/static/script/bootstrap-table.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
22
InvenTree/static/script/tables.js
Normal file
22
InvenTree/static/script/tables.js
Normal file
@ -0,0 +1,22 @@
|
||||
function editButton(url, text='Edit') {
|
||||
return "<button class='btn btn-success edit-button' type='button' url='" + url + "'>" + text + "</button>";
|
||||
}
|
||||
|
||||
function deleteButton(url, text='Delete') {
|
||||
return "<button class='btn btn-danger delete-button' type='button' url='" + url + "'>" + text + "</button>";
|
||||
}
|
||||
|
||||
function renderLink(text, url) {
|
||||
if (text && url) {
|
||||
return '<a href="' + url + '">' + text + '</a>';
|
||||
}
|
||||
else if (text) {
|
||||
return text;
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,10 +2,30 @@ from rest_framework import serializers
|
||||
|
||||
from .models import StockItem, StockLocation
|
||||
|
||||
from part.serializers import PartBriefSerializer
|
||||
|
||||
|
||||
class LocationBriefSerializer(serializers.ModelSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = StockLocation
|
||||
fields = [
|
||||
'pk',
|
||||
'name',
|
||||
'pathstring',
|
||||
'url',
|
||||
]
|
||||
|
||||
|
||||
class StockItemSerializer(serializers.ModelSerializer):
|
||||
""" Serializer for a StockItem
|
||||
"""
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
|
||||
part = PartBriefSerializer(many=False, read_only=True)
|
||||
location = LocationBriefSerializer(many=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = StockItem
|
||||
@ -16,17 +36,17 @@ class StockItemSerializer(serializers.ModelSerializer):
|
||||
'supplier_part',
|
||||
'location',
|
||||
'in_stock',
|
||||
'belongs_to',
|
||||
'customer',
|
||||
#'belongs_to',
|
||||
#'customer',
|
||||
'quantity',
|
||||
'serial',
|
||||
'batch',
|
||||
'status',
|
||||
'notes',
|
||||
'updated',
|
||||
'stocktake_date',
|
||||
'stocktake_user',
|
||||
'review_needed',
|
||||
#'updated',
|
||||
#'stocktake_date',
|
||||
#'stocktake_user',
|
||||
#'review_needed',
|
||||
]
|
||||
|
||||
""" These fields are read-only in this context.
|
||||
|
@ -9,35 +9,7 @@
|
||||
{% include "stock/location_list.html" with locations=locations %}
|
||||
{% endif %}
|
||||
|
||||
<table class="table table-striped" id='stock-table' data-filtering='true' data-sorting='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th>Location</th>
|
||||
<th data-type='number'>Stock</th>
|
||||
<th>Status</th>
|
||||
<th data-type='date'>Stocktake</th>
|
||||
<th data-sortable='false'></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'part-stock' item.part.id %}">{{ item.part.name }}</a></td>
|
||||
<td>
|
||||
{% if item.location %}
|
||||
<a href="{% url 'stock-location-detail' item.location.id %}">
|
||||
{{ item.location.pathstring }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.get_status_display }}</td>
|
||||
<td>{{ item.stocktake_date }}</td>
|
||||
<td><a href="{% url 'stock-item-detail' item.id %}">Click</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<table class="table table-striped" id='stock-table'>
|
||||
</table>
|
||||
|
||||
<div class='container-fluid'>
|
||||
@ -49,12 +21,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#stock-table').footable();
|
||||
|
||||
$('#location-create').click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -63,4 +32,7 @@
|
||||
follow: true
|
||||
});
|
||||
});
|
||||
|
||||
{% include "stock/stock_table.html" %}
|
||||
|
||||
{% endblock %}
|
@ -114,8 +114,6 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
|
@ -12,8 +12,10 @@
|
||||
{% include "stock/location_list.html" with locations=location.children %}
|
||||
{% endif %}
|
||||
|
||||
<h4>Stock Items</h4>
|
||||
{% include "stock/stock_table.html" with items=location.items %}
|
||||
{% if location.has_items %}
|
||||
<table class='table table-striped table-condensed' id='stock-table'>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<div class='container-fluid'>
|
||||
<button class='btn btn-success' id='location-create'>New Stock Location</button>
|
||||
@ -28,12 +30,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block js_ready %}
|
||||
$('#stock-table').footable();
|
||||
|
||||
$('#location-create').click(function () {
|
||||
launchModalForm("#modal-form",
|
||||
@ -72,4 +71,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
{% include 'stock/stock_table.html' with location=location %}
|
||||
|
||||
{% endblock %}
|
||||
|
@ -1,22 +1,60 @@
|
||||
<table class="table table-striped" id='stock-table' data-filtering='true' data-sorting='true'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th data-type='number'>Stock</th>
|
||||
<th>Status</th>
|
||||
<th>Stocktake</th>
|
||||
<th data-sortable='false'></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'part-stock' item.part.id %}">{{ item.part.name }}</a></td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.get_status_display }}</td>
|
||||
<td>{{ item.stocktake_date }}</td>
|
||||
<td><a href="{% url 'stock-item-detail' item.id %}">Click</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
$("#stock-table").bootstrapTable({
|
||||
sortable: true,
|
||||
search: true,
|
||||
method: 'get',
|
||||
pagination: true,
|
||||
rememberOrder: true,
|
||||
{% if location %}
|
||||
queryParams: function(p) {
|
||||
return {
|
||||
location: {{ location.id }}
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
columns: [
|
||||
{
|
||||
checkbox: true,
|
||||
title: 'Select',
|
||||
searchable: false,
|
||||
},
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'part.name',
|
||||
title: 'Part',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.part.url);
|
||||
}
|
||||
},
|
||||
{% if location == None %}
|
||||
{
|
||||
field: 'location',
|
||||
title: 'Location',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
if (row.location) {
|
||||
return renderLink(row.location.name, row.location.url);
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
{
|
||||
field: 'quantity',
|
||||
title: 'Stock',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Status',
|
||||
sortable: true,
|
||||
}
|
||||
],
|
||||
url: "{% url 'api-stock-list' %}",
|
||||
});
|
@ -10,8 +10,9 @@
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
|
||||
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
@ -47,6 +48,12 @@ InvenTree
|
||||
<script type="text/javascript" src="{% static 'script/bootstrap.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/bootstrap-treeview.js' %}"></script>
|
||||
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/bootstrap-table.min.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/bootstrap-table-en-US.min.js' %}"></script>
|
||||
|
||||
<script type='text/javascript' src="{% static 'script/tables.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/trees.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/sidenav.js' %}"></script>
|
||||
<script type='text/javascript' src="{% static 'script/notification.js' %}"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user