merge master in

This commit is contained in:
Matthias 2021-12-02 09:17:57 +01:00
commit 0379498ee3
No known key found for this signature in database
GPG Key ID: F50EF5741D33E076
8 changed files with 140 additions and 18 deletions

View File

@ -781,6 +781,7 @@ input[type="submit"] {
.btn-small { .btn-small {
padding: 3px; padding: 3px;
padding-left: 5px; padding-left: 5px;
padding-right: 5px;
} }
.btn-remove { .btn-remove {

View File

@ -12,11 +12,15 @@ import common.models
INVENTREE_SW_VERSION = "0.6.0 dev" INVENTREE_SW_VERSION = "0.6.0 dev"
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 18 INVENTREE_API_VERSION = 19
""" """
Increment this API version number whenever there is a significant change to the API that any clients need to know about Increment this API version number whenever there is a significant change to the API that any clients need to know about
v19 -> 2021-12-02
- Adds the ability to filter the StockItem API by "part_tree"
- Returns only stock items which match a particular part.tree_id field
v18 -> 2021-11-15 v18 -> 2021-11-15
- Adds the ability to filter BomItem API by "uses" field - Adds the ability to filter BomItem API by "uses" field
- This returns a list of all BomItems which "use" the specified part - This returns a list of all BomItems which "use" the specified part

View File

@ -1075,6 +1075,7 @@ class PartList(generics.ListCreateAPIView):
'revision', 'revision',
'keywords', 'keywords',
'category__name', 'category__name',
'manufacturer_parts__MPN',
] ]

View File

@ -322,7 +322,14 @@
<tr> <tr>
<td><span class='fas fa-hashtag'></span></td> <td><span class='fas fa-hashtag'></span></td>
<td>{% trans "Latest Serial Number" %}</td> <td>{% trans "Latest Serial Number" %}</td>
<td>{{ part.getLatestSerialNumber }}{% include "clip.html"%}</td> <td>
{{ part.getLatestSerialNumber }}
<div class='btn-group float-right' role='group'>
<a class='btn btn-small btn-outline-secondary text-sm' href='#' id='serial-number-search' title='{% trans "Search for serial number" %}'>
<span class='fas fa-search'></span>
</a>
</div>
</td>
</tr> </tr>
{% endif %} {% endif %}
{% if part.default_location %} {% if part.default_location %}
@ -577,4 +584,8 @@
$('#collapse-part-details').collapse('show'); $('#collapse-part-details').collapse('show');
} }
$('#serial-number-search').click(function() {
findStockItemBySerialNumber({{ part.pk }});
});
{% endblock %} {% endblock %}

View File

@ -313,7 +313,7 @@ class StockFilter(rest_filters.FilterSet):
# Serial number filtering # Serial number filtering
serial_gte = rest_filters.NumberFilter(label='Serial number GTE', field_name='serial', lookup_expr='gte') serial_gte = rest_filters.NumberFilter(label='Serial number GTE', field_name='serial', lookup_expr='gte')
serial_lte = rest_filters.NumberFilter(label='Serial number LTE', field_name='serial', lookup_expr='lte') serial_lte = rest_filters.NumberFilter(label='Serial number LTE', field_name='serial', lookup_expr='lte')
serial = rest_filters.NumberFilter(label='Serial number', field_name='serial', lookup_expr='exact') serial = rest_filters.CharFilter(label='Serial number', field_name='serial', lookup_expr='exact')
serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized') serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized')
@ -703,6 +703,18 @@ class StockList(generics.ListCreateAPIView):
except (ValueError, StockItem.DoesNotExist): except (ValueError, StockItem.DoesNotExist):
pass pass
# Filter by "part tree" - only allow parts within a given variant tree
part_tree = params.get('part_tree', None)
if part_tree is not None:
try:
part = Part.objects.get(pk=part_tree)
if part.tree_id is not None:
queryset = queryset.filter(part__tree_id=part.tree_id)
except:
pass
# Filter by 'allocated' parts? # Filter by 'allocated' parts?
allocated = params.get('allocated', None) allocated = params.get('allocated', None)

View File

