mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Filter StockItem API by staleness
This commit is contained in:
parent
33d6396a4e
commit
ba915da22b
@ -27,7 +27,7 @@ from InvenTree.helpers import increment, getSetting, normalize
|
|||||||
from InvenTree.validators import validate_build_order_reference
|
from InvenTree.validators import validate_build_order_reference
|
||||||
from InvenTree.models import InvenTreeAttachment
|
from InvenTree.models import InvenTreeAttachment
|
||||||
|
|
||||||
from common.models import InvenTreeSetting
|
import common.models
|
||||||
|
|
||||||
import InvenTree.fields
|
import InvenTree.fields
|
||||||
|
|
||||||
@ -822,7 +822,7 @@ class Build(MPTTModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Exclude expired stock items
|
# Exclude expired stock items
|
||||||
if not InvenTreeSetting.get_setting('STOCK_ALLOW_EXPIRED_BUILD'):
|
if not common.models.InvenTreeSetting.get_setting('STOCK_ALLOW_EXPIRED_BUILD'):
|
||||||
items = items.exclude(StockModels.StockItem.EXPIRED_FILTER)
|
items = items.exclude(StockModels.StockItem.EXPIRED_FILTER)
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
@ -174,6 +174,14 @@ class InvenTreeSetting(models.Model):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'STOCK_STALE_DAYS': {
|
||||||
|
'name': _('Stock Stale Time'),
|
||||||
|
'description': _('Number of days stock items are considered stale before expiring'),
|
||||||
|
'default': 0,
|
||||||
|
'units': _('days'),
|
||||||
|
'validator': [int],
|
||||||
|
},
|
||||||
|
|
||||||
'STOCK_ALLOW_EXPIRED_BUILD': {
|
'STOCK_ALLOW_EXPIRED_BUILD': {
|
||||||
'name': _('Build Expired Stock'),
|
'name': _('Build Expired Stock'),
|
||||||
'description': _('Allow building with expired stock'),
|
'description': _('Allow building with expired stock'),
|
||||||
@ -381,8 +389,10 @@ class InvenTreeSetting(models.Model):
|
|||||||
value = InvenTree.helpers.str2bool(value)
|
value = InvenTree.helpers.str2bool(value)
|
||||||
|
|
||||||
if setting.is_int():
|
if setting.is_int():
|
||||||
# TODO - Coerce to an integer value
|
try:
|
||||||
pass
|
value = int(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
value = backup_value
|
||||||
|
|
||||||
else:
|
else:
|
||||||
value = backup_value
|
value = backup_value
|
||||||
@ -472,18 +482,26 @@ class InvenTreeSetting(models.Model):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if a 'type' has been specified for this value
|
# Boolean validator
|
||||||
if type(validator) == type:
|
if validator == bool:
|
||||||
|
# Value must "look like" a boolean value
|
||||||
|
if InvenTree.helpers.is_bool(self.value):
|
||||||
|
# Coerce into either "True" or "False"
|
||||||
|
self.value = str(InvenTree.helpers.str2bool(self.value))
|
||||||
|
else:
|
||||||
|
raise ValidationError({
|
||||||
|
'value': _('Value must be a boolean value')
|
||||||
|
})
|
||||||
|
|
||||||
if validator == bool:
|
# Integer validator
|
||||||
# Value must "look like" a boolean value
|
if validator == int:
|
||||||
if InvenTree.helpers.is_bool(self.value):
|
try:
|
||||||
# Coerce into either "True" or "False"
|
# Coerce into an integer value
|
||||||
self.value = str(InvenTree.helpers.str2bool(self.value))
|
self.value = str(int(self.value))
|
||||||
else:
|
except (ValueError, TypeError):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'value': _('Value must be a boolean value')
|
'value': _('Value must be an integer value'),
|
||||||
})
|
})
|
||||||
|
|
||||||
def validate_unique(self, exclude=None):
|
def validate_unique(self, exclude=None):
|
||||||
""" Ensure that the key:value pair is unique.
|
""" Ensure that the key:value pair is unique.
|
||||||
@ -528,15 +546,29 @@ class InvenTreeSetting(models.Model):
|
|||||||
def is_int(self):
|
def is_int(self):
|
||||||
"""
|
"""
|
||||||
Check if the setting is required to be an integer value:
|
Check if the setting is required to be an integer value:
|
||||||
|
|
||||||
- int / 'int' = any integer value
|
|
||||||
- 'pos' / 'positive' = any positive integer value (including zero)
|
|
||||||
- 'neg' / 'negative' = any negative integer value (including zero)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
validator = InvenTreeSetting.get_setting_validator(self.key)
|
||||||
|
|
||||||
return validator in [int, 'int', 'pos', 'positive', 'neg', 'negative']
|
if validator == int:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if type(validator) in [list, tuple]:
|
||||||
|
for v in validator:
|
||||||
|
if v == int:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def as_int(self):
|
||||||
|
"""
|
||||||
|
Return the value of this setting converted to a boolean value.
|
||||||
|
|
||||||
|
If an error occurs, return the default value
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = int()
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return self.default_value()
|
||||||
|
|
||||||
|
|
||||||
class PriceBreak(models.Model):
|
class PriceBreak(models.Model):
|
||||||
|
@ -23,6 +23,9 @@ from part.serializers import PartBriefSerializer
|
|||||||
from company.models import SupplierPart
|
from company.models import SupplierPart
|
||||||
from company.serializers import SupplierPartSerializer
|
from company.serializers import SupplierPartSerializer
|
||||||
|
|
||||||
|
import common.settings
|
||||||
|
import common.models
|
||||||
|
|
||||||
from .serializers import StockItemSerializer
|
from .serializers import StockItemSerializer
|
||||||
from .serializers import LocationSerializer, LocationBriefSerializer
|
from .serializers import LocationSerializer, LocationBriefSerializer
|
||||||
from .serializers import StockTrackingSerializer
|
from .serializers import StockTrackingSerializer
|
||||||
@ -535,16 +538,37 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
# Exclude items which are instaled in another item
|
# Exclude items which are instaled in another item
|
||||||
queryset = queryset.filter(belongs_to=None)
|
queryset = queryset.filter(belongs_to=None)
|
||||||
|
|
||||||
# Filter by 'expired' status
|
if common.settings.stock_expiry_enabled():
|
||||||
expired = params.get('expired', None)
|
|
||||||
|
|
||||||
if expired is not None:
|
# Filter by 'expired' status
|
||||||
expired = str2bool(expired)
|
expired = params.get('expired', None)
|
||||||
|
|
||||||
if expired:
|
if expired is not None:
|
||||||
queryset = queryset.filter(StockItem.EXPIRED_FILTER)
|
expired = str2bool(expired)
|
||||||
else:
|
|
||||||
queryset = queryset.exclude(StockItem.EXPIRED_FILTER)
|
if expired:
|
||||||
|
queryset = queryset.filter(StockItem.EXPIRED_FILTER)
|
||||||
|
else:
|
||||||
|
queryset = queryset.exclude(StockItem.EXPIRED_FILTER)
|
||||||
|
|
||||||
|
# Filter by 'stale' status
|
||||||
|
stale = params.get('stale', None)
|
||||||
|
|
||||||
|
if stale is not None:
|
||||||
|
stale = str2bool(stale)
|
||||||
|
|
||||||
|
# How many days to account for "staleness"?
|
||||||
|
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
||||||
|
|
||||||
|
if stale_days > 0:
|
||||||
|
stale_date = datetime.now().date() + timedelta(days=stale_days)
|
||||||
|
|
||||||
|
stale_filter = StockItem.IN_STOCK_FILTER & ~Q(expiry_date=None) & Q(expiry_date__lt=stale_date)
|
||||||
|
|
||||||
|
if stale:
|
||||||
|
queryset = queryset.filter(stale_filter)
|
||||||
|
else:
|
||||||
|
queryset = queryset.exclude(stale_filter)
|
||||||
|
|
||||||
# Filter by customer
|
# Filter by customer
|
||||||
customer = params.get('customer', None)
|
customer = params.get('customer', None)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% if setting.value %}
|
{% if setting.value %}
|
||||||
<i><b>
|
<i><b>
|
||||||
{{ setting.value }}</b>{{ setting.units }}
|
{{ setting.value }}</b> {{ setting.units }}
|
||||||
</i>
|
</i>
|
||||||
{% else %}
|
{% else %}
|
||||||
<i>{% trans "No value set" %}</i>
|
<i>{% trans "No value set" %}</i>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="STOCK_STALE_DAYS" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_BUILD" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_BUILD" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
Loading…
Reference in New Issue
Block a user