Add "expiry_date" field to StockItem model

- Also adds "is_expired" function
This commit is contained in:
Oliver Walters 2021-01-03 23:56:35 +11:00
parent fe3d4a9867
commit 07cda765f0
3 changed files with 89 additions and 27 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2021-01-03 12:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0055_auto_20201117_1453'),
]
operations = [
migrations.AddField(
model_name='stockitem',
name='expiry_date',
field=models.DateField(blank=True, help_text='Expiry date for stock item. Stock will be considered expired after this date', null=True, verbose_name='Expiry Date'),
),
]

View File

@ -125,6 +125,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
@ -428,11 +429,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)
@ -459,6 +468,27 @@ class StockItem(MPTTModel):
help_text=_('Single unit purchase price at time of purchase'),
)
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:
@ -721,36 +751,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):

View File

@ -49,6 +49,40 @@ class StockTest(TestCase):
Part.objects.rebuild()
StockItem.objects.rebuild()
def test_expiry(self):
"""
Test expiry date functionality for StockItem model.
"""
today = datetime.datetime.now().date()
item = StockItem.objects.create(
location=self.office,
part=Part.objects.get(pk=1),
quantity=10,
)
# Without an expiry_date set, item should not be "expired"
self.assertFalse(item.is_expired())
# Set the expiry date to today
item.expiry_date = today
item.save()
self.assertFalse(item.is_expired())
# Set the expiry date in the future
item.expiry_date = today + datetime.timedelta(days=5)
item.save()
self.assertFalse(item.is_expired())
# Set the expiry date in the past
item.expiry_date = today - datetime.timedelta(days=5)
item.save()
self.assertTrue(item.is_expired())
def test_is_building(self):
"""
Test that the is_building flag does not count towards stock.