mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-05 13:10:57 +00:00
Part stocktake (#4069)
* Remove stat context variables
* Revert "Remove stat context variables"
This reverts commit 0989c308d0
.
* Allow longer timeout for image download tests
* Create PartStocktake model
Model for representing stocktake entries against any given part
* Admin interface support for new model
* Adds API endpoint for listing stocktake information
* Bump API version
* Enable filtering and ordering for API endpoint
* Add model to permission group
* Add UI hooks for displaying stocktake data for a particular part
* Fix encoded type for 'quantity' field
* Load stocktake table for part
* Add "stocktake" button
* Add "note" field for stocktake
* Add user information when performing stocktake
* First pass at UI elements for performing stocktake
* Add user information to stocktake table
* Auto-calculate quantity based on available stock items
* add stocktake data as tabular inline (admin)
* js linting
* Add indication that a stock item has not been updated recently
* Display last stocktake information on part page
* js style fix
* Test fix for ongoing CI issues
* Add configurable option for controlling default "delete_on_deplete" behaviour
* Add id values to cells
* Hide action buttons (at least for now)
* Adds refresh button to table
* Add API endpoint to delete or edit stocktake entries
* Adds unit test for API list endpoint
* javascript linting
* More unit testing
* Add Part API filter for stocktake
* Add 'last_stocktake' field to Part model
- Gets filled out automatically when a new PartStocktake instance is created
* Update part table to include last_stocktake date
* Add simple unit test
* Fix test
This commit is contained in:
@ -372,6 +372,7 @@ class Part(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
|
||||
creation_date: Date that this part was added to the database
|
||||
creation_user: User who added this part to the database
|
||||
responsible: User who is responsible for this part (optional)
|
||||
last_stocktake: Date at which last stocktake was performed for this Part
|
||||
"""
|
||||
|
||||
objects = PartManager()
|
||||
@ -1004,6 +1005,11 @@ class Part(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
|
||||
|
||||
responsible = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, verbose_name=_('Responsible'), related_name='parts_responible')
|
||||
|
||||
last_stocktake = models.DateField(
|
||||
blank=True, null=True,
|
||||
verbose_name=_('Last Stocktake'),
|
||||
)
|
||||
|
||||
@property
|
||||
def category_path(self):
|
||||
"""Return the category path of this Part instance"""
|
||||
@ -2161,6 +2167,12 @@ class Part(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
|
||||
|
||||
return params
|
||||
|
||||
@property
|
||||
def latest_stocktake(self):
|
||||
"""Return the latest PartStocktake object associated with this part (if one exists)"""
|
||||
|
||||
return self.stocktakes.order_by('-pk').first()
|
||||
|
||||
@property
|
||||
def has_variants(self):
|
||||
"""Check if this Part object has variants underneath it."""
|
||||
@ -2878,6 +2890,66 @@ class PartPricing(models.Model):
|
||||
)
|
||||
|
||||
|
||||
class PartStocktake(models.Model):
|
||||
"""Model representing a 'stocktake' entry for a particular Part.
|
||||
|
||||
A 'stocktake' is a representative count of available stock:
|
||||
- Performed on a given date
|
||||
- Records quantity of part in stock (across multiple stock items)
|
||||
- Records user information
|
||||
"""
|
||||
|
||||
part = models.ForeignKey(
|
||||
Part,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='stocktakes',
|
||||
verbose_name=_('Part'),
|
||||
help_text=_('Part for stocktake'),
|
||||
)
|
||||
|
||||
quantity = models.DecimalField(
|
||||
max_digits=19, decimal_places=5,
|
||||
validators=[MinValueValidator(0)],
|
||||
verbose_name=_('Quantity'),
|
||||
help_text=_('Total available stock at time of stocktake'),
|
||||
)
|
||||
|
||||
date = models.DateField(
|
||||
verbose_name=_('Date'),
|
||||
help_text=_('Date stocktake was performed'),
|
||||
auto_now_add=True
|
||||
)
|
||||
|
||||
note = models.CharField(
|
||||
max_length=250,
|
||||
blank=True,
|
||||
verbose_name=_('Notes'),
|
||||
help_text=_('Additional notes'),
|
||||
)
|
||||
|
||||
user = models.ForeignKey(
|
||||
User, blank=True, null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='part_stocktakes',
|
||||
verbose_name=_('User'),
|
||||
help_text=_('User who performed this stocktake'),
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=PartStocktake, dispatch_uid='post_save_stocktake')
|
||||
def update_last_stocktake(sender, instance, created, **kwargs):
|
||||
"""Callback function when a PartStocktake instance is created / edited"""
|
||||
|
||||
# When a new PartStocktake instance is create, update the last_stocktake date for the Part
|
||||
if created:
|
||||
try:
|
||||
part = instance.part
|
||||
part.last_stocktake = instance.date
|
||||
part.save()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class PartAttachment(InvenTreeAttachment):
|
||||
"""Model for storing file attachments against a Part object."""
|
||||
|
||||
|
Reference in New Issue
Block a user