summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commitef7bc287bd743b01b534cff5b28bbe39268063a5 (patch)
treed5fc7bd1cb9d8dab4c967fcad6dccba5e6b3517a
parent8d72941c7ba307d8f4541e34f24a957784e9660d (diff)
downloadIshtar-ef7bc287bd743b01b534cff5b28bbe39268063a5.tar.bz2
Ishtar-ef7bc287bd743b01b534cff5b28bbe39268063a5.zip
Refactoring and many fixes on file module
-rw-r--r--archaeological_files_pdl/forms.py199
-rw-r--r--archaeological_files_pdl/templates/ishtar/wizard/wizard_generalcontractor.html39
-rw-r--r--archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html116
-rw-r--r--archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html53
-rw-r--r--archaeological_files_pdl/wizards.py14
-rw-r--r--archaeological_finds/forms.py2
-rw-r--r--example_project/settings.py2
-rw-r--r--ishtar_common/forms_common.py22
-rw-r--r--ishtar_common/models.py95
-rw-r--r--ishtar_common/static/js/ishtar.js14
-rw-r--r--ishtar_common/templates/blocks/JQueryAutocomplete.js2
-rw-r--r--ishtar_common/templates/blocks/bs_field_snippet.html1
-rw-r--r--ishtar_common/templates/ishtar/forms/qa_new_item.html3
-rw-r--r--ishtar_common/templates/ishtar/wizard/default_wizard.html2
-rw-r--r--ishtar_common/templates/ishtar/wizard/parcels_wizard.html7
-rw-r--r--ishtar_common/urls.py8
-rw-r--r--ishtar_common/views.py7
-rw-r--r--ishtar_common/views_item.py65
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: