diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms_common.py | 68 | ||||
-rw-r--r-- | ishtar_common/models.py | 79 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/forms/qa_document_duplicate.html | 95 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/sheet_document.html | 2 | ||||
-rw-r--r-- | ishtar_common/urls.py | 4 | ||||
-rw-r--r-- | ishtar_common/views.py | 26 |
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 + + |