2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 11:10:54 +00:00

Merge remote-tracking branch 'inventree/master' into locate-mixin

# Conflicts:
#	InvenTree/InvenTree/api_version.py
#	InvenTree/InvenTree/urls.py
This commit is contained in:
Oliver Walters
2022-05-15 23:44:07 +10:00
66 changed files with 17711 additions and 17204 deletions

View File

@ -33,7 +33,7 @@ from company.serializers import CompanySerializer, SupplierPartSerializer
from InvenTree.helpers import str2bool, isNull, extract_serial_numbers
from InvenTree.helpers import DownloadFile
from InvenTree.api import AttachmentMixin
from InvenTree.api import AttachmentMixin, APIDownloadMixin
from InvenTree.filters import InvenTreeOrderingFilter
from order.models import PurchaseOrder
@ -505,7 +505,7 @@ class StockFilter(rest_filters.FilterSet):
updated_after = rest_filters.DateFilter(label='Updated after', field_name='updated', lookup_expr='gte')
class StockList(generics.ListCreateAPIView):
class StockList(APIDownloadMixin, generics.ListCreateAPIView):
""" API endpoint for list view of Stock objects
- GET: Return a list of all StockItem objects (with optional query filters)
@ -646,6 +646,22 @@ class StockList(generics.ListCreateAPIView):
return Response(response_data, status=status.HTTP_201_CREATED, headers=self.get_success_headers(serializer.data))
def download_queryset(self, queryset, export_format):
"""
Download this queryset as a file.
Uses the APIDownloadMixin mixin class
"""
dataset = StockItemResource().export(queryset=queryset)
filedata = dataset.export(export_format)
filename = 'InvenTree_StockItems_{date}.{fmt}'.format(
date=datetime.now().strftime("%d-%b-%Y"),
fmt=export_format
)
return DownloadFile(filedata, filename)
def list(self, request, *args, **kwargs):
"""
Override the 'list' method, as the StockLocation objects
@ -658,25 +674,6 @@ class StockList(generics.ListCreateAPIView):
params = request.query_params
# Check if we wish to export the queried data to a file.
# If so, skip pagination!
export_format = params.get('export', None)
if export_format:
export_format = str(export_format).strip().lower()
if export_format in ['csv', 'tsv', 'xls', 'xlsx']:
dataset = StockItemResource().export(queryset=queryset)
filedata = dataset.export(export_format)
filename = 'InvenTree_Stocktake_{date}.{fmt}'.format(
date=datetime.now().strftime("%d-%b-%Y"),
fmt=export_format
)
return DownloadFile(filedata, filename)
page = self.paginate_queryset(queryset)
if page is not None:

View File

@ -30,7 +30,8 @@ from mptt.managers import TreeManager
from decimal import Decimal, InvalidOperation
from datetime import datetime, timedelta
from InvenTree import helpers
import InvenTree.helpers
import InvenTree.ready
import InvenTree.tasks
import common.models
@ -137,7 +138,7 @@ class StockLocation(InvenTreeTree):
def format_barcode(self, **kwargs):
""" Return a JSON string for formatting a barcode for this StockLocation object """
return helpers.MakeBarcode(
return InvenTree.helpers.MakeBarcode(
'stocklocation',
self.pk,
{
@ -555,7 +556,14 @@ class StockItem(MPTTModel):
# If the item points to a build, check that the Part references match
if self.build:
if not self.part == self.build.part:
if self.part == self.build.part:
# Part references match exactly
pass
elif self.part in self.build.part.get_conversion_options():
# Part reference is one of the valid conversion options for the build output
pass
else:
raise ValidationError({
'build': _("Build reference does not point to the same part object")
})
@ -577,7 +585,7 @@ class StockItem(MPTTModel):
Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change)
"""
return helpers.MakeBarcode(
return InvenTree.helpers.MakeBarcode(
"stockitem",
self.id,
{
@ -1775,7 +1783,7 @@ class StockItem(MPTTModel):
sn=self.serial)
else:
s = '{n} x {part}'.format(
n=helpers.decimal2string(self.quantity),
n=InvenTree.helpers.decimal2string(self.quantity),
part=self.part.full_name)
if self.location:
@ -1783,7 +1791,7 @@ class StockItem(MPTTModel):
if self.purchase_order:
s += " ({pre}{po})".format(
pre=helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
pre=InvenTree.helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
po=self.purchase_order,
)
@ -1851,7 +1859,7 @@ class StockItem(MPTTModel):
result_map = {}
for result in results:
key = helpers.generateTestKey(result.test)
key = InvenTree.helpers.generateTestKey(result.test)
result_map[key] = result
# Do we wish to "cascade" and include test results from installed stock items?
@ -1898,7 +1906,7 @@ class StockItem(MPTTModel):
failed = 0
for test in required:
key = helpers.generateTestKey(test.test_name)
key = InvenTree.helpers.generateTestKey(test.test_name)
if key in results:
result = results[key]
@ -1949,7 +1957,7 @@ class StockItem(MPTTModel):
# Attempt to validate report filter (skip if invalid)
try:
filters = helpers.validateFilterString(test_report.filters)
filters = InvenTree.helpers.validateFilterString(test_report.filters)
if item_query.filter(**filters).exists():
reports.append(test_report)
except (ValidationError, FieldError):
@ -1977,7 +1985,7 @@ class StockItem(MPTTModel):
for lbl in label.models.StockItemLabel.objects.filter(enabled=True):
try:
filters = helpers.validateFilterString(lbl.filters)
filters = InvenTree.helpers.validateFilterString(lbl.filters)
if item_query.filter(**filters).exists():
labels.append(lbl)
@ -2016,8 +2024,9 @@ def after_delete_stock_item(sender, instance: StockItem, **kwargs):
Function to be executed after a StockItem object is deleted
"""
# Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
if not InvenTree.ready.isImportingData():
# Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
@receiver(post_save, sender=StockItem, dispatch_uid='stock_item_post_save_log')
@ -2026,8 +2035,9 @@ def after_save_stock_item(sender, instance: StockItem, created, **kwargs):
Hook function to be executed after StockItem object is saved/updated
"""
# Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
if not InvenTree.ready.isImportingData():
# Run this check in the background
InvenTree.tasks.offload_task('part.tasks.notify_low_stock_if_required', instance.part)
class StockItemAttachment(InvenTreeAttachment):
@ -2170,7 +2180,7 @@ class StockItemTestResult(models.Model):
@property
def key(self):
return helpers.generateTestKey(self.test)
return InvenTree.helpers.generateTestKey(self.test)
stock_item = models.ForeignKey(
StockItem,