2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-17 04:25:42 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into extend-build-order

This commit is contained in:
2021-07-04 00:02:29 +02:00
237 changed files with 6341 additions and 3613 deletions

View File

@ -11,11 +11,12 @@ from rest_framework import generics
from django.conf.urls import url, include
from InvenTree.api import AttachmentMixin
from InvenTree.helpers import str2bool, isNull
from InvenTree.status_codes import BuildStatus
from .models import Build, BuildItem
from .serializers import BuildSerializer, BuildItemSerializer
from .models import Build, BuildItem, BuildOrderAttachment
from .serializers import BuildAttachmentSerializer, BuildSerializer, BuildItemSerializer
class BuildList(generics.ListCreateAPIView):
@ -228,14 +229,40 @@ class BuildItemList(generics.ListCreateAPIView):
]
build_item_api_urls = [
url('^.*$', BuildItemList.as_view(), name='api-build-item-list'),
]
class BuildAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
"""
API endpoint for listing (and creating) BuildOrderAttachment objects
"""
queryset = BuildOrderAttachment.objects.all()
serializer_class = BuildAttachmentSerializer
class BuildAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin):
"""
Detail endpoint for a BuildOrderAttachment object
"""
queryset = BuildOrderAttachment.objects.all()
serializer_class = BuildAttachmentSerializer
build_api_urls = [
url(r'^item/', include(build_item_api_urls)),
# Attachments
url(r'^attachment/', include([
url(r'^(?P<pk>\d+)/', BuildAttachmentDetail.as_view(), name='api-build-attachment-detail'),
url('^.*$', BuildAttachmentList.as_view(), name='api-build-attachment-list'),
])),
# Build Items
url(r'^item/', include([
url('^.*$', BuildItemList.as_view(), name='api-build-item-list')
])),
# Build Detail
url(r'^(?P<pk>\d+)/', BuildDetail.as_view(), name='api-build-detail'),
# Build List
url(r'^.*$', BuildList.as_view(), name='api-build-list'),
]

View File

@ -15,7 +15,7 @@ from InvenTree.fields import DatePickerFormField
from InvenTree.status_codes import StockStatus
from .models import Build, BuildItem, BuildOrderAttachment
from .models import Build, BuildItem
from stock.models import StockLocation, StockItem
@ -275,17 +275,3 @@ class EditBuildItemForm(HelperForm):
'quantity',
'install_into',
]
class EditBuildAttachmentForm(HelperForm):
"""
Form for creating / editing a BuildAttachment object
"""
class Meta:
model = BuildOrderAttachment
fields = [
'build',
'attachment',
'comment'
]

View File

