summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2020-03-06 11:41:54 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2020-03-06 11:44:44 +0100
commit3808df22596ff03e8b24c9b97506f68c86197c60 (patch)
tree87dc15b6b07b78eb8aed52a707c9adab5ae89a9f /ishtar_common
parent2ebb25f9a93d9b840162ca035c243354a3169a87 (diff)
downloadIshtar-3808df22596ff03e8b24c9b97506f68c86197c60.tar.bz2
Ishtar-3808df22596ff03e8b24c9b97506f68c86197c60.zip
Sheet actions: add duplicate for site, operation, document and context record
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms_common.py68
-rw-r--r--ishtar_common/models.py79
-rw-r--r--ishtar_common/templates/ishtar/forms/qa_document_duplicate.html95
-rw-r--r--ishtar_common/templates/ishtar/sheet_document.html2
-rw-r--r--ishtar_common/urls.py4
-rw-r--r--ishtar_common/views.py26
6 files changed, 245 insertions, 29 deletions
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 7a6f2fe72..31eb5c7d2 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -1302,9 +1302,9 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
not cleaned_data.get('image', None) and \
not cleaned_data.get('associated_file', None) and \
not cleaned_data.get('associated_url', None):
- raise forms.ValidationError(_(u"You should at least fill one of "
- u"this field: title, url, image or "
- u"file."))
+ raise forms.ValidationError(_("You should at least fill one of "
+ "this field: title, url, image or "
+ "file."))
for rel in models.Document.RELATED_MODELS:
if cleaned_data.get(rel, None):
return cleaned_data
@@ -1477,6 +1477,68 @@ class QADocumentFormMulti(QAForm):
return value
+class QADocumentDuplicateForm(IshtarForm):
+ qa_title = forms.CharField(label=_("Reference"), max_length=500,
+ required=False)
+ qa_source_type = forms.ChoiceField(label=_("Type"), choices=[],
+ required=False)
+
+ TYPES = [
+ FieldType('qa_source_type', models.SourceType),
+ ]
+
+ def __init__(self, *args, **kwargs):
+ self.user = None
+ if 'user' in kwargs:
+ self.user = kwargs.pop('user')
+ if hasattr(self.user, 'ishtaruser'):
+ self.user = self.user.ishtaruser
+ self.document = kwargs.pop('items')[0]
+ super(QADocumentDuplicateForm, self).__init__(*args, **kwargs)
+
+ self.fields['qa_title'].initial = self.document.title + str(
+ _(" - duplicate"))
+ if self.document.source_type:
+ self.fields['qa_source_type'].initial = self.document.source_type.pk
+
+ for related_key in models.Document.RELATED_MODELS_ALT:
+ related = getattr(self.document, related_key)
+ if not related.count():
+ continue
+ model = models.Document._meta.get_field(related_key).related_model
+ initial = []
+ for item in related.all():
+ initial.append(item.pk)
+ self.fields["qa_" + related_key] = widgets.Select2MultipleField(
+ model=model, remote=True, label=model._meta.verbose_name_plural,
+ required=False, long_widget=True, initial=initial
+ )
+
+ def save(self):
+ data = {"index": None}
+ for k in ["title"]:
+ data[k] = self.cleaned_data.get("qa_" + k, None)
+ if self.cleaned_data.get("qa_source_type", None):
+ try:
+ data["source_type"] = models.SourceType.objects.get(
+ pk=int(self.cleaned_data["qa_source_type"]), available=True)
+ except models.SourceType.DoesNotExist:
+ return
+ new = self.document.duplicate_item(self.user, data=data)
+ for related_key in models.Document.RELATED_MODELS_ALT:
+ getattr(new, related_key).clear()
+ values = self.cleaned_data.get("qa_" + related_key, [])
+ model = models.Document._meta.get_field(related_key).related_model
+ for value in values:
+ getattr(new, related_key).add(model.objects.get(pk=value))
+ new.skip_history_when_saving = True
+ new._cached_label_checked = False
+ new._search_updated = False
+ new._no_move = True
+ new.save() # regen of labels
+ return new
+
+
class QALockForm(forms.Form):
action = forms.ChoiceField(
label=_("Action"), choices=(('lock', _("Lock")),
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 7238d7782..dc2fef815 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -1212,7 +1212,7 @@ class HistoryError(Exception):
return repr(self.value)
-PRIVATE_FIELDS = ('id', 'history_modifier', 'order')
+PRIVATE_FIELDS = ('id', 'history_modifier', 'order', 'uuid')
class BulkUpdatedItem(object):
@@ -2127,6 +2127,34 @@ class CascasdeUpdate:
post_save_geo(item.__class__, instance=item)
+def duplicate_item(item, user=None, data=None):
+ model = item.__class__
+ new = model.objects.get(pk=item.pk)
+
+ for field in model._meta.fields:
+ # pk is in PRIVATE_FIELDS so: new.pk = None and a new
+ # item will be created on save
+ if field.name == "uuid":
+ new.uuid = uuid.uuid4()
+ elif field.name in PRIVATE_FIELDS:
+ setattr(new, field.name, None)
+ if user:
+ new.history_user = user
+ if data:
+ for k in data:
+ setattr(new, k, data[k])
+ new.save()
+
+ # m2m fields
+ m2m = [field.name for field in model._meta.many_to_many
+ if field.name not in PRIVATE_FIELDS]
+ for field in m2m:
+ for val in getattr(item, field).all():
+ if val not in getattr(new, field).all():
+ getattr(new, field).add(val)
+ return new
+
+
class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
JsonData, FixAssociated, CascasdeUpdate):
"""
@@ -2194,29 +2222,7 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
return {}
def duplicate(self, user=None, data=None):
- model = self.__class__
- new = model.objects.get(pk=self.pk)
-
- for field in model._meta.fields:
- # pk is in PRIVATE_FIELDS so: new.pk = None and a new
- # item will be created on save
- if field.name in PRIVATE_FIELDS:
- setattr(new, field.name, None)
- if user:
- new.history_user = user
- if data:
- for k in data:
- setattr(new, k, data[k])
- new.save()
-
- # m2m fields
- m2m = [field.name for field in model._meta.many_to_many
- if field.name not in PRIVATE_FIELDS]
- for field in m2m:
- for val in getattr(self, field).all():
- if val not in getattr(new, field).all():
- getattr(new, field).add(val)
- return new
+ return duplicate_item(self, user, data)
def update_external_id(self, save=False):
if not self.EXTERNAL_ID_KEY or (
@@ -5233,7 +5239,12 @@ class Document(BaseHistorizedItem, QRCodeItem, OwnPerms, ImageModel,
text=_(u"Bulk update"), target="many",
rights=['change_document', 'change_own_document'])
QUICK_ACTIONS = [
- QA_EDIT
+ QA_EDIT,
+ QuickAction(
+ url="document-qa-duplicate", icon_class="fa fa-clone",
+ text=_("Duplicate"), target="one",
+ rights=['change_document',
+ 'change_own_document']),
]
SERIALIZATION_FILES = ["image", "thumbnail", "associated_file"]
@@ -5321,6 +5332,8 @@ class Document(BaseHistorizedItem, QRCodeItem, OwnPerms, ImageModel,
return "{}-{:04d}".format(self.operation.code_patriarche or '',
self.index)
"""
+ def duplicate_item(self, user=None, data=None):
+ return duplicate_item(self, user, data)
def public_representation(self):
site = Site.objects.get_current()
@@ -5352,6 +5365,22 @@ class Document(BaseHistorizedItem, QRCodeItem, OwnPerms, ImageModel,
"thumbnail": thumbnail,
}
+ def get_extra_actions(self, request):
+ """
+ For sheet template
+ """
+ # url, base_text, icon, extra_text, extra css class, is a quick action
+ actions = super(Document, self).get_extra_actions(request)
+ # is_locked = self.is_locked(request.user)
+
+ can_edit_document = self.can_do(request, 'change_document')
+ if can_edit_document:
+ actions += [
+ (reverse("document-qa-duplicate", args=[self.pk]),
+ _("Duplicate"), "fa fa-clone", "", "", True),
+ ]
+ return actions
+
@property
def thumbnail_path(self):
if not self.thumbnail:
diff --git a/ishtar_common/templates/ishtar/forms/qa_document_duplicate.html b/ishtar_common/templates/ishtar/forms/qa_document_duplicate.html
new file mode 100644
index 000000000..4dc04d15d
--- /dev/null
+++ b/ishtar_common/templates/ishtar/forms/qa_document_duplicate.html
@@ -0,0 +1,95 @@
+{% extends "ishtar/forms/qa_base.html" %}
+{% load i18n inline_formset table_form %}
+
+{% block main_form %}
+{% if form.non_field_errors %}
+<div class="alert alert-danger" role="alert">
+ {{form.non_field_errors}}
+</div>
+{% endif %}
+{% with force_large_col=True %}
+<div class="form-row">
+ {% with form.qa_title as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+<div class="form-row">
+ {% with form.qa_source_type as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endwith %}
+
+{% if form.qa_finds %}
+<div class="form-row">
+ {% with form.qa_finds as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_context_records %}
+<div class="form-row">
+ {% with form.qa_context_records as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_operations %}
+<div class="form-row">
+ {% with form.qa_operations as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_sites %}
+<div class="form-row">
+ {% with form.qa_sites as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_files %}
+<div class="form-row">
+ {% with form.qa_files as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_warehouses %}
+<div class="form-row">
+ {% with form.qa_warehouses as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_containers %}
+<div class="form-row">
+ {% with form.qa_containers as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_treatments %}
+<div class="form-row">
+ {% with form.qa_treatments as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% if form.qa_files %}
+<div class="form-row">
+ {% with form.qa_treatment_files as field %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endwith %}
+</div>
+{% endif %}
+
+{% endblock %}
diff --git a/ishtar_common/templates/ishtar/sheet_document.html b/ishtar_common/templates/ishtar/sheet_document.html
index 386b33a8a..93951c056 100644
--- a/ishtar_common/templates/ishtar/sheet_document.html
+++ b/ishtar_common/templates/ishtar/sheet_document.html
@@ -37,7 +37,7 @@
{% field_flex "Creation date" item.creation_date %}
{% field_flex "Receipt date" item.receipt_date %}
{% field_flex "Receipt date in documentation" item.receipt_date_in_documentation %}
- {% field_flex "Has a duplicate" item.duplicate %}
+ {% if item.duplicate %}{% field_flex "Has a duplicate" item.duplicate %}{% endif %}
{% field_flex "Description" item.description %}
{% field_flex "Comment" item.comment %}
{% field_flex "Additional information" item.additional_information %}
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index 8c08ade06..cc8d3eed4 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -319,6 +319,10 @@ urlpatterns += [
check_rights(['change_document', 'change_own_document'])(
views.QADocumentForm.as_view()),
name='document-qa-bulk-update-confirm', kwargs={"confirm": True}),
+ url(r'^document-qa-duplicate/(?P<pks>[0-9-]+)?/$',
+ check_rights(['change_document', 'change_own_document'])(
+ views.QADocumentDuplicateFormView.as_view()),
+ name='document-qa-duplicate'),
url(r'^qa-not-available(?:/(?P<context>[0-9a-z-]+))?/$',
views.QANotAvailable.as_view(), name='qa-not-available'),
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 3563ac9db..4724d61b7 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -2264,6 +2264,8 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
# check availability
quick_action = self.get_quick_action()
+ if not quick_action:
+ raise Http404()
if not quick_action.is_available(
user=request.user, session=request.session):
for item in self.items:
@@ -2379,3 +2381,27 @@ class QADocumentForm(QAItemEditForm):
form_class = forms.QADocumentFormMulti
+class QADocumentDuplicateFormView(QAItemForm):
+ template_name = 'ishtar/forms/qa_document_duplicate.html'
+ model = models.Document
+ page_name = _("Duplicate")
+ form_class = forms.QADocumentDuplicateForm
+ base_url = "document-qa-duplicate"
+
+ def get_form_kwargs(self):
+ kwargs = super(QADocumentDuplicateFormView,
+ self).get_form_kwargs()
+ kwargs['user'] = self.request.user
+ return kwargs
+
+ def form_valid(self, form):
+ form.save()
+ return HttpResponseRedirect(reverse("success"))
+
+ def get_context_data(self, **kwargs):
+ data = super(QADocumentDuplicateFormView,
+ self).get_context_data(**kwargs)
+ data['action_name'] = _("Duplicate")
+ return data
+
+