mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
787ab0a2e4
@ -17,3 +17,19 @@ class HelperForm(forms.ModelForm):
|
|||||||
self.helper = FormHelper()
|
self.helper = FormHelper()
|
||||||
|
|
||||||
self.helper.form_tag = False
|
self.helper.form_tag = False
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteForm(forms.Form):
|
||||||
|
""" Generic deletion form which provides simple user confirmation
|
||||||
|
"""
|
||||||
|
|
||||||
|
confirm_delete = forms.BooleanField(
|
||||||
|
required=False,
|
||||||
|
initial=False,
|
||||||
|
help_text='Confirm item deletion'
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = [
|
||||||
|
'confirm_delete'
|
||||||
|
]
|
||||||
|
@ -12,11 +12,14 @@ from django.template.loader import render_to_string
|
|||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
|
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import UpdateView, CreateView, DeleteView
|
from django.views.generic import UpdateView, CreateView
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
|
|
||||||
|
from .forms import DeleteForm
|
||||||
|
from .helpers import str2bool
|
||||||
|
|
||||||
from rest_framework import views
|
from rest_framework import views
|
||||||
|
|
||||||
|
|
||||||
@ -116,7 +119,7 @@ class AjaxMixin(object):
|
|||||||
"""
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def renderJsonResponse(self, request, form=None, data={}, context={}):
|
def renderJsonResponse(self, request, form=None, data={}, context=None):
|
||||||
""" Render a JSON response based on specific class context.
|
""" Render a JSON response based on specific class context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -129,6 +132,12 @@ class AjaxMixin(object):
|
|||||||
JSON response object
|
JSON response object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if context is None:
|
||||||
|
try:
|
||||||
|
context = self.get_context_data()
|
||||||
|
except AttributeError:
|
||||||
|
context = {}
|
||||||
|
|
||||||
if form:
|
if form:
|
||||||
context['form'] = form
|
context['form'] = form
|
||||||
|
|
||||||
@ -294,13 +303,28 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
|
|||||||
return self.renderJsonResponse(request, form, data)
|
return self.renderJsonResponse(request, form, data)
|
||||||
|
|
||||||
|
|
||||||
class AjaxDeleteView(AjaxMixin, DeleteView):
|
class AjaxDeleteView(AjaxMixin, UpdateView):
|
||||||
|
|
||||||
""" An 'AJAXified DeleteView for removing an object from the DB
|
""" An 'AJAXified DeleteView for removing an object from the DB
|
||||||
- Returns a HTML object (not a form!) in JSON format (for delivery to a modal window)
|
- Returns a HTML object (not a form!) in JSON format (for delivery to a modal window)
|
||||||
- Handles deletion
|
- Handles deletion
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
form_class = DeleteForm
|
||||||
|
ajax_form_title = "Delete Item"
|
||||||
|
ajax_template_name = "modal_delete_form.html"
|
||||||
|
context_object_name = 'item'
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
try:
|
||||||
|
self.object = self.model.objects.get(pk=self.kwargs['pk'])
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
return self.object
|
||||||
|
|
||||||
|
def get_form(self):
|
||||||
|
return self.form_class(self.get_form_kwargs())
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
""" Respond to GET request
|
""" Respond to GET request
|
||||||
|
|
||||||
@ -308,19 +332,15 @@ class AjaxDeleteView(AjaxMixin, DeleteView):
|
|||||||
- Return rendered form to client
|
- Return rendered form to client
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super(DeleteView, self).get(request, *args, **kwargs)
|
super(UpdateView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
data = {
|
form = self.get_form()
|
||||||
'id': self.get_object().id,
|
|
||||||
'delete': False,
|
|
||||||
'title': self.ajax_form_title,
|
|
||||||
'html_data': render_to_string(
|
|
||||||
self.ajax_template_name,
|
|
||||||
self.get_context_data(),
|
|
||||||
request=request)
|
|
||||||
}
|
|
||||||
|
|
||||||
return JsonResponse(data)
|
context = self.get_context_data()
|
||||||
|
|
||||||
|
context[self.context_object_name] = self.get_object()
|
||||||
|
|
||||||
|
return self.renderJsonResponse(request, form, context=context)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
""" Respond to POST request
|
""" Respond to POST request
|
||||||
@ -331,14 +351,24 @@ class AjaxDeleteView(AjaxMixin, DeleteView):
|
|||||||
|
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
pk = obj.id
|
pk = obj.id
|
||||||
|
|
||||||
|
form = self.get_form()
|
||||||
|
|
||||||
|
confirmed = str2bool(request.POST.get('confirm_delete', False))
|
||||||
|
context = self.get_context_data()
|
||||||
|
|
||||||
|
if confirmed:
|
||||||
obj.delete()
|
obj.delete()
|
||||||
|
else:
|
||||||
|
form.errors['confirm_delete'] = ['Check box to confirm item deletion']
|
||||||
|
context[self.context_object_name] = self.get_object()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'id': pk,
|
'id': pk,
|
||||||
'delete': True
|
'form_valid': confirmed
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.renderJsonResponse(request, data=data)
|
return self.renderJsonResponse(request, form, data=data, context=context)
|
||||||
|
|
||||||
|
|
||||||
class IndexView(TemplateView):
|
class IndexView(TemplateView):
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
Are you sure you want to unallocate these parts?
|
Are you sure you want to unallocate these parts?
|
||||||
<br>
|
<br>
|
||||||
This will remove {{ item.quantity }} parts from build '{{ item.build.title }}'.
|
This will remove {{ item.quantity }} parts from build '{{ item.build.title }}'.
|
||||||
|
{% endblock %}
|
@ -1,3 +1,7 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
|
|
||||||
Are you sure you want to delete company '{{ company.name }}'?
|
Are you sure you want to delete company '{{ company.name }}'?
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@ -11,3 +15,5 @@ If this supplier is deleted, these supplier part entries will also be deleted.</
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -54,7 +54,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#delete-company').click(function() {
|
$('#delete-company').click(function() {
|
||||||
launchDeleteForm(
|
launchModalForm(
|
||||||
"{% url 'company-delete' company.id %}",
|
"{% url 'company-delete' company.id %}",
|
||||||
{
|
{
|
||||||
redirect: "{% url 'company-index' %}"
|
redirect: "{% url 'company-index' %}"
|
||||||
|
@ -1 +1,5 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
Are you sure you want to delete this supplier part?
|
Are you sure you want to delete this supplier part?
|
||||||
|
{% endblock %}
|
@ -109,7 +109,7 @@ InvenTree | {{ company.name }} - Parts
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#delete-part').click(function() {
|
$('#delete-part').click(function() {
|
||||||
launchDeleteForm(
|
launchModalForm(
|
||||||
"{% url 'supplier-part-delete' part.id %}",
|
"{% url 'supplier-part-delete' part.id %}",
|
||||||
{
|
{
|
||||||
redirect: "{% url 'company-index' %}"
|
redirect: "{% url 'company-index' %}"
|
||||||
|
@ -93,10 +93,12 @@ class CompanyCreate(AjaxCreateView):
|
|||||||
|
|
||||||
class CompanyDelete(AjaxDeleteView):
|
class CompanyDelete(AjaxDeleteView):
|
||||||
""" View for deleting a Company object """
|
""" View for deleting a Company object """
|
||||||
|
|
||||||
model = Company
|
model = Company
|
||||||
success_url = '/company/'
|
success_url = '/company/'
|
||||||
ajax_template_name = 'company/delete.html'
|
ajax_template_name = 'company/delete.html'
|
||||||
ajax_form_title = 'Delete Company'
|
ajax_form_title = 'Delete Company'
|
||||||
|
context_object_name = 'company'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
|
@ -75,11 +75,20 @@ class EditPartAttachmentForm(HelperForm):
|
|||||||
class EditPartForm(HelperForm):
|
class EditPartForm(HelperForm):
|
||||||
""" Form for editing a Part object """
|
""" Form for editing a Part object """
|
||||||
|
|
||||||
confirm_creation = forms.BooleanField(required=False, initial=False, help_text='Confirm part creation', widget=forms.HiddenInput())
|
deep_copy = forms.BooleanField(required=False,
|
||||||
|
initial=True,
|
||||||
|
help_text="Perform 'deep copy' which will duplicate all BOM data for this part",
|
||||||
|
widget=forms.HiddenInput())
|
||||||
|
|
||||||
|
confirm_creation = forms.BooleanField(required=False,
|
||||||
|
initial=False,
|
||||||
|
help_text='Confirm part creation',
|
||||||
|
widget=forms.HiddenInput())
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Part
|
model = Part
|
||||||
fields = [
|
fields = [
|
||||||
|
'deep_copy',
|
||||||
'confirm_creation',
|
'confirm_creation',
|
||||||
'category',
|
'category',
|
||||||
'name',
|
'name',
|
||||||
|
@ -16,6 +16,7 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
|
|
||||||
@ -533,6 +534,33 @@ class Part(models.Model):
|
|||||||
""" Return the number of supplier parts available for this part """
|
""" Return the number of supplier parts available for this part """
|
||||||
return self.supplier_parts.count()
|
return self.supplier_parts.count()
|
||||||
|
|
||||||
|
def deepCopy(self, other, **kwargs):
|
||||||
|
""" Duplicates non-field data from another part.
|
||||||
|
Does not alter the normal fields of this part,
|
||||||
|
but can be used to copy other data linked by ForeignKey refernce.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
image: If True, copies Part image (default = True)
|
||||||
|
bom: If True, copies BOM data (default = False)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Copy the part image
|
||||||
|
if kwargs.get('image', True):
|
||||||
|
image_file = ContentFile(other.image.read())
|
||||||
|
image_file.name = rename_part_image(self, 'test.png')
|
||||||
|
|
||||||
|
self.image = image_file
|
||||||
|
|
||||||
|
# Copy the BOM data
|
||||||
|
if kwargs.get('bom', False):
|
||||||
|
for item in other.bom_items.all():
|
||||||
|
# Point the item to THIS part
|
||||||
|
item.part = self
|
||||||
|
item.pk = None
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
def export_bom(self, **kwargs):
|
def export_bom(self, **kwargs):
|
||||||
|
|
||||||
data = tablib.Dataset(headers=[
|
data = tablib.Dataset(headers=[
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
Are you sure you wish to delete this attachment?
|
Are you sure you wish to delete this attachment?
|
||||||
<br>
|
<br>
|
||||||
This will remove the file '{{ attachment.basename }}'.
|
This will remove the file '{{ attachment.basename }}'.
|
||||||
|
{% endblock %}
|
@ -62,7 +62,7 @@
|
|||||||
$("#attachment-table").on('click', '.attachment-delete-button', function() {
|
$("#attachment-table").on('click', '.attachment-delete-button', function() {
|
||||||
var button = $(this);
|
var button = $(this);
|
||||||
|
|
||||||
launchDeleteForm(button.attr('url'), {
|
launchModalForm(button.attr('url'), {
|
||||||
success: function() {
|
success: function() {
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
|
|
||||||
Are you sure you want to delete this BOM item?
|
Are you sure you want to delete this BOM item?
|
||||||
<br>
|
<br>
|
||||||
Deleting this entry will remove the BOM row from the following part:
|
Deleting this entry will remove the BOM row from the following part:
|
||||||
@ -7,3 +11,5 @@ Deleting this entry will remove the BOM row from the following part:
|
|||||||
<b>{{ item.part.full_name }}</b> - <i>{{ item.part.description }}</i>
|
<b>{{ item.part.full_name }}</b> - <i>{{ item.part.description }}</i>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -111,7 +111,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
$('#cat-delete').click(function() {
|
$('#cat-delete').click(function() {
|
||||||
launchDeleteForm("{% url 'category-delete' category.id %}",
|
launchModalForm("{% url 'category-delete' category.id %}",
|
||||||
{
|
{
|
||||||
redirect: redirect
|
redirect: redirect
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
Are you sure you want to delete category '{{ category.name }}'?
|
Are you sure you want to delete category '{{ category.name }}'?
|
||||||
|
|
||||||
{% if category.children.all|length > 0 %}
|
{% if category.children.all|length > 0 %}
|
||||||
@ -31,3 +34,5 @@ the top level 'Parts' category.
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
24
InvenTree/part/templates/part/copy_part.html
Normal file
24
InvenTree/part/templates/part/copy_part.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{% extends "modal_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
|
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
<div class='alert alert-info alert-block'>
|
||||||
|
<b>Duplicate Part</b><br>
|
||||||
|
Make a copy of part '{{ part.full_name }}'.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if matches %}
|
||||||
|
<b>Possible Matching Parts</b>
|
||||||
|
<p>The new part may be a duplicate of these existing parts:</p>
|
||||||
|
<ul class='list-group'>
|
||||||
|
{% for match in matches %}
|
||||||
|
<li class='list-group-item list-group-item-condensed'>
|
||||||
|
{{ match.part.full_name }} - <i>{{ match.part.description }}</i> ({{ match.ratio }}%)
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -14,8 +14,8 @@
|
|||||||
<span class="caret"></span></button>
|
<span class="caret"></span></button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% if part.active %}
|
{% if part.active %}
|
||||||
<li><a href='#' id='duplicate-part' title='Duplicate Part'>Duplicate</a></li>
|
|
||||||
<li><a href="#" id='edit-part' title='Edit part'>Edit</a></li>
|
<li><a href="#" id='edit-part' title='Edit part'>Edit</a></li>
|
||||||
|
<li><a href='#' id='duplicate-part' title='Duplicate Part'>Duplicate</a></li>
|
||||||
<hr>
|
<hr>
|
||||||
<li><a href="#" id='deactivate-part' title='Deactivate part'>Deactivate</a></li>
|
<li><a href="#" id='deactivate-part' title='Deactivate part'>Deactivate</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -131,12 +131,9 @@
|
|||||||
|
|
||||||
$("#duplicate-part").click(function() {
|
$("#duplicate-part").click(function() {
|
||||||
launchModalForm(
|
launchModalForm(
|
||||||
"{% url 'part-create' %}",
|
"{% url 'part-duplicate' part.id %}",
|
||||||
{
|
{
|
||||||
follow: true,
|
follow: true,
|
||||||
data: {
|
|
||||||
copy: {{ part.id }},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -196,7 +193,7 @@
|
|||||||
|
|
||||||
|
|
||||||
$('#delete-part').click(function() {
|
$('#delete-part').click(function() {
|
||||||
launchDeleteForm(
|
launchModalForm(
|
||||||
"{% url 'part-delete' part.id %}",
|
"{% url 'part-delete' part.id %}",
|
||||||
{
|
{
|
||||||
redirect: {% if part.category %}"{% url 'category-detail' part.category.id %}"{% else %}"{% url 'part-index' %}"{% endif %}
|
redirect: {% if part.category %}"{% url 'category-detail' part.category.id %}"{% else %}"{% url 'part-index' %}"{% endif %}
|
||||||
|
@ -36,6 +36,7 @@ part_detail_urls = [
|
|||||||
url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'),
|
url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'),
|
||||||
url(r'^bom-export/?', views.BomDownload.as_view(), name='bom-export'),
|
url(r'^bom-export/?', views.BomDownload.as_view(), name='bom-export'),
|
||||||
url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'),
|
url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'),
|
||||||
|
url(r'^duplicate/', views.PartDuplicate.as_view(), name='part-duplicate'),
|
||||||
|
|
||||||
url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'),
|
url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'),
|
||||||
url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'),
|
url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'),
|
||||||
|
@ -124,13 +124,122 @@ class PartAttachmentDelete(AjaxDeleteView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PartDuplicate(AjaxCreateView):
|
||||||
|
""" View for duplicating an existing Part object.
|
||||||
|
|
||||||
|
- Part <pk> is provided in the URL '/part/<pk>/copy/'
|
||||||
|
- Option for 'deep-copy' which will duplicate all BOM items (default = True)
|
||||||
|
"""
|
||||||
|
|
||||||
|
model = Part
|
||||||
|
form_class = part_forms.EditPartForm
|
||||||
|
|
||||||
|
ajax_form_title = "Duplicate Part"
|
||||||
|
ajax_template_name = "part/copy_part.html"
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
return {
|
||||||
|
'success': 'Copied part'
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_part_to_copy(self):
|
||||||
|
try:
|
||||||
|
return Part.objects.get(id=self.kwargs['pk'])
|
||||||
|
except Part.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_context_data(self):
|
||||||
|
return {
|
||||||
|
'part': self.get_part_to_copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_form(self):
|
||||||
|
form = super(AjaxCreateView, self).get_form()
|
||||||
|
|
||||||
|
# Force display of the 'deep_copy' widget
|
||||||
|
form.fields['deep_copy'].widget = CheckboxInput()
|
||||||
|
|
||||||
|
return form
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
""" Capture the POST request for part duplication
|
||||||
|
|
||||||
|
- If the deep_copy object is set, copy all the BOM items too!
|
||||||
|
"""
|
||||||
|
|
||||||
|
form = self.get_form()
|
||||||
|
|
||||||
|
context = self.get_context_data()
|
||||||
|
|
||||||
|
valid = form.is_valid()
|
||||||
|
|
||||||
|
name = request.POST.get('name', None)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
matches = match_part_names(name)
|
||||||
|
|
||||||
|
if len(matches) > 0:
|
||||||
|
context['matches'] = matches
|
||||||
|
|
||||||
|
# Enforce display of the checkbox
|
||||||
|
form.fields['confirm_creation'].widget = CheckboxInput()
|
||||||
|
|
||||||
|
# Check if the user has checked the 'confirm_creation' input
|
||||||
|
confirmed = str2bool(request.POST.get('confirm_creation', False))
|
||||||
|
|
||||||
|
if not confirmed:
|
||||||
|
form.errors['confirm_creation'] = ['Possible matches exist - confirm creation of new part']
|
||||||
|
|
||||||
|
form.pre_form_warning = 'Possible matches exist - confirm creation of new part'
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'form_valid': valid
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
# Create the new Part
|
||||||
|
part = form.save()
|
||||||
|
|
||||||
|
data['pk'] = part.pk
|
||||||
|
|
||||||
|
deep_copy = str2bool(request.POST.get('deep_copy', False))
|
||||||
|
|
||||||
|
original = self.get_part_to_copy()
|
||||||
|
|
||||||
|
if original:
|
||||||
|
part.deepCopy(original, bom=deep_copy)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data['url'] = part.get_absolute_url()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return self.renderJsonResponse(request, form, data, context=context)
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
""" Get initial data based on the Part to be copied from.
|
||||||
|
"""
|
||||||
|
|
||||||
|
part = self.get_part_to_copy()
|
||||||
|
|
||||||
|
if part:
|
||||||
|
initials = model_to_dict(part)
|
||||||
|
else:
|
||||||
|
initials = super(AjaxCreateView, self).get_initial()
|
||||||
|
|
||||||
|
return initials
|
||||||
|
|
||||||
|
|
||||||
class PartCreate(AjaxCreateView):
|
class PartCreate(AjaxCreateView):
|
||||||
""" View for creating a new Part object.
|
""" View for creating a new Part object.
|
||||||
|
|
||||||
Options for providing initial conditions:
|
Options for providing initial conditions:
|
||||||
|
|
||||||
- Provide a category object as initial data
|
- Provide a category object as initial data
|
||||||
- Copy an existing Part
|
|
||||||
"""
|
"""
|
||||||
model = Part
|
model = Part
|
||||||
form_class = part_forms.EditPartForm
|
form_class = part_forms.EditPartForm
|
||||||
@ -224,21 +333,8 @@ class PartCreate(AjaxCreateView):
|
|||||||
""" Get initial data for the new Part object:
|
""" Get initial data for the new Part object:
|
||||||
|
|
||||||
- If a category is provided, pre-fill the Category field
|
- If a category is provided, pre-fill the Category field
|
||||||
- If 'copy' parameter is provided, copy from referenced Part
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Is the client attempting to copy an existing part?
|
|
||||||
part_to_copy = self.request.GET.get('copy', None)
|
|
||||||
|
|
||||||
if part_to_copy:
|
|
||||||
try:
|
|
||||||
original = Part.objects.get(pk=part_to_copy)
|
|
||||||
initials = model_to_dict(original)
|
|
||||||
self.ajax_form_title = "Copy Part '{p}'".format(p=original.name)
|
|
||||||
except Part.DoesNotExist:
|
|
||||||
initials = super(PartCreate, self).get_initial()
|
|
||||||
|
|
||||||
else:
|
|
||||||
initials = super(PartCreate, self).get_initial()
|
initials = super(PartCreate, self).get_initial()
|
||||||
|
|
||||||
if self.get_category_id():
|
if self.get_category_id():
|
||||||
@ -708,3 +804,4 @@ class SupplierPartDelete(AjaxDeleteView):
|
|||||||
success_url = '/supplier/'
|
success_url = '/supplier/'
|
||||||
ajax_template_name = 'company/partdelete.html'
|
ajax_template_name = 'company/partdelete.html'
|
||||||
ajax_form_title = 'Delete Supplier Part'
|
ajax_form_title = 'Delete Supplier Part'
|
||||||
|
context_object_name = 'supplier_part'
|
||||||
|
@ -162,6 +162,10 @@
|
|||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.js-modal-form .checkbox {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
width: 45%;
|
width: 45%;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ function loadBomTable(table, options) {
|
|||||||
table.on('click', '.bom-delete-button', function() {
|
table.on('click', '.bom-delete-button', function() {
|
||||||
var button = $(this);
|
var button = $(this);
|
||||||
|
|
||||||
launchDeleteForm(button.attr('url'), {
|
launchModalForm(button.attr('url'), {
|
||||||
success: function() {
|
success: function() {
|
||||||
reloadBomTable(table);
|
reloadBomTable(table);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ function loadAllocationTable(table, part_id, part, url, required, button) {
|
|||||||
table.on('click', '.item-del-button', function() {
|
table.on('click', '.item-del-button', function() {
|
||||||
var button = $(this);
|
var button = $(this);
|
||||||
|
|
||||||
launchDeleteForm(button.attr('url'), {
|
launchModalForm(button.attr('url'), {
|
||||||
success: function() {
|
success: function() {
|
||||||
table.bootstrapTable('refresh');
|
table.bootstrapTable('refresh');
|
||||||
}
|
}
|
||||||
|
@ -345,68 +345,6 @@ function openModal(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function launchDeleteForm(url, options = {}) {
|
|
||||||
/* Launch a modal form to delete an object
|
|
||||||
*/
|
|
||||||
|
|
||||||
var modal = options.modal || '#modal-delete';
|
|
||||||
|
|
||||||
$(modal).on('shown.bs.modal', function() {
|
|
||||||
$(modal + ' .modal-form-content').scrollTop(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Un-bind any attached click listeners
|
|
||||||
$(modal).off('click', '#modal-form-delete');
|
|
||||||
|
|
||||||
// Request delete form data
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
type: 'get',
|
|
||||||
dataType: 'json',
|
|
||||||
beforeSend: function() {
|
|
||||||
openModal({modal: modal});
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
if (response.title) {
|
|
||||||
modalSetTitle(modal, response.title);
|
|
||||||
}
|
|
||||||
if (response.html_data) {
|
|
||||||
modalSetContent(modal, response.html_data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
$(modal).modal('hide');
|
|
||||||
showAlertDialog('Invalid form response', 'JSON response missing HTML data');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (xhr, ajaxOptions, thrownError) {
|
|
||||||
$(modal).modal('hide');
|
|
||||||
showAlertDialog('Error requesting form data', renderErrorMessage(xhr));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(modal).on('click', '#modal-form-delete', function() {
|
|
||||||
|
|
||||||
var form = $(modal).find('#delete-form');
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
data: form.serialize(),
|
|
||||||
type: 'post',
|
|
||||||
dataType: 'json',
|
|
||||||
success: function (response) {
|
|
||||||
$(modal).modal('hide');
|
|
||||||
afterForm(response, options);
|
|
||||||
},
|
|
||||||
error: function (xhr, ajaxOptions, thrownError) {
|
|
||||||
$(modal).modal('hide');
|
|
||||||
showAlertDialog('Error deleting item', renderErrorMessage(xhr));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function injectModalForm(modal, form_html) {
|
function injectModalForm(modal, form_html) {
|
||||||
/* Inject form content into the modal.
|
/* Inject form content into the modal.
|
||||||
* Updates the HTML of the form content, and then applies some other updates
|
* Updates the HTML of the form content, and then applies some other updates
|
||||||
|
@ -194,7 +194,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
$("#stock-delete").click(function () {
|
$("#stock-delete").click(function () {
|
||||||
launchDeleteForm(
|
launchModalForm(
|
||||||
"{% url 'stock-item-delete' item.id %}",
|
"{% url 'stock-item-delete' item.id %}",
|
||||||
{
|
{
|
||||||
redirect: "{% url 'part-stock' item.part.id %}"
|
redirect: "{% url 'part-stock' item.part.id %}"
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
|
|
||||||
|
<div class='alert alert-danger alert-block'>
|
||||||
Are you sure you want to delete this stock item?
|
Are you sure you want to delete this stock item?
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
This will remove <b>{{ item.quantity }}</b> units of <b>{{ item.part.full_name }}</b> from stock.
|
This will remove <b>{{ item.quantity }}</b> units of <b>{{ item.part.full_name }}</b> from stock.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -97,7 +97,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#location-delete').click(function() {
|
$('#location-delete').click(function() {
|
||||||
launchDeleteForm("{% url 'stock-location-delete' location.id %}",
|
launchModalForm("{% url 'stock-location-delete' location.id %}",
|
||||||
{
|
{
|
||||||
redirect: "{% url 'stock-index' %}"
|
redirect: "{% url 'stock-index' %}"
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
{% extends "modal_delete_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
Are you sure you want to delete stock location '{{ location.name }}'?
|
Are you sure you want to delete stock location '{{ location.name }}'?
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@ -34,3 +37,4 @@ If this location is deleted, these items will be moved to the top level 'Stock'
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
1
InvenTree/templates/modal_delete_form.html
Normal file
1
InvenTree/templates/modal_delete_form.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
{% extends "modal_form.html" %}
|
@ -1,6 +1,6 @@
|
|||||||
<div>
|
<div>
|
||||||
{% if form.pre_form_info %}
|
{% if form.pre_form_info %}
|
||||||
<div class='alert alert-info' role='alert' style='display: block;'>
|
<div class='alert alert-info alert-block' role='alert'>
|
||||||
{{ form.pre_form_info }}
|
{{ form.pre_form_info }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user