@ -148,17 +148,24 @@
<td><span class='fas fa-hashtag'></span></td> <td><span class='fas fa-hashtag'></span></td>
<td>{% trans "Serial Number" %}</td> <td>{% trans "Serial Number" %}</td>
<td> <td>
{% if previous %} {{ item.serial }}
<a class="btn btn-outline-secondary" aria-label="{% trans 'previous page' %}" href="{% url request.resolver_match.url_name previous.id %}"> <div class='btn-group float-right' role='group'>
<small>{{ previous.serial }}</small> {% if previous %}
</a> <a class="btn btn-small btn-outline-secondary" aria-label="{% trans 'previous page' %}" href="{% url request.resolver_match.url_name previous.id %}" title='{% trans "Navigate to previous serial number" %}'>
{% endif %} <span class='fas fa-angle-left'></span>
{{ item.serial }} <small>{{ previous.serial }}</small>
{% if next %} </a>
<a class="btn btn-outline-secondary text-sm" aria-label="{% trans 'next page' %}" href="{% url request.resolver_match.url_name next.id %}"> {% endif %}
<small>{{ next.serial }}</small> <a class='btn btn-small btn-outline-secondary text-sm' href='#' id='serial-number-search' title='{% trans "Search for serial number" %}'>
</a> <span class='fas fa-search'></span>
{% endif %} </a>
{% if next %}
<a class="btn btn-small btn-outline-secondary text-sm" aria-label="{% trans 'next page' %}" href="{% url request.resolver_match.url_name next.id %}" title='{% trans "Navigate to next serial number" %}'>
<small>{{ next.serial }}</small>
<span class='fas fa-angle-right'></span>
</a>
{% endif %}
</div>
</td> </td>
</tr> </tr>
{% else %} {% else %}
@ -592,4 +599,8 @@ $("#stock-return-from-customer").click(function() {
{% endif %} {% endif %}
$('#serial-number-search').click(function() {
findStockItemBySerialNumber({{ item.part.pk }});
});
{% endblock %} {% endblock %}

View File

@ -181,10 +181,10 @@
<script type='text/javascript' src="{% i18n_static 'tables.js' %}"></script> <script type='text/javascript' src="{% i18n_static 'tables.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'table_filters.js' %}"></script> <script type='text/javascript' src="{% i18n_static 'table_filters.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script> <script type='text/javascript' src="{% static 'fontawesome/js/solid.min.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/regular.js' %}"></script> <script type='text/javascript' src="{% static 'fontawesome/js/regular.min.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script> <script type='text/javascript' src="{% static 'fontawesome/js/brands.min.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script> <script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.min.js' %}"></script>
{% block js_load %} {% block js_load %}
{% endblock %} {% endblock %}

View File

@ -44,6 +44,7 @@
editStockItem, editStockItem,
editStockLocation, editStockLocation,
exportStock, exportStock,
findStockItemBySerialNumber,
loadInstalledInTable, loadInstalledInTable,
loadStockLocationTable, loadStockLocationTable,
loadStockTable, loadStockTable,
@ -394,6 +395,87 @@ function createNewStockItem(options={}) {
constructForm(url, options); constructForm(url, options);
} }
/*
* Launch a modal form to find a particular stock item by serial number.
* Arguments:
* - part: ID (PK) of the part in question
*/
function findStockItemBySerialNumber(part_id) {
constructFormBody({}, {
title: '{% trans "Find Serial Number" %}',
fields: {
serial: {
label: '{% trans "Serial Number" %}',
help_text: '{% trans "Enter serial number" %}',
placeholder: '{% trans "Enter serial number" %}',
required: true,
type: 'string',
value: '',
}
},
onSubmit: function(fields, opts) {
var serial = getFormFieldValue('serial', fields['serial'], opts);
serial = serial.toString().trim();
if (!serial) {
handleFormErrors(
{
'serial': [
'{% trans "Enter a serial number" %}',
]
}, fields, opts
);
return;
}
inventreeGet(
'{% url "api-stock-list" %}',
{
part_tree: part_id,
serial: serial,
},
{
success: function(response) {
if (response.length == 0) {
// No results!
handleFormErrors(
{
'serial': [
'{% trans "No matching serial number" %}',
]
}, fields, opts
);
} else if (response.length > 1) {
// Too many results!
handleFormErrors(
{
'serial': [
'{% trans "More than one matching result found" %}',
]
}, fields, opts
);
} else {
$(opts.modal).modal('hide');
// Redirect
var pk = response[0].pk;
location.href = `/stock/item/${pk}/`;
}
},
error: function(xhr) {
showApiError(xhr, opts.url);
$(opts.modal).modal('hide');
}
}
);
}
});
}
/* Stock API functions /* Stock API functions
* Requires api.js to be loaded first * Requires api.js to be loaded first