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
bbb6319792
@ -807,7 +807,19 @@ function launchModalForm(url, options = {}) {
|
||||
}
|
||||
},
|
||||
error: function (xhr, ajaxOptions, thrownError) {
|
||||
|
||||
$(modal).modal('hide');
|
||||
|
||||
// Permission denied!
|
||||
if (xhr.status == 403) {
|
||||
showAlertDialog(
|
||||
"Permission Denied",
|
||||
"You do not have the required permissions to access this function"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
showAlertDialog('Error requesting form data', renderErrorMessage(xhr));
|
||||
}
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import django
|
||||
|
||||
import common.models
|
||||
|
||||
INVENTREE_SW_VERSION = "0.1.3 pre"
|
||||
INVENTREE_SW_VERSION = "0.1.4 pre"
|
||||
|
||||
|
||||
def inventreeInstanceName():
|
||||
|
@ -13,6 +13,8 @@ from django.template.loader import render_to_string
|
||||
from django.http import JsonResponse, HttpResponseRedirect
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
|
||||
from django.views import View
|
||||
from django.views.generic import UpdateView, CreateView, FormView
|
||||
from django.views.generic.base import TemplateView
|
||||
@ -105,12 +107,32 @@ class TreeSerializer(views.APIView):
|
||||
return JsonResponse(response, safe=False)
|
||||
|
||||
|
||||
class AjaxMixin(object):
|
||||
class AjaxMixin(PermissionRequiredMixin):
|
||||
""" AjaxMixin provides basic functionality for rendering a Django form to JSON.
|
||||
Handles jsonResponse rendering, and adds extra data for the modal forms to process
|
||||
on the client side.
|
||||
|
||||
Any view which inherits the AjaxMixin will need
|
||||
correct permissions set using the 'permission_required' attribute
|
||||
|
||||
"""
|
||||
|
||||
# By default, allow *any* permissions
|
||||
permission_required = '*'
|
||||
|
||||
def has_permission(self):
|
||||
"""
|
||||
Override the default behaviour of has_permission from PermissionRequiredMixin.
|
||||
|
||||
Basically, if permission_required attribute = '*',
|
||||
no permissions are actually required!
|
||||
"""
|
||||
|
||||
if self.permission_required == '*':
|
||||
return True
|
||||
else:
|
||||
return super().has_permission()
|
||||
|
||||
# By default, point to the modal_form template
|
||||
# (this can be overridden by a child class)
|
||||
ajax_template_name = 'modal_form.html'
|
||||
|
@ -20,6 +20,12 @@ class BuildAdmin(ImportExportModelAdmin):
|
||||
'notes',
|
||||
)
|
||||
|
||||
search_fields = [
|
||||
'title',
|
||||
'part__name',
|
||||
'part__description',
|
||||
]
|
||||
|
||||
|
||||
class BuildItemAdmin(admin.ModelAdmin):
|
||||
|
||||
|
@ -33,7 +33,12 @@ src="{% static 'img/blank_image.png' %}"
|
||||
{% block page_data %}
|
||||
<h3>{% trans "Build" %} {% build_status_label build.status large=True %}</h3>
|
||||
<hr>
|
||||
<h4>{{ build.quantity }} x {{ build.part.full_name }}</h4>
|
||||
<h4>
|
||||
{{ build.quantity }} x {{ build.part.full_name }}
|
||||
{% if user.is_staff and perms.build.change_build %}
|
||||
<a href="{% url 'admin:build_build_change' build.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<div class='btn-row'>
|
||||
<div class='btn-group action-buttons'>
|
||||
<button type='button' class='btn btn-default' id='build-edit' title='Edit Build'>
|
||||
|
@ -32,6 +32,11 @@ class CompanyAdmin(ImportExportModelAdmin):
|
||||
|
||||
list_display = ('name', 'website', 'contact')
|
||||
|
||||
search_fields = [
|
||||
'name',
|
||||
'description',
|
||||
]
|
||||
|
||||
|
||||
class SupplierPartResource(ModelResource):
|
||||
""" Class for managing SupplierPart data import/export """
|
||||
@ -57,6 +62,13 @@ class SupplierPartAdmin(ImportExportModelAdmin):
|
||||
|
||||
list_display = ('part', 'supplier', 'SKU')
|
||||
|
||||
search_fields = [
|
||||
'company__name',
|
||||
'part__name',
|
||||
'MPN',
|
||||
'SKU',
|
||||
]
|
||||
|
||||
|
||||
class SupplierPriceBreakResource(ModelResource):
|
||||
""" Class for managing SupplierPriceBreak data import/export """
|
||||
|
@ -21,7 +21,12 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
|
||||
{% block page_data %}
|
||||
<h3>{% trans "Company" %}</h3>
|
||||
<hr>
|
||||
<h4>{{ company.name }}</h4>
|
||||
<h4>
|
||||
{{ company.name }}
|
||||
{% if user.is_staff and perms.company.change_company %}
|
||||
<a href="{% url 'admin:company_company_change' company.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<p>{{ company.description }}</p>
|
||||
<div class='btn-group action-buttons'>
|
||||
{% if company.is_supplier %}
|
||||
|
@ -23,6 +23,12 @@ class PurchaseOrderAdmin(ImportExportModelAdmin):
|
||||
'creation_date'
|
||||
)
|
||||
|
||||
search_fields = [
|
||||
'reference',
|
||||
'supplier__name',
|
||||
'description',
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderAdmin(ImportExportModelAdmin):
|
||||
|
||||
@ -34,6 +40,12 @@ class SalesOrderAdmin(ImportExportModelAdmin):
|
||||
'creation_date',
|
||||
)
|
||||
|
||||
search_fields = [
|
||||
'reference',
|
||||
'customer__name',
|
||||
'description',
|
||||
]
|
||||
|
||||
|
||||
class POLineItemResource(ModelResource):
|
||||
""" Class for managing import / export of POLineItem data """
|
||||
|
@ -22,7 +22,12 @@ src="{% static 'img/blank_image.png' %}"
|
||||
{% block page_data %}
|
||||
<h3>{% trans "Purchase Order" %} {% purchase_order_status_label order.status large=True %}</h3>
|
||||
<hr>
|
||||
<h4>{{ order }}</h4>
|
||||
<h4>
|
||||
{{ order }}
|
||||
{% if user.is_staff and perms.order.change_purchaseorder %}
|
||||
<a href="{% url 'admin:order_purchaseorder_change' order.pk %}"><span title='{% trans "Admin view" %}' class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<p>{{ order.description }}</p>
|
||||
<p>
|
||||
<div class='btn-row'>
|
||||
|
@ -32,7 +32,12 @@ src="{% static 'img/blank_image.png' %}"
|
||||
|
||||
<h3>{% trans "Sales Order" %} {% sales_order_status_label order.status large=True %}</h3>
|
||||
<hr>
|
||||
<h4>{{ order }}</h4>
|
||||
<h4>
|
||||
{{ order }}
|
||||
{% if user.is_staff and perms.order.change_salesorder %}
|
||||
<a href="{% url 'admin:order_salesorder_change' order.pk %}"><span title='{% trans "Admin view" %}' class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<p>{{ order.description }}</p>
|
||||
<div class='btn-row'>
|
||||
<div class='btn-group action-buttons'>
|
||||
|
@ -430,6 +430,17 @@ class PartList(generics.ListCreateAPIView):
|
||||
except (ValueError, Part.DoesNotExist):
|
||||
pass
|
||||
|
||||
# Filter by whether the part has an IPN (internal part number) defined
|
||||
has_ipn = params.get('has_ipn', None)
|
||||
|
||||
if has_ipn is not None:
|
||||
has_ipn = str2bool(has_ipn)
|
||||
|
||||
if has_ipn:
|
||||
queryset = queryset.exclude(IPN='')
|
||||
else:
|
||||
queryset = queryset.filter(IPN='')
|
||||
|
||||
# Filter by whether the BOM has been validated (or not)
|
||||
bom_valid = params.get('bom_valid', None)
|
||||
|
||||
|
@ -7,7 +7,12 @@
|
||||
<div class='row'>
|
||||
<div class='col-sm-6'>
|
||||
{% if category %}
|
||||
<h3>{{ category.name }}</h3>
|
||||
<h3>
|
||||
{{ category.name }}
|
||||
{% if user.is_staff and perms.part.change_partcategory %}
|
||||
<a href="{% url 'admin:part_partcategory_change' category.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p>{{ category.description }}</p>
|
||||
{% else %}
|
||||
<h3>{% trans "Part Categories" %}</h3>
|
||||
@ -109,11 +114,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='filter-list' id='filter-list-parts'>
|
||||
<!-- Empty div -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class='table table-striped table-condensed' data-toolbar='#button-toolbar' id='part-table'>
|
||||
</table>
|
||||
|
@ -28,6 +28,9 @@
|
||||
<div class="media-body">
|
||||
<h3>
|
||||
{{ part.full_name }}
|
||||
{% if user.is_staff and perms.part.change_part %}
|
||||
<a href="{% url 'admin:part_part_change' part.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
{% if not part.active %}
|
||||
<div class='label label-large label-large-red'>
|
||||
{% trans 'Inactive' %}
|
||||
|
@ -117,6 +117,14 @@ class StockItemAdmin(ImportExportModelAdmin):
|
||||
|
||||
list_display = ('part', 'quantity', 'location', 'status', 'updated')
|
||||
|
||||
# A list of search fields which can be used for lookup on matching 'autocomplete' fields
|
||||
search_fields = [
|
||||
'part__name',
|
||||
'part__description',
|
||||
'serial',
|
||||
'batch',
|
||||
]
|
||||
|
||||
|
||||
class StockAttachmentAdmin(admin.ModelAdmin):
|
||||
|
||||
|
@ -65,6 +65,9 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
||||
{% else %}
|
||||
<a href='{% url "part-detail" item.part.pk %}'>{{ item.part.full_name }}</a> × {% decimal item.quantity %}
|
||||
{% endif %}
|
||||
{% if user.is_staff and perms.stock.change_stockitem %}
|
||||
<a href="{% url 'admin:stock_stockitem_change' item.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
|
||||
<div class='btn-group' role='group'>
|
||||
@ -107,6 +110,11 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
||||
{% if item.customer %}
|
||||
<li><a href='#' id='stock-return-from-customer' title='{% trans "Return to stock" %}'><span class='fas fa-undo'></span> {% trans "Return to stock" %}</a></li>
|
||||
{% endif %}
|
||||
{% if item.belongs_to %}
|
||||
<li>
|
||||
<a href='#' id='stock-uninstall' title='{% trans "Uninstall stock item" %}'><span class='fas fa-unlink'></span> {% trans "Uninstall" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Edit stock item -->
|
||||
@ -165,8 +173,12 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
||||
{% if item.belongs_to %}
|
||||
<tr>
|
||||
<td><span class='fas fa-box'></span></td>
|
||||
<td>{% trans "Belongs To" %}</td>
|
||||
<td><a href="{% url 'stock-item-detail' item.belongs_to.id %}">{{ item.belongs_to }}</a></td>
|
||||
<td>
|
||||
{% trans "Installed In" %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'stock-item-detail' item.belongs_to.id %}">{{ item.belongs_to }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% elif item.sales_order %}
|
||||
<tr>
|
||||
@ -301,6 +313,19 @@ $("#stock-serialize").click(function() {
|
||||
);
|
||||
});
|
||||
|
||||
$('#stock-uninstall').click(function() {
|
||||
|
||||
launchModalForm(
|
||||
"{% url 'stock-item-uninstall' %}",
|
||||
{
|
||||
data: {
|
||||
'items[]': [{{ item.pk}}],
|
||||
},
|
||||
reload: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#stock-test-report").click(function() {
|
||||
launchModalForm(
|
||||
"{% url 'stock-item-test-report-select' item.id %}",
|
||||
|
@ -128,7 +128,7 @@ $('#installed-table').inventreeTable({
|
||||
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-uninstall', pk, '{% trans "Uninstall item" %}');
|
||||
html += makeIconButton('fa-unlink', 'button-uninstall', pk, '{% trans "Uninstall item" %}');
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
|
@ -6,7 +6,12 @@
|
||||
<div class='row'>
|
||||
<div class='col-sm-6'>
|
||||
{% if location %}
|
||||
<h3>{{ location.name }}</h3>
|
||||
<h3>
|
||||
{{ location.name }}
|
||||
{% if user.is_staff and perms.stock.change_stocklocation %}
|
||||
<a href="{% url 'admin:stock_stocklocation_change' location.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p>{{ location.description }}</p>
|
||||
{% else %}
|
||||
<h3>{% trans "Stock" %}</h3>
|
||||
|
@ -18,8 +18,10 @@ InvenTree | {% trans "Search Results" %}
|
||||
<br><br>
|
||||
<hr>
|
||||
|
||||
{% if query %}
|
||||
|
||||
<div id='no-search-results'>
|
||||
<h4><i>{% trans "No results found" %}</i></h4>
|
||||
<h4><i>{% trans "No results found for " %}'{{ query }}'</i></h4>
|
||||
</div>
|
||||
|
||||
{% include "InvenTree/search_part_category.html" with collapse_id="categories" %}
|
||||
@ -34,6 +36,14 @@ InvenTree | {% trans "Search Results" %}
|
||||
|
||||
{% include "InvenTree/search_stock_items.html" with collapse_id="stock" %}
|
||||
|
||||
{% else %}
|
||||
|
||||
<div id='empty-search-query'>
|
||||
<h4><i>{% trans "Enter a search query" %}</i></h4>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js_load %}
|
||||
|
@ -173,6 +173,11 @@ function getAvailableTableFilters(tableKey) {
|
||||
title: '{% trans "Include subcategories" %}',
|
||||
description: '{% trans "Include parts in subcategories" %}',
|
||||
},
|
||||
has_ipn: {
|
||||
type: 'bool',
|
||||
title: '{% trans "Has IPN" %}',
|
||||
description: '{% trans "Part has internal part number" %}',
|
||||
},
|
||||
active: {
|
||||
type: 'bool',
|
||||
title: '{% trans "Active" %}',
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
<div id='button-toolbar'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
<div class='btn-group'>
|
||||
<button class='btn btn-default' id='stock-export' title='{% trans "Export Stock Information" %}'>{% trans "Export" %}</button>
|
||||
{% if read_only %}
|
||||
{% else %}
|
||||
@ -18,6 +19,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class='filter-list' id='filter-list-stock'>
|
||||
<!-- An empty div in which the filter list will be constructed -->
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user