mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 20:16:44 +00:00
Merge pull request #1350 from SchrodingersGat/recently-updated
Adds "Recently Updated Stock" to index page
This commit is contained in:
commit
94c8bb6805
@ -125,6 +125,13 @@ class InvenTreeSetting(models.Model):
|
||||
'validator': bool
|
||||
},
|
||||
|
||||
'PART_RECENT_COUNT': {
|
||||
'name': _('Recent Part Count'),
|
||||
'description': _('Number of recent parts to display on index page'),
|
||||
'default': 10,
|
||||
'validator': [int, MinValueValidator(1)]
|
||||
},
|
||||
|
||||
'PART_TEMPLATE': {
|
||||
'name': _('Template'),
|
||||
'description': _('Parts are templates by default'),
|
||||
@ -249,6 +256,13 @@ class InvenTreeSetting(models.Model):
|
||||
'validator': bool,
|
||||
},
|
||||
|
||||
'STOCK_RECENT_COUNT': {
|
||||
'name': _('Recent Stock Count'),
|
||||
'description': _('Number of recent stock items to display on index page'),
|
||||
'default': 10,
|
||||
'validator': [int, MinValueValidator(1)]
|
||||
},
|
||||
|
||||
'BUILDORDER_REFERENCE_PREFIX': {
|
||||
'name': _('Build Order Reference Prefix'),
|
||||
'description': _('Prefix value for build order reference'),
|
||||
@ -521,12 +535,18 @@ class InvenTreeSetting(models.Model):
|
||||
|
||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
||||
|
||||
if validator is not None:
|
||||
self.run_validator(validator)
|
||||
|
||||
if self.is_bool():
|
||||
self.value = InvenTree.helpers.str2bool(self.value)
|
||||
|
||||
if self.is_int():
|
||||
try:
|
||||
self.value = int(self.value)
|
||||
except (ValueError):
|
||||
raise ValidationError(_('Must be an integer value'))
|
||||
|
||||
if validator is not None:
|
||||
self.run_validator(validator)
|
||||
|
||||
def run_validator(self, validator):
|
||||
"""
|
||||
Run a validator against the 'value' field for this InvenTreeSetting object.
|
||||
@ -535,39 +555,39 @@ class InvenTreeSetting(models.Model):
|
||||
if validator is None:
|
||||
return
|
||||
|
||||
# If a list of validators is supplied, iterate through each one
|
||||
if type(validator) in [list, tuple]:
|
||||
for v in validator:
|
||||
self.run_validator(v)
|
||||
|
||||
return
|
||||
|
||||
if callable(validator):
|
||||
# We can accept function validators with a single argument
|
||||
print("Running validator function")
|
||||
validator(self.value)
|
||||
value = self.value
|
||||
|
||||
# Boolean validator
|
||||
if validator == bool:
|
||||
if self.is_bool():
|
||||
# Value must "look like" a boolean value
|
||||
if InvenTree.helpers.is_bool(self.value):
|
||||
if InvenTree.helpers.is_bool(value):
|
||||
# Coerce into either "True" or "False"
|
||||
self.value = str(InvenTree.helpers.str2bool(self.value))
|
||||
value = InvenTree.helpers.str2bool(value)
|
||||
else:
|
||||
raise ValidationError({
|
||||
'value': _('Value must be a boolean value')
|
||||
})
|
||||
|
||||
# Integer validator
|
||||
if validator == int:
|
||||
if self.is_int():
|
||||
|
||||
try:
|
||||
# Coerce into an integer value
|
||||
self.value = str(int(self.value))
|
||||
value = int(value)
|
||||
except (ValueError, TypeError):
|
||||
raise ValidationError({
|
||||
'value': _('Value must be an integer value'),
|
||||
})
|
||||
|
||||
# If a list of validators is supplied, iterate through each one
|
||||
if type(validator) in [list, tuple]:
|
||||
for v in validator:
|
||||
self.run_validator(v)
|
||||
|
||||
if callable(validator):
|
||||
# We can accept function validators with a single argument
|
||||
validator(self.value)
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
""" Ensure that the key:value pair is unique.
|
||||
In addition to the base validators, this ensures that the 'key'
|
||||
@ -597,7 +617,13 @@ class InvenTreeSetting(models.Model):
|
||||
|
||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
||||
|
||||
return validator == bool
|
||||
if validator == bool:
|
||||
return True
|
||||
|
||||
if type(validator) in [list, tuple]:
|
||||
for v in validator:
|
||||
if v == bool:
|
||||
return True
|
||||
|
||||
def as_bool(self):
|
||||
"""
|
||||
@ -623,6 +649,8 @@ class InvenTreeSetting(models.Model):
|
||||
if v == int:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def as_int(self):
|
||||
"""
|
||||
Return the value of this setting converted to a boolean value.
|
||||
|
@ -626,7 +626,7 @@ class PartList(generics.ListCreateAPIView):
|
||||
|
||||
queryset = queryset.filter(pk__in=parts_need_stock)
|
||||
|
||||
# Limit choices
|
||||
# Limit number of results
|
||||
limit = params.get('limit', None)
|
||||
|
||||
if limit is not None:
|
||||
|
@ -808,6 +808,19 @@ class StockList(generics.ListCreateAPIView):
|
||||
print("After error:", str(updated_after))
|
||||
pass
|
||||
|
||||
# Limit number of results
|
||||
limit = params.get('limit', None)
|
||||
|
||||
if limit is not None:
|
||||
try:
|
||||
limit = int(limit)
|
||||
|
||||
if limit > 0:
|
||||
queryset = queryset[:limit]
|
||||
|
||||
except (ValueError):
|
||||
pass
|
||||
|
||||
# Also ensure that we pre-fecth all the related items
|
||||
queryset = queryset.prefetch_related(
|
||||
'part',
|
||||
@ -815,8 +828,6 @@ class StockList(generics.ListCreateAPIView):
|
||||
'location'
|
||||
)
|
||||
|
||||
queryset = queryset.order_by('part__name')
|
||||
|
||||
return queryset
|
||||
|
||||
filter_backends = [
|
||||
@ -828,6 +839,15 @@ class StockList(generics.ListCreateAPIView):
|
||||
filter_fields = [
|
||||
]
|
||||
|
||||
ordering_fields = [
|
||||
'part__name',
|
||||
'updated',
|
||||
'stocktake_date',
|
||||
'expiry_date',
|
||||
]
|
||||
|
||||
ordering = ['part__name']
|
||||
|
||||
search_fields = [
|
||||
'serial',
|
||||
'batch',
|
||||
|
@ -102,7 +102,7 @@ addHeaderAction('bom-validation', '{% trans "BOM Waiting Validation" %}', 'fa-ti
|
||||
loadSimplePartTable("#table-latest-parts", "{% url 'api-part-list' %}", {
|
||||
params: {
|
||||
ordering: "-creation_date",
|
||||
limit: 10,
|
||||
limit: {% settings_value "PART_RECENT_COUNT" %},
|
||||
},
|
||||
name: 'latest_parts',
|
||||
});
|
||||
@ -125,8 +125,19 @@ loadSimplePartTable("#table-bom-validation", "{% url 'api-part-list' %}", {
|
||||
|
||||
{% if roles.stock.view %}
|
||||
addHeaderTitle('{% trans "Stock" %}');
|
||||
addHeaderAction('recently-updated-stock', '{% trans "Recently Updated" %}', 'fa-clock');
|
||||
addHeaderAction('low-stock', '{% trans "Low Stock" %}', 'fa-shopping-cart');
|
||||
addHeaderAction('stock-to-build', '{% trans "Required for Build Orders" %}', 'fa-bullhorn');
|
||||
|
||||
loadStockTable($('#table-recently-updated-stock'), {
|
||||
params: {
|
||||
ordering: "-updated",
|
||||
limit: {% settings_value "STOCK_RECENT_COUNT" %},
|
||||
},
|
||||
name: 'recently-updated-stock',
|
||||
grouping: false,
|
||||
});
|
||||
|
||||
{% settings_value "STOCK_ENABLE_EXPIRY" as expiry %}
|
||||
{% if expiry %}
|
||||
addHeaderAction('expired-stock', '{% trans "Expired Stock" %}', 'fa-calendar-times');
|
||||
|
@ -19,6 +19,7 @@
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_ALLOW_DUPLICATE_IPN" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_RECENT_COUNT" icon="fa-clock" %}
|
||||
<tr><td colspan='5 '></td></tr>
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %}
|
||||
|
@ -16,6 +16,7 @@
|
||||
{% include "InvenTree/settings/header.html" %}
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="STOCK_GROUP_BY_PART" icon="fa-layer-group" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="STOCK_RECENT_COUNT" icon="fa-clock" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" icon="fa-stopwatch" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="STOCK_STALE_DAYS" icon="fa-calendar" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %}
|
||||
|
@ -319,6 +319,12 @@ function loadStockTable(table, options) {
|
||||
}
|
||||
}
|
||||
|
||||
var grouping = true;
|
||||
|
||||
if ('grouping' in options) {
|
||||
grouping = options.grouping;
|
||||
}
|
||||
|
||||
table.inventreeTable({
|
||||
method: 'get',
|
||||
formatNoMatches: function() {
|
||||
@ -333,7 +339,7 @@ function loadStockTable(table, options) {
|
||||
{% settings_value 'STOCK_GROUP_BY_PART' as group_by_part %}
|
||||
{% if group_by_part %}
|
||||
groupByField: options.groupByField || 'part',
|
||||
groupBy: true,
|
||||
groupBy: grouping,
|
||||
groupByFormatter: function(field, id, data) {
|
||||
|
||||
var row = data[0];
|
||||
|
Loading…
x
Reference in New Issue
Block a user