@ -1,8 +1,13 @@
# Generated by Django 3.2 on 2021-06-01 05:25
import logging
from django.db import migrations
logger = logging.getLogger('inventree')
def assign_bom_items(apps, schema_editor):
"""
Run through existing BuildItem objects,
@ -13,7 +18,7 @@ def assign_bom_items(apps, schema_editor):
BomItem = apps.get_model('part', 'bomitem')
Part = apps.get_model('part', 'part')
print("Assigning BomItems to existing BuildItem objects")
logger.info("Assigning BomItems to existing BuildItem objects")
count_valid = 0
count_total = 0
@ -41,7 +46,7 @@ def assign_bom_items(apps, schema_editor):
pass
if count_total > 0:
print(f"Assigned BomItem for {count_valid}/{count_total} entries")
logger.info(f"Assigned BomItem for {count_valid}/{count_total} entries")
def unassign_bom_items(apps, schema_editor):

View File

@ -60,6 +60,10 @@ class Build(MPTTModel):
responsible: User (or group) responsible for completing the build
"""
@staticmethod
def get_api_url():
return reverse('api-build-list')
OVERDUE_FILTER = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
class Meta:
@ -1117,6 +1121,10 @@ class BuildItem(models.Model):
quantity: Number of units allocated
"""
@staticmethod
def get_api_url():
return reverse('api-build-item-list')
def get_absolute_url(self):
# TODO - Fix!
return '/build/item/{pk}/'.format(pk=self.id)

View File

@ -10,13 +10,13 @@ from django.db.models import BooleanField
from rest_framework import serializers
from InvenTree.serializers import InvenTreeModelSerializer, UserSerializerBrief
from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializerField, UserSerializerBrief
from stock.serializers import StockItemSerializerBrief
from stock.serializers import LocationSerializer
from part.serializers import PartSerializer, PartBriefSerializer
from .models import Build, BuildItem
from .models import Build, BuildItem, BuildOrderAttachment
class BuildSerializer(InvenTreeModelSerializer):
@ -148,3 +148,26 @@ class BuildItemSerializer(InvenTreeModelSerializer):
'stock_item_detail',
'quantity'
]
class BuildAttachmentSerializer(InvenTreeModelSerializer):
"""
Serializer for a BuildAttachment
"""
attachment = InvenTreeAttachmentSerializerField(required=True)
class Meta:
model = BuildOrderAttachment
fields = [
'pk',
'build',
'attachment',
'comment',
'upload_date',
]
read_only_fields = [
'upload_date',
]

View File

@ -22,7 +22,7 @@
enableDragAndDrop(
'#attachment-dropzone',
'{% url "build-attachment-create" %}',
'{% url "api-build-attachment-list" %}',
{
data: {
build: {{ build.id }},
@ -36,45 +36,49 @@ enableDragAndDrop(
// Callback for creating a new attachment
$('#new-attachment').click(function() {
launchModalForm(
'{% url "build-attachment-create" %}',
{
reload: true,
data: {
build: {{ build.pk }},
constructForm('{% url "api-build-attachment-list" %}', {
fields: {
attachment: {},
comment: {},
build: {
value: {{ build.pk }},
hidden: true,
}
}
);
},
method: 'POST',
onSuccess: reloadAttachmentTable,
title: '{% trans "Add Attachment" %}',
});
});
// Callback for editing an attachment
$("#attachment-table").on('click', '.attachment-edit-button', function() {
var pk = $(this).attr('pk');
loadAttachmentTable(
'{% url "api-build-attachment-list" %}',
{
filters: {
build: {{ build.pk }},
},
onEdit: function(pk) {
var url = `/api/build/attachment/${pk}/`;
var url = `/build/attachment/${pk}/edit/`;
constructForm(url, {
fields: {
comment: {},
},
onSuccess: reloadAttachmentTable,
title: '{% trans "Edit Attachment" %}',
});
},
onDelete: function(pk) {
launchModalForm(
url,
{
reload: true,
constructForm(`/api/build/attachment/${pk}/`, {
method: 'DELETE',
confirmMessage: '{% trans "Confirm Delete Operation" %}',
title: '{% trans "Delete Attachment" %}',
onSuccess: reloadAttachmentTable,
});
}
);
});
// Callback for deleting an attachment
$("#attachment-table").on('click', '.attachment-delete-button', function() {
var pk = $(this).attr('pk');
var url = `/build/attachment/${pk}/delete/`;
launchModalForm(
url,
{
reload: true,
}
);
});
$("#attachment-table").inventreeTable({});
}
);
{% endblock %}

View File

@ -36,12 +36,6 @@ build_urls = [
url('^new/', views.BuildItemCreate.as_view(), name='build-item-create'),
])),
url('^attachment/', include([
url('^new/', views.BuildAttachmentCreate.as_view(), name='build-attachment-create'),
url(r'^(?P<pk>\d+)/edit/', views.BuildAttachmentEdit.as_view(), name='build-attachment-edit'),
url(r'^(?P<pk>\d+)/delete/', views.BuildAttachmentDelete.as_view(), name='build-attachment-delete'),
])),
url(r'new/', views.BuildCreate.as_view(), name='build-create'),
url(r'^(?P<pk>\d+)/', include(build_detail_urls)),

View File

@ -12,7 +12,7 @@ from django.forms import HiddenInput
from django.urls import reverse
from part.models import Part
from .models import Build, BuildItem, BuildOrderAttachment
from .models import Build, BuildItem
from . import forms
from stock.models import StockLocation, StockItem
@ -1058,88 +1058,3 @@ class BuildItemEdit(AjaxUpdateView):
form.fields['install_into'].widget = HiddenInput()
return form
class BuildAttachmentCreate(AjaxCreateView):
"""
View for creating a BuildAttachment
"""
model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Add Build Order Attachment')
def save(self, form, **kwargs):
"""
Add information on the user that uploaded the attachment
"""
attachment = form.save(commit=False)
attachment.user = self.request.user
attachment.save()
def get_data(self):
return {
'success': _('Added attachment')
}
def get_initial(self):
"""
Get initial data for creating an attachment
"""
initials = super().get_initial()
try:
initials['build'] = Build.objects.get(pk=self.request.GET.get('build', -1))
except (ValueError, Build.DoesNotExist):
pass
return initials
def get_form(self):
"""
Hide the 'build' field if specified
"""
form = super().get_form()
form.fields['build'].widget = HiddenInput()
return form
class BuildAttachmentEdit(AjaxUpdateView):
"""
View for editing a BuildAttachment object
"""
model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Edit Attachment')
def get_form(self):
form = super().get_form()
form.fields['build'].widget = HiddenInput()
return form
def get_data(self):
return {
'success': _('Attachment updated')
}
class BuildAttachmentDelete(AjaxDeleteView):
"""
View for deleting a BuildAttachment
"""
model = BuildOrderAttachment
ajax_form_title = _('Delete Attachment')
context_object_name = 'attachment'
def get_data(self):
return {
'danger': _('Deleted attachment')
}