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

Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters
2020-08-16 15:10:23 +10:00
36 changed files with 1923 additions and 1089 deletions

View File

@ -338,11 +338,6 @@ class StockList(generics.ListCreateAPIView):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
data = serializer.data
@ -363,6 +358,7 @@ class StockList(generics.ListCreateAPIView):
part_ids.add(part)
sp = item['supplier_part']
if sp:
supplier_part_ids.add(sp)
@ -434,6 +430,7 @@ class StockList(generics.ListCreateAPIView):
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
queryset = StockItemSerializer.prefetch_queryset(queryset)
queryset = StockItemSerializer.annotate_queryset(queryset)

View File

@ -178,6 +178,37 @@ class SerializeStockForm(HelperForm):
]
class StockItemLabelSelectForm(HelperForm):
""" Form for selecting a label template for a StockItem """
label = forms.ChoiceField(
label=_('Label'),
help_text=_('Select test report template')
)
class Meta:
model = StockItem
fields = [
'label',
]
def get_label_choices(self, labels):
choices = []
if len(labels) > 0:
for label in labels:
choices.append((label.pk, label))
return choices
def __init__(self, labels, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['label'].choices = self.get_label_choices(labels)
class TestReportFormatForm(HelperForm):
""" Form for selection a test report template """

View File

@ -45,16 +45,17 @@ class StockLocation(InvenTreeTree):
def get_absolute_url(self):
return reverse('stock-location-detail', kwargs={'pk': self.id})
def format_barcode(self):
def format_barcode(self, **kwargs):
""" Return a JSON string for formatting a barcode for this StockLocation object """
return helpers.MakeBarcode(
'stocklocation',
self.pk,
{
"id": self.id,
"name": self.name,
"url": reverse('api-location-detail', kwargs={'pk': self.id}),
}
},
**kwargs
)
def get_stock_items(self, cascade=True):
@ -283,7 +284,7 @@ class StockItem(MPTTModel):
def get_part_name(self):
return self.part.full_name
def format_barcode(self):
def format_barcode(self, **kwargs):
""" Return a JSON string for formatting a barcode for this StockItem.
Can be used to perform lookup of a stockitem using barcode
@ -296,10 +297,11 @@ class StockItem(MPTTModel):
return helpers.MakeBarcode(
"stockitem",
self.id,
{
"id": self.id,
"url": reverse('api-stock-detail', kwargs={'pk': self.id}),
}
},
**kwargs
)
uid = models.CharField(blank=True, max_length=128, help_text=("Unique identifier field"))

View File

@ -99,15 +99,34 @@ class StockItemSerializer(InvenTreeModelSerializer):
return queryset
belongs_to = serializers.PrimaryKeyRelatedField(read_only=True)
build_order = serializers.PrimaryKeyRelatedField(read_only=True)
customer = serializers.PrimaryKeyRelatedField(read_only=True)
location = serializers.PrimaryKeyRelatedField(read_only=True)
in_stock = serializers.BooleanField(read_only=True)
sales_order = serializers.PrimaryKeyRelatedField(read_only=True)
status_text = serializers.CharField(source='get_status_display', read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
supplier_part = serializers.PrimaryKeyRelatedField(read_only=True)
supplier_part_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True)
part = serializers.PrimaryKeyRelatedField(read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True, required=False)
quantity = serializers.FloatField()
allocated = serializers.FloatField(source='allocation_count', required=False)
serial = serializers.IntegerField(required=False)
@ -140,9 +159,9 @@ class StockItemSerializer(InvenTreeModelSerializer):
fields = [
'allocated',
'batch',
'build_order',
'belongs_to',
'customer',
'build_order',
'in_stock',
'link',
'location',
@ -155,10 +174,10 @@ class StockItemSerializer(InvenTreeModelSerializer):
'required_tests',
'sales_order',
'serial',
'supplier_part',
'supplier_part_detail',
'status',
'status_text',
'supplier_part',
'supplier_part_detail',
'tracking_items',
'uid',
]

View File

@ -78,7 +78,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
<button id='barcode-options' title='{% trans "Barcode actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-qrcode'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
<li><a href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
<li class='disabled'><a href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li>
<li><a href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li>
{% if item.uid %}
<li><a href='#' id='unlink-barcode'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
{% else %}
@ -126,7 +126,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</div>
{% if item.part.has_test_report_templates %}
<button type='button' class='btn btn-default' id='stock-test-report' title='{% trans "Generate test report" %}'>
<span class='fas fa-tasks'/>
<span class='fas fa-file-invoice'/>
</button>
{% endif %}
</div>
@ -314,6 +314,15 @@ $("#stock-test-report").click(function() {
});
{% endif %}
$("#print-label").click(function() {
launchModalForm(
"{% url 'stock-item-label-select' item.id %}",
{
follow: true,
}
)
});
$("#stock-duplicate").click(function() {
launchModalForm(
"{% url 'stock-item-create' %}",

View File

@ -29,6 +29,7 @@ stock_item_detail_urls = [
url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
url(r'^test-report-select/', views.StockItemTestReportSelect.as_view(), name='stock-item-test-report-select'),
url(r'^label-select/', views.StockItemSelectLabels.as_view(), name='stock-item-label-select'),
url(r'^test/', views.StockItemDetail.as_view(template_name='stock/item_tests.html'), name='stock-item-test-results'),
url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'),
@ -59,6 +60,7 @@ stock_urls = [
url(r'^item/new/?', views.StockItemCreate.as_view(), name='stock-item-create'),
url(r'^item/test-report-download/', views.StockItemTestReportDownload.as_view(), name='stock-item-test-report-download'),
url(r'^item/print-stock-labels/', views.StockItemPrintLabels.as_view(), name='stock-item-print-labels'),
# URLs for StockItem attachments
url(r'^item/attachment/', include([

View File

@ -28,6 +28,7 @@ from datetime import datetime
from company.models import Company, SupplierPart
from part.models import Part
from report.models import TestReport
from label.models import StockItemLabel
from .models import StockItem, StockLocation, StockItemTracking, StockItemAttachment, StockItemTestResult
from .admin import StockItemResource
@ -295,6 +296,88 @@ class StockItemReturnToStock(AjaxUpdateView):
return self.renderJsonResponse(request, self.get_form(), data)
class StockItemSelectLabels(AjaxView):
"""
View for selecting a template for printing labels for one (or more) StockItem objects
"""
model = StockItem
ajax_form_title = _('Select Label Template')
def get_form(self):
item = StockItem.objects.get(pk=self.kwargs['pk'])
labels = []
for label in StockItemLabel.objects.all():
if label.matches_stock_item(item):
labels.append(label)
return StockForms.StockItemLabelSelectForm(labels)
def post(self, request, *args, **kwargs):
label = request.POST.get('label', None)
try:
label = StockItemLabel.objects.get(pk=label)
except (ValueError, StockItemLabel.DoesNotExist):
raise ValidationError({'label': _("Select valid label")})
stock_item = StockItem.objects.get(pk=self.kwargs['pk'])
url = reverse('stock-item-print-labels')
url += '?label={pk}'.format(pk=label.pk)
url += '&items[]={pk}'.format(pk=stock_item.pk)
data = {
'form_valid': True,
'url': url,
}
return self.renderJsonResponse(request, self.get_form(), data=data)
class StockItemPrintLabels(AjaxView):
"""
View for printing labels and returning a PDF
Requires the following arguments to be passed as URL params:
items: List of valid StockItem pk values
label: Valid pk of a StockItemLabel template
"""
def get(self, request, *args, **kwargs):
label = request.GET.get('label', None)
try:
label = StockItemLabel.objects.get(pk=label)
except (ValueError, StockItemLabel.DoesNotExist):
raise ValidationError({'label': 'Invalid label ID'})
item_pks = request.GET.getlist('items[]')
items = []
for pk in item_pks:
try:
item = StockItem.objects.get(pk=pk)
items.append(item)
except (ValueError, StockItem.DoesNotExist):
pass
if len(items) == 0:
raise ValidationError({'items': 'Must provide valid stockitems'})
pdf = label.render(items).getbuffer()
return DownloadFile(pdf, 'stock_labels.pdf', content_type='application/pdf')
class StockItemDeleteTestData(AjaxUpdateView):
"""
View for deleting all test data