diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2020-03-20 19:40:24 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2020-03-20 19:40:24 +0100 |
commit | e60666c795e1531fda90013a001ac6dbc58b5667 (patch) | |
tree | d5fc7bd1cb9d8dab4c967fcad6dccba5e6b3517a | |
parent | 3674706764068d37ad0aca120a49e37c1ed291ec (diff) | |
download | Ishtar-e60666c795e1531fda90013a001ac6dbc58b5667.tar.bz2 Ishtar-e60666c795e1531fda90013a001ac6dbc58b5667.zip |
Refactoring and many fixes on file module
18 files changed, 352 insertions, 299 deletions
diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py index 7ade0b3f0..7ada27be8 100644 --- a/archaeological_files_pdl/forms.py +++ b/archaeological_files_pdl/forms.py @@ -26,11 +26,14 @@ from ishtar_common.utils import ugettext_lazy as _ from ishtar_common.models import Person, Town, Department, valid_id, \ person_type_pk_lazy, person_type_pks_lazy, organization_type_pks_lazy, \ - organization_type_pk_lazy + organization_type_pk_lazy, get_sra_agent_label, \ + get_orga_general_contractor_label, get_general_contractor_label, \ + get_orga_planning_service_label, get_responsible_planning_service_label + from archaeological_files import models from ishtar_common.forms import get_now, reverse_lazy, ManageOldType, \ - CustomForm, FieldType, IshtarForm + CustomForm, FieldType, IshtarForm, FormHeader from ishtar_common import widgets from bootstrap_datepicker.widgets import DatePicker @@ -84,18 +87,22 @@ class FileFormPreventiveType(CustomForm, ManageOldType, forms.Form): self.fields['permit_type'].help_text = models.PermitType.get_help() -class FileFormPlanning(CustomForm, forms.Form): +class FileFormPlanning(CustomForm, ManageOldType): form_label = _(u"Planning") form_admin_name = _(u"Archaeological file - 017 - Preventive - Planning") form_slug = "file-017-preventiveplanning" base_models = ['town', 'department'] associated_models = {'town': Town, 'department': Department} + HEADERS = {} + HEADERS['town'] = FormHeader(_("Localisation")) name = forms.CharField(label=_(u"Planning name"), required=False, max_length=100) town = widgets.Select2MultipleField( model=Town, label=_("Towns"), required=False, remote=True) department = widgets.Select2MultipleField( - model=Department, label=_("Departments"), required=False) + model=Department, label=_("Departments"), required=False, + help_text=_("Only relevant when no town is provided.") + ) locality = forms.CharField(label=_(u"Locality"), max_length=100, required=False) address = forms.CharField( @@ -104,6 +111,7 @@ class FileFormPlanning(CustomForm, forms.Form): required=False) postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, required=False) + HEADERS['total_surface'] = FormHeader(_("Surfaces")) total_surface = forms.FloatField( required=False, widget=widgets.AreaWidget, @@ -236,33 +244,36 @@ class PersonOrgaForm(forms.Form): validators=[valid_id(models.Organization)]) -class FileFormGeneralContractor(CustomForm, PersonOrgaForm): +class FileFormGeneralContractor(CustomForm, ManageOldType): form_label = _(u"General contractor") form_admin_name = _("Archaeological file - 030 - General contractor") form_slug = "file-030-generalcontractor" + extra_form_modals = ["person", "organization"] associated_models = {'general_contractor': models.Person, 'corporation_general_contractor': models.Organization} + corporation_general_contractor = forms.IntegerField( label=_("General contractor"), - required=False, - widget=widgets.JQueryPersonOrganization( - reverse_lazy('autocomplete-organization', - args=[ - organization_type_pks_lazy(['general_contractor'])] - ), - reverse_lazy('organization_create'), - model=models.Organization, + widget=widgets.JQueryAutoComplete( + reverse_lazy( + 'autocomplete-organization', + args=[ + organization_type_pks_lazy(['general_contractor']), + ]), limit={ 'organization_type': [ organization_type_pk_lazy('general_contractor') - ]}, - js_template='ishtar/blocks/JQueryCorporationPerson.js', - new=True), - validators=[valid_id(models.Organization)] - ) + ] + }, + tips=get_orga_general_contractor_label, + associated_model=models.Organization, new=True, + detail=True, + modify=True + ), + validators=[valid_id(models.Organization)]) general_contractor = forms.IntegerField( - label=_(u"In charge"), + label=_("In charge"), required=False, widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', @@ -271,118 +282,56 @@ class FileFormGeneralContractor(CustomForm, PersonOrgaForm): ]), associated_model=Person, limit={'person_types': [ - person_type_pk_lazy(['general_contractor']) + person_type_pk_lazy('general_contractor') ]}, - dynamic_limit=['general_contractor'], - url_new='new-person-noorga', + tips=get_general_contractor_label, + detail=True, + modify=True, new=True), validators=[valid_id(Person)] ) - PERSON_FIELD = 'general_contractor' - PERSON_TYPE_PK = person_type_pk_lazy('general_contractor') - PERSON_LABEL = _(u"General contractor") - ORGA_FIELD = 'corporation_general_contractor' - ORGA_TYPE_PK = organization_type_pk_lazy('general_contractor') - ORGA_LABEL = _(u"General contractor") - - def __init__(self, *args, **kwargs): - # get the status: natural person or corporation - DEFAULT_STATUS = 'natural' - current_status = '' - if 'data' in kwargs: - # the order is important: PERSON can have an ORGA - for field in [self.PERSON_FIELD, self.ORGA_FIELD]: - current_item_key = ( - (kwargs['prefix'] + '-') - if kwargs.get('prefix') else '') + field - if kwargs['data'] and kwargs['data'].get(current_item_key): - model = self.associated_models[field] - try: - model.objects.get( - pk=kwargs['data'][current_item_key]) - current_status = 'natural' \ - if field == self.PERSON_FIELD else 'corporation' - except (model.DoesNotExist, ValueError): - pass - initial = kwargs.get("initial", {}) - if not current_status: - # the order is important: PERSON can have an ORGA - for field in [self.ORGA_FIELD, self.PERSON_FIELD]: - value = initial.get(field) - model = self.associated_models[field] - try: - model.objects.get(pk=value) - current_status = 'natural' if field == self.PERSON_FIELD \ - else 'corporation' - except (model.DoesNotExist, ValueError): - pass - status = '' - if 'status' in kwargs: - status = kwargs.pop('status') - if current_status != status: - if kwargs.get('data'): - # status is different from the existing - clear fields - kwargs.pop('data') - elif current_status: - status = current_status - else: - status = DEFAULT_STATUS - - self.status = status - - if status not in ('natural', 'corporation'): - status = DEFAULT_STATUS - - user = None - if 'user' in kwargs: - user = kwargs.pop('user') - - super(PersonOrgaForm, self).__init__(*args, **kwargs) - - # distinct widget for natural and corporation - if status == 'natural': - self.fields[self.PERSON_FIELD] = forms.IntegerField( - label=self.PERSON_LABEL, - required=False, - initial=initial.get(self.PERSON_FIELD, None), - widget=widgets.JQueryPersonOrganization( - reverse_lazy('autocomplete-person', - args=[self.PERSON_TYPE_PK]), - reverse_lazy('person_create'), - model=Person, - limit={'person_types': [self.PERSON_TYPE_PK], - 'attached_to__isnull': True}, - js_template='ishtar/blocks/JQueryNaturalPerson.js', - new=True), - validators=[valid_id(Person)]) - self.fields.pop(self.ORGA_FIELD) - - -class FileFormPlanningService(CustomForm, forms.Form): - form_label = _(u"Planning service") + def clean(self): + general_contractor = self.cleaned_data["general_contractor"] + corporation_general_contractor = self.cleaned_data[ + "corporation_general_contractor"] + if general_contractor: + try: + person = models.Person.objects.get(pk=general_contractor) + except models.Person.DoesNotExist: + raise forms.ValidationError(_("Non existing person.")) + if person.attached_to.pk != corporation_general_contractor: + raise forms.ValidationError(_( + "The organization of the person in charge differs from the " + "general contractor.")) + return self.cleaned_data + + +class FileFormPlanningService(CustomForm, IshtarForm): + form_label = _("Planning service") form_admin_name = _("Archaeological file - 040 - Planning service") form_slug = "file-040-planningservice" + extra_form_modals = ["person", "organization"] associated_models = {'responsible_town_planning_service': models.Person, 'planning_service': models.Organization} - permit_reference = forms.CharField(label=_(u"File reference"), - required=False, max_length=200) planning_service = forms.IntegerField( label=_("Planning service"), required=False, - widget=widgets.JQueryPersonOrganization( + widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-organization', args=[organization_type_pks_lazy(['planning_service'])]), - reverse_lazy('organization_create'), - model=models.Organization, + associated_model=models.Organization, limit={ 'organization_type': [organization_type_pk_lazy(['planning_service'])], }, - js_template='ishtar/blocks/JQueryCorporationPerson.js', - new=True), + tips=get_orga_planning_service_label, + new=True, + detail=True, + modify=True, + ), validators=[valid_id(models.Organization)] ) responsible_town_planning_service = forms.IntegerField( @@ -398,21 +347,39 @@ class FileFormPlanningService(CustomForm, forms.Form): person_type_pk_lazy('responsible_planning_service') ]}, dynamic_limit=['planning_service'], - url_new='new-person-noorga', + tips=get_responsible_planning_service_label, + detail=True, + modify=True, new=True), validators=[valid_id(Person)] ) + permit_reference = forms.CharField(label=_(u"File reference"), + required=False, max_length=200) + + def clean(self): + responsible = self.cleaned_data["responsible_town_planning_service"] + orga = self.cleaned_data["planning_service"] + if responsible: + try: + person = models.Person.objects.get(pk=responsible) + except models.Person.DoesNotExist: + raise forms.ValidationError(_("Non existing person.")) + if person.attached_to.pk != orga: + raise forms.ValidationError(_( + "The organization of the person in charge differs from the " + "planning service.")) + return self.cleaned_data class FileFormInstruction(CustomForm, IshtarForm): - form_label = u"Instruction SRA" + form_label = _("Instruction") form_admin_name = _("Archaeological file - 050 - Instruction") form_slug = "file-050-instruction" extra_form_modals = ["person", "organization"] associated_models = {'in_charge': models.Person, 'related_file': models.File} in_charge = forms.IntegerField( - label=_("Person in charge"), + label=_("File managed by"), widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', @@ -421,7 +388,9 @@ class FileFormInstruction(CustomForm, IshtarForm): 'person_types': [ person_type_pk_lazy('sra_agent')] }, - associated_model=Person, new=True), + tips=get_sra_agent_label, + associated_model=Person, new=True, + ), validators=[valid_id(Person)]) related_file = forms.IntegerField( label=_("Related file"), required=False, diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_generalcontractor.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_generalcontractor.html deleted file mode 100644 index 169b2757e..000000000 --- a/archaeological_files_pdl/templates/ishtar/wizard/wizard_generalcontractor.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "ishtar/wizard/wizard_person_orga.html" %} -{% load replace_underscore %} - -{% block corporation %} - <tr class='required'> - <th>{{ wizard.form.corporation_general_contractor.label_tag }}</th> - <td> {{ wizard.form.corporation_general_contractor.errors }}{{wizard.form.corporation_general_contractor|safe}}</td> - </tr> -{% endblock %} - -{% block natural %} - <tr class='required'> - <th>{{ wizard.form.general_contractor.label_tag }}</th> - <td> {{ wizard.form.general_contractor.errors }}{{wizard.form.general_contractor|safe}}</td> - </tr> -{% endblock %} -{% block extra_head_po %} -<script type='text/javascript'> -$(function() { -var corp_id = '#id_{{wizard.form.prefix}}-corporation_general_contractor'; -var pers_id = "#id_select_{{wizard.form.prefix}}-general_contractor" ; -var pers_select_id = "#id_select_{{wizard.form.prefix}}-general_contractor" ; -$(corp_id).change( - function(){ - $(pers_select_id).autocomplete( - "option", "source", - source_{{wizard.form.prefix|replace_underscore}}_general_contractor - + $(corp_id).val() + '/'); - $(pers_select_id).val(""); - $(pers_id).val(""); - if ($(corp_id).val()){ - $(pers_select_id).prop("disabled", false); - } else { - $(pers_select_id).prop("disabled", true); - } -}); -}); -</script> -{% endblock %} diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html index 72dc1d35d..34db944aa 100644 --- a/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html +++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html @@ -1,76 +1,48 @@ {% extends "ishtar/wizard/default_wizard.html" %} {% load i18n range table_form %} -{% block wizard_form %} -<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} -<div class='form'> -{{ wizard.form.media }} -{{ wizard.management_form }} -<table> +{% block form_detail %} + <div class="form-row"> + {% with wizard.form.in_charge as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} + {% with wizard.form.related_file as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} + {% with wizard.form.comment as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} -<tr class='required'> - <th><label for="id_instruction-{{CURRENT_ACTION}}-in_charge">Dossier suivi par</label></th> -</tr> -<tr class='required'> - <td>{{wizard.form.in_charge.errors}}{{wizard.form.in_charge|safe}}</td> -</tr> - -<tr> - <th><label for="id_instruction-{{CURRENT_ACTION}}-related_file">Dossier lié à</label></th> -</tr> -<tr> - <td>{{wizard.form.related_file|safe}}</td> -</tr> - -<tr> - <th><label for="id_instruction-{{CURRENT_ACTION}}-comment">Commentaire</label></th> -</tr> -<tr> - <td>{{wizard.form.comment|safe}}</td> -</tr> - -<tr class='required'> - <th><label>État du dossier</label></th> -</tr> -<tr> - <td><input type='radio' name='state' value='open' id='state-open'/> <label for='state-open'>Dossier actif</label></td> -</tr> -<tr> - <td>{{wizard.form.end_date.errors}}<input type='radio' name='state' value='closed' id='state-closed'/> <label for='state-closed'>Dossier clos / date de clôture</label> : {{wizard.form.end_date|safe}}</td> -</tr> - -<tr class='required'> - <th><label for="id_instruction-{{CURRENT_ACTION}}-instruction_deadline">Date limite d'instruction</label></th> -</tr> -{% if saisine_type %}<tr> - <th><em>{{ saisine_type }}{% if saisine_type_delay %} : délai de {{saisine_type_delay}} jours{% endif %}</em></th> -</tr>{% endif %} -<tr class='required'> - <td>{{wizard.form.instruction_deadline.errors}}{{wizard.form.instruction_deadline|safe}}</td> -</tr> - -<tr class='required'> - <th><label for="id_instruction-{{CURRENT_ACTION}}-year">{{wizard.form.numeric_reference.label}}</label></th> -</tr> -<tr> - <td>{{wizard.form.numeric_reference.errors}}SRA <span class='small'>{{wizard.form.year|safe}}</span> - <span class='small'>{{wizard.form.numeric_reference|safe}}</span></td> -</tr> -</table> - -<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> -{{ previous_fields|safe }} - {% block "footer" %} - <div id="footer"> - {% block "validation_bar" %} - {% include 'ishtar/wizard/validation_bar.html' %} - {% endblock %} - {% include 'ishtar/blocks/footer.html' %} + <div class="form-group col-lg-6"> + <span class="required"> + <label class="required">{% trans "State of the file:" %}</label> + </span> + <div class="form-group col-lg-12 mb-0"> + <span><input type='radio' name='state' value='open' id='state-open'/> + <label for='state-open'>Dossier actif</label></span> + </div> + <div class="form-group col-lg-12"> + <span>{{wizard.form.end_date.errors}}<input type='radio' name='state' value='closed' id='state-closed'/> + <label for='state-closed'>Dossier clos / date de clôture</label> : {{wizard.form.end_date|safe}}</span> + </div> + </div> + {% with wizard.form.instruction_deadline as field %}{% with saisine_type_message as extra_field_label %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %}{% endwith %} + <div class="form-group col-lg-6"> + <span class="required"> + <label>{{wizard.form.numeric_reference.label}}{% trans ":" %}</label> + </span> + <div class="form-inline"> + {{wizard.form.numeric_reference.errors}} + {% if FILE_PREFIX %}<span class="pr-2">{{FILE_PREFIX}}</span>{% endif %} + <span class="pr-2">{{wizard.form.year|safe}}</span> - + <span class="pl-2">{{wizard.form.numeric_reference|safe}}</span> + </div> + </div> </div> - {% endblock %} -</div> -</form> -<script type='text/javascript'> -$(function(){ +{% endblock %} +{% block "js_extra_ready" %} if ($('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ $("#state-closed").prop('checked', true); } else { @@ -96,18 +68,16 @@ $(function(){ var state = $("input[name=state]:checked").val(); if (state == 'closed'){ if (!$('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ - alert("Vous devez sélectionner une date de clôture.") + alert("{% trans 'You must select a closing date.' %}") return false; } return true; } else if (state == 'open'){ return true; } else { - alert("Vous devez choisir un état pour ce dossier.") + alert("{% trans 'You must select a state for this file.' %}") return false; } return true; }); -}); -</script> -{% endblock %} + {% endblock %} diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html deleted file mode 100644 index 5eb7c014b..000000000 --- a/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "ishtar/wizard/default_wizard.html" %} -{% load i18n range table_form %} -{% block wizard_form %} -<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} -<div class='form'> -{% if wizard.form.media %}{{ wizard.form.media }}{% endif %} -{{ wizard.management_form }} - -<table> - {% if wizard.form.non_field_errors %}<tr class='errors'> - <td colspan='3'>{{wizard.form.non_field_errors}}</td> - </tr>{%endif%} - - <tr> - <th>{{ wizard.form.planning_service.label_tag }}</th> - <td> {{ wizard.form.planning_service.errors }}{{wizard.form.planning_service|safe}}</td> - </tr> - <tr> - <th>{{ wizard.form.responsible_town_planning_service.label_tag }}</th> - <td> {{ wizard.form.responsible_town_planning_service.errors }}{{wizard.form.responsible_town_planning_service|safe}}</td> - </tr> -</table> - - -<div> -<table> - {% if permit_type %} - <tr> - <th colspan='3'>{{permit_type}}</th> - </tr>{% endif %} - <tr> - <th>{{ wizard.form.permit_reference.label_tag }}{% if permit_type_code %} [{{permit_type_code}}]{% endif %}</th> - <td> {{ wizard.form.permit_reference.errors }}{{wizard.form.permit_reference|safe}}</td> - </tr> -</table> -</div> - -<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> -{{ previous_fields|safe }} - {% block "footer" %} - <div id="footer"> - {% block "validation_bar" %} - {% include 'ishtar/wizard/validation_bar.html' %} - {% endblock %} - {% include 'ishtar/blocks/footer.html' %} - </div> - {% endblock %} -</div> -</form> -{% endblock %} - - - diff --git a/archaeological_files_pdl/wizards.py b/archaeological_files_pdl/wizards.py index d13811eea..988303937 100644 --- a/archaeological_files_pdl/wizards.py +++ b/archaeological_files_pdl/wizards.py @@ -17,9 +17,13 @@ # See the file COPYING for details. +from django.conf import settings + from archaeological_files.wizards import FileWizard as BaseFileWizard from archaeological_files import models +from ishtar_common.utils import ugettext_lazy as _ + class FileWizard(BaseFileWizard): parcel_step_key = 'parcelspdl-' @@ -28,8 +32,8 @@ class FileWizard(BaseFileWizard): towns_formset = False multi_towns = True wizard_templates = { - 'generalcontractor-%(url_name)s': - 'ishtar/wizard/wizard_generalcontractor.html', + #'generalcontractor-%(url_name)s': + # 'ishtar/wizard/wizard_generalcontractor.html', 'planningservice-%(url_name)s': 'ishtar/wizard/wizard_planningservice.html', 'instruction-%(url_name)s': @@ -82,9 +86,13 @@ class FileWizard(BaseFileWizard): pass elif self.steps.current == forminstruction: saisine_type = self.get_saisine_type() + context['FILE_PREFIX'] = settings.ISHTAR_FILE_PREFIX if saisine_type: context['saisine_type'] = str(saisine_type) - context['saisine_type_delay'] = saisine_type.delay or 0 + context['saisine_type_message'] = str(saisine_type) + if saisine_type.delay: + context['saisine_type_message'] += str(_( + ": delay of {} days")).format(saisine_type.delay) elif self.steps.current == formfinal: if self.steps.current.endswith('creation'): # creation only parcels = [] diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 90805e656..843d082fe 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -55,7 +55,7 @@ from bootstrap_datepicker.widgets import DatePicker from ishtar_common import widgets from ishtar_common.forms import CustomForm, CustomFormSearch, FormSet, \ FloatField, reverse_lazy, TableSelect, get_now, FinalForm, \ - ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, HistorySelect, \ + ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, \ MultiSearchForm, LockForm, DocumentItemSelect from ishtar_common.forms_common import get_town_field from ishtar_common.models import valid_id, valid_ids, get_current_profile, \ diff --git a/example_project/settings.py b/example_project/settings.py index a5d1d3b3e..24c3bee35 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -254,6 +254,8 @@ ISHTAR_MAP_MAX_ITEMS = 50000 ISHTAR_QRCODE_VERSION = 6 # density of the QR code ISHTAR_QRCODE_SCALE = 2 # scale of the QR code +ISHTAR_FILE_PREFIX = "" + SRID = 4326 # WGS84 - World SURFACE_SRID = 4326 # WGS84 - World ENCODING = 'windows-1252' diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 2b52f0919..2df825594 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -315,7 +315,7 @@ class TargetKeyFormset(BaseModelFormSet): class OrganizationForm(ManageOldType, NewItemForm): prefix = 'organization' - form_label = _(u"Organization") + form_label = _("Organization") associated_models = {'organization_type': models.OrganizationType, "precise_town": models.Town} name = forms.CharField( @@ -348,7 +348,7 @@ class OrganizationForm(ManageOldType, NewItemForm): models.OrganizationType.get_help() self.limit_fields() - def save(self, user): + def save(self, user, item=None): dct = self.cleaned_data dct['history_modifier'] = user dct['organization_type'] = models.OrganizationType.objects.get( @@ -359,7 +359,12 @@ class OrganizationForm(ManageOldType, NewItemForm): pk=dct["precise_town"]) except models.Town.DoesNotExist: dct.pop("precise_town") - new_item = models.Organization(**dct) + if not item: + new_item = models.Organization(**dct) + else: + new_item = item + for k in dct: + setattr(new_item, k, dct[k]) new_item.save() return new_item @@ -792,7 +797,7 @@ class PersonForm(SimplePersonForm): self.fields['person_types'].help_text = models.PersonType.get_help() self.limit_fields() - def save(self, user): + def save(self, user, item=None): dct = self.cleaned_data dct['history_modifier'] = user for key in self.associated_models.keys(): @@ -806,7 +811,14 @@ class PersonForm(SimplePersonForm): except model.DoesNotExist: dct.pop(key) person_types = dct.pop('person_types') - new_item = models.Person.objects.create(**dct) + if not item: + new_item = models.Person.objects.create(**dct) + else: + for k in dct: + setattr(item, k, dct[k]) + item.save() + item.person_types.clear() + new_item = item for pt in person_types: new_item.person_types.add(pt) return new_item diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 5fa668faf..9b446ff9e 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1046,6 +1046,13 @@ class GeneralType(Cached, models.Model): item.generate_key() +def get_general_type_label(model, slug): + obj = model.get_cache(slug) + if not obj: + return "" + return str(obj) + + class HierarchicalType(GeneralType): parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL, @@ -3971,6 +3978,46 @@ class Address(BaseHistorizedItem): class Meta: abstract = True + def get_short_html_items(self): + items = [] + if self.address: + items.append( + """<span class="subadress">{}</span>""".format(self.address)) + if self.address_complement: + items.append( + """<span class="subadress-complement">{}</span>""".format( + self.address_complement)) + if self.postal_code: + items.append( + """<span class="postal-code">{}</span>""".format( + self.postal_code)) + if self.precise_town: + items.append( + """<span class="town">{}</span>""".format( + self.precise_town.name)) + elif self.town: + items.append( + """<span class="town">{}</span>""".format( + self.town)) + if self.country: + items.append( + """<span class="country">{}</span>""".format( + self.country)) + return items + + def get_short_html_detail(self): + html = """<div class="address">""" + items = self.get_short_html_items() + if not items: + items = [ + "<span class='no-address'>{}</span>".format( + _("No associated address") + ) + ] + html += "".join(items) + html += """</div>""" + return html + def get_town_centroid(self): if self.precise_town: return self.precise_town.center, self._meta.verbose_name @@ -4138,6 +4185,20 @@ class OrganizationType(GeneralType): ordering = ('label',) +def get_orga_planning_service_label(): + lbl = get_general_type_label(OrganizationType, "planning_service") + if lbl: + return lbl + return _("Error: planning_service type is missing") + + +def get_orga_general_contractor_label(): + lbl = get_general_type_label(OrganizationType, "general_contractor") + if lbl: + return lbl + return _("Error: general_contractor type is missing") + + post_save.connect(post_save_cache, sender=OrganizationType) post_delete.connect(post_save_cache, sender=OrganizationType) @@ -4259,6 +4320,27 @@ person_type_pk_lazy = lazy(PersonType.get_or_create_pk, str) person_type_pks_lazy = lazy(PersonType.get_or_create_pks, str) +def get_sra_agent_label(): + lbl = get_general_type_label(PersonType, "sra_agent") + if lbl: + return lbl + return _("Error: sra_agent type is missing") + + +def get_general_contractor_label(): + lbl = get_general_type_label(PersonType, "general_contractor") + if lbl: + return lbl + return _("Error: general_contractor type is missing") + + +def get_responsible_planning_service_label(): + lbl = get_general_type_label(PersonType, "responsible_planning_service") + if lbl: + return lbl + return _("Error: responsible_planning_service type is missing") + + class TitleType(GeneralType): class Meta: verbose_name = _("Title type") @@ -4407,6 +4489,19 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem): profile.save() return profile + def get_short_html_items(self): + items = super(Person, self).get_short_html_items() + if items or not self.attached_to: + return items + orga_address = self.attached_to.get_short_html_items() + if not orga_address: + return [] + items.append( + """<span class="organization">{}</span>""".format( + self.attached_to.name)) + items += orga_address + return items + def simple_lbl(self): values = [str(getattr(self, attr)) for attr in ('surname', 'name') if getattr(self, attr)] diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index b8a9bf9ce..60ebb0bc9 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -706,15 +706,21 @@ function save_and_close_window_data(main_page, name_label, name_pk, item_name, item_pk){ var cur_item; var cur_item_pk; + var id_item; if (main_page){ - cur_item = $(main_page).find("#"+name_label); - cur_item_pk = $(main_page).find("#"+name_pk); + cur_item = $(main_page).find("#" + name_label); + cur_item_pk = $(main_page).find("#" + name_pk); + id_item = $(main_page).find("#id_" + name_label); } else { - cur_item = $("#"+name_label); - cur_item_pk = $("#"+name_pk); + cur_item = $("#" + name_label); + cur_item_pk = $("#" + name_pk); + id_item = $("#id_" + name_label); } cur_item.val(item_name); + cur_item.change(); cur_item_pk.val(item_pk); + cur_item_pk.change(); + id_item.change(); } function save_and_close_window_many(name_label, name_pk, item_name, item_pk){ diff --git a/ishtar_common/templates/blocks/JQueryAutocomplete.js b/ishtar_common/templates/blocks/JQueryAutocomplete.js index 7cd0e2a60..aaf493db9 100644 --- a/ishtar_common/templates/blocks/JQueryAutocomplete.js +++ b/ishtar_common/templates/blocks/JQueryAutocomplete.js @@ -52,7 +52,7 @@ $(function() { {{safe_field_id}}_modify = function(){ var current_val = $('#id_{{field_id}}').val(); if (current_val){ - dt_qa_open('/modify-{{model_name}}/' + current_val + "/", + dt_qa_open('/modify-{{model_name}}/{{field_id}}/' + current_val + "/", 'modal-dynamic-form-{{model_name}}'); } } diff --git a/ishtar_common/templates/blocks/bs_field_snippet.html b/ishtar_common/templates/blocks/bs_field_snippet.html index 644f7f433..dcee87f7f 100644 --- a/ishtar_common/templates/blocks/bs_field_snippet.html +++ b/ishtar_common/templates/blocks/bs_field_snippet.html @@ -2,6 +2,7 @@ <div id="main_div-{{field.auto_id}}" class="form-group{% if not field.label %} no-label{% endif %} {% if field.field.widget.attrs.cols or force_large_col %}col-lg-12{% else %}col-lg-6{% endif %}{% if field.errors %} is-invalid{% endif %}{% if field.field.required %} required{% endif %}{% if force_large_col %} full-width{% endif %}" data-alt-name="{{field.field.alt_name}}"> {% if field.label %}{{ field.label_tag }}{% endif %} + {% if extra_field_label %}<label><em>{{extra_field_label}}</em></label>{% endif %} {% if show_field_number or form.show_field_number %} {% if field.field.order_number %}<span class="badge badge-pill badge-success field-tip"> {{field.field.order_number}} diff --git a/ishtar_common/templates/ishtar/forms/qa_new_item.html b/ishtar_common/templates/ishtar/forms/qa_new_item.html index ae57adfc2..435531594 100644 --- a/ishtar_common/templates/ishtar/forms/qa_new_item.html +++ b/ishtar_common/templates/ishtar/forms/qa_new_item.html @@ -3,7 +3,8 @@ {% block main_form %} {% if new_item_pk %} -<p>{% if new_item_label %}{{new_item_label}}{% else %}{% trans "Item" %}{% endif %} {% trans "created." %}</p> +<p>{% if new_item_label %}{{new_item_label}}{% else %}{% trans "Item" %}{% endif %} + {% if modify %}{% trans "modified." %}{% else %}{% trans "created." %}{% endif %}</p> {% else %} {% bs_compact_form form %} {% endif %} diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html index b5ea4207c..cfd17e58f 100644 --- a/ishtar_common/templates/ishtar/wizard/default_wizard.html +++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html @@ -62,6 +62,8 @@ $(document).ready(function(){ return false; }); {% if open_url %}load_window("{{open_url}}");{% endif %} + {% block "js_extra_ready" %} + {% endblock %} }); </script> {% endblock %} diff --git a/ishtar_common/templates/ishtar/wizard/parcels_wizard.html b/ishtar_common/templates/ishtar/wizard/parcels_wizard.html index 2028d8792..d8c902c72 100644 --- a/ishtar_common/templates/ishtar/wizard/parcels_wizard.html +++ b/ishtar_common/templates/ishtar/wizard/parcels_wizard.html @@ -22,13 +22,16 @@ {% bs_form wizard.form.selection_form %} <table class='inline-table' id='parcel-table'> - <tr>{% for field in wizard.form.forms.0 %}<th{% if not forloop.last %} rowspan='2'{% endif %}>{{ field.label_tag }}</th>{% endfor %}</tr> + <tr>{% for field in wizard.form.forms.0 %} + {% if field.required %}<th{%else%}<td{% endif %}{% if not forloop.last %} rowspan='2'{% endif %}> + {{ field.label_tag }}{% if field.required %}</th>{%else%}</td>{% endif %}{% endfor %} + </tr> <tr><td>({% trans "all"%} <input type='checkbox' name='check-all' class='check-all'/>)</td></tr> {% inline_formset 'Parcels' wizard.form.forms False %} </table> {% if add_all %}<p><input type='checkbox' name='add_all_parcels' id='add_all_parcels'> <label for='add_all_parcels'>{% trans "Add all parcels from the archaeological file" %}</label></p>{% endif %} - <div class="text-center"> + <div class="mt-3 text-center"> <button class="btn btn-success" name="formset_modify" value="{{wizard.steps.current}}"> {% trans "Add/Modify" %} </button> diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index cc8d3eed4..8b506c55c 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -206,6 +206,14 @@ urlpatterns += [ views.get_by_importer, name='get-by-importer'), url(r'new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', views.new_person, name='new-person'), + url(r'modify-person/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$', + views.modify_person, name='modify-person'), + url(r'detail-person/(?P<pk>[\d+]+)/$', + views.detail_person, name='detail-person'), + url(r'modify-organization/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$', + views.modify_organization, name='modify-organization'), + url(r'detail-organization/(?P<pk>[\d+]+)/$', + views.detail_organization, name='detail-organization'), url(r'new-person-noorga/' r'(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', views.new_person_noorga, name='new-person-noorga'), diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 4724d61b7..b662c1a4d 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -70,7 +70,8 @@ from ishtar_common.widgets import JQueryAutoComplete from ishtar_common import tasks from .views_item import CURRENT_ITEM_KEYS, CURRENT_ITEM_KEYS_DICT, \ - check_permission, display_item, get_item, show_item, new_qa_item + check_permission, display_item, get_item, show_item, new_qa_item, \ + modify_qa_item, get_short_html_detail logger = logging.getLogger(__name__) @@ -791,11 +792,15 @@ def autocomplete_author(request): new_person = new_qa_item(models.Person, forms.PersonForm) +modify_person = modify_qa_item(models.Person, forms.PersonForm) +detail_person = get_short_html_detail(models.Person) new_person_noorga = new_qa_item(models.Person, forms.NoOrgaPersonForm) new_organization = new_qa_item(models.Organization, forms.OrganizationForm) show_organization = show_item(models.Organization, 'organization') get_organization = get_item(models.Organization, 'get_organization', 'organization') +modify_organization = modify_qa_item(models.Organization, forms.OrganizationForm) +detail_organization = get_short_html_detail(models.Organization) new_author = new_qa_item(models.Author, forms.AuthorForm) show_person = show_item(models.Person, 'person') diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index 8cd903a00..aa9a39965 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -22,6 +22,7 @@ from django.core.urlresolvers import reverse, NoReverseMatch from django.db.models import Q, Count, Sum, ImageField, Func, \ ExpressionWrapper, FloatField, FileField from django.db.models.fields import FieldDoesNotExist +from django.forms.models import model_to_dict from django.http import HttpResponse from django.shortcuts import render from django.template import loader @@ -146,7 +147,7 @@ def new_qa_item(model, frm, many=False): template = "ishtar/forms/qa_new_item.html" model_name = model._meta.object_name if not check_permission(request, 'add_' + model_name.lower()): - not_permitted_msg = ugettext(u"Operation not permitted.") + not_permitted_msg = ugettext("Operation not permitted.") return HttpResponse(not_permitted_msg) slug = model.SLUG if model.SLUG == "site": @@ -177,6 +178,68 @@ def new_qa_item(model, frm, many=False): return func +def get_short_html_detail(model): + def func(request, pk): + model_name = model._meta.object_name + not_permitted_msg = ugettext("Operation not permitted.") + if not check_permission(request, 'view_' + model_name.lower(), + pk): + return HttpResponse(not_permitted_msg) + try: + item = model.objects.get(pk=pk) + except model.DoesNotExist: + return HttpResponse(not_permitted_msg) + html = item.get_short_html_detail() + return HttpResponse(html) + return func + + +def modify_qa_item(model, frm): + def func(request, parent_name="", pk=None): + template = "ishtar/forms/qa_new_item.html" + model_name = model._meta.object_name + not_permitted_msg = ugettext("Operation not permitted.") + if not check_permission(request, 'change_' + model_name.lower(), + pk): + return HttpResponse(not_permitted_msg) + slug = model.SLUG + if model.SLUG == "site": + slug = "archaeologicalsite" + try: + item = model.objects.get(pk=pk) + except model.DoesNotExist: + return HttpResponse(not_permitted_msg) + url_slug = "modify-" + slug + dct = {'page_name': str(_('Modify a %s' % model_name.lower())), + 'url': reverse(url_slug, args=[parent_name, pk]), + 'slug': slug, + "modify": True, + 'parent_name': parent_name} + if request.method == 'POST': + dct['form'] = frm(request.POST) + if dct['form'].is_valid(): + new_item = dct['form'].save(request.user, item) + lbl = str(new_item) + if not lbl and hasattr(new_item, "_generate_cached_label"): + lbl = new_item._generate_cached_label() + dct['new_item_label'] = lbl + dct['new_item_pk'] = new_item.pk + dct['parent_pk'] = parent_name + if dct['parent_pk'] and '_select_' in dct['parent_pk']: + parents = dct['parent_pk'].split('_') + dct['parent_pk'] = "_".join([parents[0]] + parents[2:]) + return render(request, template, dct) + else: + data = model_to_dict(item) + for k in list(data.keys()): + if data[k] and isinstance(data[k], list) and hasattr( + data[k][0], "pk"): + data[k] = [i.pk for i in data[k]] + dct['form'] = frm(initial=data) + return render(request, template, dct) + return func + + def display_item(model, extra_dct=None, show_url=None): def func(request, pk, **dct): if show_url: |