mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
merge master in
This commit is contained in:
commit
0379498ee3
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -1075,6 +1075,7 @@ class PartList(generics.ListCreateAPIView):
|
|||||||
'revision',
|
'revision',
|
||||||
'keywords',
|
'keywords',
|
||||||
'category__name',
|
'category__name',
|
||||||
|
'manufacturer_parts__MPN',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 %}
|
@ -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)
|
||||||
|
|
||||||
|
@ -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 %}
|
||||||
|
@ -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 %}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user