mirror of
https://github.com/inventree/InvenTree.git
synced 2025-08-28 14:25:56 +00:00
Merged master
This commit is contained in:
@@ -27,9 +27,12 @@ from mptt.models import MPTTModel, TreeForeignKey
|
||||
from djmoney.models.fields import MoneyField
|
||||
|
||||
from decimal import Decimal, InvalidOperation
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from InvenTree import helpers
|
||||
|
||||
import common.models
|
||||
import report.models
|
||||
|
||||
from InvenTree.status_codes import StockStatus
|
||||
from InvenTree.models import InvenTreeTree, InvenTreeAttachment
|
||||
from InvenTree.fields import InvenTreeURLField
|
||||
@@ -129,6 +132,7 @@ class StockItem(MPTTModel):
|
||||
serial: Unique serial number for this StockItem
|
||||
link: Optional URL to link to external resource
|
||||
updated: Date that this stock item was last updated (auto)
|
||||
expiry_date: Expiry date of the StockItem (optional)
|
||||
stocktake_date: Date of last stocktake for this item
|
||||
stocktake_user: User that performed the most recent stocktake
|
||||
review_needed: Flag if StockItem needs review
|
||||
@@ -153,6 +157,9 @@ class StockItem(MPTTModel):
|
||||
status__in=StockStatus.AVAILABLE_CODES
|
||||
)
|
||||
|
||||
# A query filter which can be used to filter StockItem objects which have expired
|
||||
EXPIRED_FILTER = IN_STOCK_FILTER & ~Q(expiry_date=None) & Q(expiry_date__lt=datetime.now().date())
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Save this StockItem to the database. Performs a number of checks:
|
||||
@@ -432,11 +439,19 @@ class StockItem(MPTTModel):
|
||||
related_name='stock_items',
|
||||
null=True, blank=True)
|
||||
|
||||
# last time the stock was checked / counted
|
||||
expiry_date = models.DateField(
|
||||
blank=True, null=True,
|
||||
verbose_name=_('Expiry Date'),
|
||||
help_text=_('Expiry date for stock item. Stock will be considered expired after this date'),
|
||||
)
|
||||
|
||||
stocktake_date = models.DateField(blank=True, null=True)
|
||||
|
||||
stocktake_user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True,
|
||||
related_name='stocktake_stock')
|
||||
stocktake_user = models.ForeignKey(
|
||||
User, on_delete=models.SET_NULL,
|
||||
blank=True, null=True,
|
||||
related_name='stocktake_stock'
|
||||
)
|
||||
|
||||
review_needed = models.BooleanField(default=False)
|
||||
|
||||
@@ -467,6 +482,55 @@ class StockItem(MPTTModel):
|
||||
help_text='Owner (User)',
|
||||
related_name='owner_stockitems')
|
||||
|
||||
def is_stale(self):
|
||||
"""
|
||||
Returns True if this Stock item is "stale".
|
||||
|
||||
To be "stale", the following conditions must be met:
|
||||
|
||||
- Expiry date is not None
|
||||
- Expiry date will "expire" within the configured stale date
|
||||
- The StockItem is otherwise "in stock"
|
||||
"""
|
||||
|
||||
if self.expiry_date is None:
|
||||
return False
|
||||
|
||||
if not self.in_stock:
|
||||
return False
|
||||
|
||||
today = datetime.now().date()
|
||||
|
||||
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
||||
|
||||
if stale_days <= 0:
|
||||
return False
|
||||
|
||||
expiry_date = today + timedelta(days=stale_days)
|
||||
|
||||
return self.expiry_date < expiry_date
|
||||
|
||||
def is_expired(self):
|
||||
"""
|
||||
Returns True if this StockItem is "expired".
|
||||
|
||||
To be "expired", the following conditions must be met:
|
||||
|
||||
- Expiry date is not None
|
||||
- Expiry date is "in the past"
|
||||
- The StockItem is otherwise "in stock"
|
||||
"""
|
||||
|
||||
if self.expiry_date is None:
|
||||
return False
|
||||
|
||||
if not self.in_stock:
|
||||
return False
|
||||
|
||||
today = datetime.now().date()
|
||||
|
||||
return self.expiry_date < today
|
||||
|
||||
def clearAllocations(self):
|
||||
"""
|
||||
Clear all order allocations for this StockItem:
|
||||
@@ -729,36 +793,16 @@ class StockItem(MPTTModel):
|
||||
@property
|
||||
def in_stock(self):
|
||||
"""
|
||||
Returns True if this item is in stock
|
||||
Returns True if this item is in stock.
|
||||
|
||||
See also: IN_STOCK_FILTER
|
||||
"""
|
||||
|
||||
# Quantity must be above zero (unless infinite)
|
||||
if self.quantity <= 0 and not self.infinite:
|
||||
return False
|
||||
query = StockItem.objects.filter(pk=self.pk)
|
||||
|
||||
# Not 'in stock' if it has been installed inside another StockItem
|
||||
if self.belongs_to is not None:
|
||||
return False
|
||||
|
||||
# Not 'in stock' if it has been sent to a customer
|
||||
if self.sales_order is not None:
|
||||
return False
|
||||
query = query.filter(StockItem.IN_STOCK_FILTER)
|
||||
|
||||
# Not 'in stock' if it has been assigned to a customer
|
||||
if self.customer is not None:
|
||||
return False
|
||||
|
||||
# Not 'in stock' if it is building
|
||||
if self.is_building:
|
||||
return False
|
||||
|
||||
# Not 'in stock' if the status code makes it unavailable
|
||||
if self.status in StockStatus.UNAVAILABLE_CODES:
|
||||
return False
|
||||
|
||||
return True
|
||||
return query.exists()
|
||||
|
||||
@property
|
||||
def tracking_info_count(self):
|
||||
@@ -1271,6 +1315,41 @@ class StockItem(MPTTModel):
|
||||
|
||||
return status['passed'] >= status['total']
|
||||
|
||||
def available_test_reports(self):
|
||||
"""
|
||||
Return a list of TestReport objects which match this StockItem.
|
||||
"""
|
||||
|
||||
reports = []
|
||||
|
||||
item_query = StockItem.objects.filter(pk=self.pk)
|
||||
|
||||
for test_report in report.models.TestReport.objects.filter(enabled=True):
|
||||
|
||||
filters = helpers.validateFilterString(test_report.filters)
|
||||
|
||||
if item_query.filter(**filters).exists():
|
||||
reports.append(test_report)
|
||||
|
||||
return reports
|
||||
|
||||
@property
|
||||
def has_test_reports(self):
|
||||
"""
|
||||
Return True if there are test reports available for this stock item
|
||||
"""
|
||||
|
||||
return len(self.available_test_reports()) > 0
|
||||
|
||||
@property
|
||||
def has_labels(self):
|
||||
"""
|
||||
Return True if there are any label templates available for this stock item
|
||||
"""
|
||||
|
||||
# TODO - Implement this
|
||||
return True
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=StockItem, dispatch_uid='stock_item_pre_delete_log')
|
||||
def before_delete_stock_item(sender, instance, using, **kwargs):
|
||||
|
Reference in New Issue
Block a user