diff options
Diffstat (limited to 'archaeological_operations')
| -rw-r--r-- | archaeological_operations/forms.py | 70 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 22 | ||||
| -rw-r--r-- | archaeological_operations/templates/ishtar/sheet_operation.html | 183 | ||||
| -rw-r--r-- | archaeological_operations/templates/ishtar/sheet_operation_pdf.html | 18 | ||||
| -rw-r--r-- | archaeological_operations/templates/ishtar/sheet_operation_window.html | 3 | ||||
| -rw-r--r-- | archaeological_operations/urls.py | 6 | ||||
| -rw-r--r-- | archaeological_operations/views.py | 39 | ||||
| -rw-r--r-- | archaeological_operations/widgets.py | 43 | ||||
| -rw-r--r-- | archaeological_operations/wizards.py | 41 | 
9 files changed, 403 insertions, 22 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index f5f0fea99..72834d8f0 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2012  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2013  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -35,26 +35,37 @@ from django.utils.translation import ugettext_lazy as _  from ishtar_common.models import valid_id, PersonType, Person, Town  from archaeological_files.models import File  import models +from widgets import ParcelWidget  from ishtar_common import widgets -from ishtar_common.forms import FinalForm, FormSet, ClosingDateFormSelection, \ -     formset_factory, get_now, reverse_lazy, get_form_selection +from ishtar_common.forms import BaseFormSet, FinalForm, FormSet, \ +    ClosingDateFormSelection, formset_factory, get_now, reverse_lazy, \ +    get_form_selection, TableSelect  from ishtar_common.forms_common import TownForm, TownFormSet, TownFormset, \       AuthorFormset, SourceForm, SourceSelect, \       SourceDeletionForm, get_town_field +class ParcelField(forms.MultiValueField): +    def __init__(self, *args, **kwargs): +        if 'widget' not in kwargs: +            self.widget = ParcelWidget() +        return super(ParcelField, self).__init__(*args, **kwargs) + +    def compress(data_list): +        return u"-".join(data_list) +  class ParcelForm(forms.Form):      form_label = _("Parcels")      base_model = 'parcel'      associated_models = {'parcel':models.Parcel, 'town':models.Town}      town = forms.ChoiceField(label=_("Town"), choices=(), required=False,                               validators=[valid_id(models.Town)]) +    year = forms.IntegerField(label=_("Year"), required=False, +                           validators=[validators.MinValueValidator(1900), +                                       validators.MaxValueValidator(2100)])      section = forms.CharField(label=_(u"Section"), required=False,                               validators=[validators.MaxLengthValidator(4)])      parcel_number = forms.CharField(label=_(u"Parcel number"), required=False,                               validators=[validators.MaxLengthValidator(6)]) -    year = forms.IntegerField(label=_("Year"), required=False, -                           validators=[validators.MinValueValidator(1900), -                                       validators.MaxValueValidator(2100)])      def __init__(self, *args, **kwargs):          towns = None          if 'data' in kwargs and 'TOWNS' in kwargs['data']: @@ -74,9 +85,11 @@ class ParcelForm(forms.Form):          """Check required fields"""          if any(self.errors):              return -        if not self.cleaned_data or DELETION_FIELD_NAME in self.cleaned_data \ -           and self.cleaned_data[DELETION_FIELD_NAME]: +        if not self.cleaned_data or (DELETION_FIELD_NAME in self.cleaned_data \ +           and self.cleaned_data[DELETION_FIELD_NAME]):              return +        if not self.cleaned_data.get('parcel_number'): +            return {}          for key in ('town', 'parcel_number', 'section'):              if not key in self.cleaned_data or not self.cleaned_data[key]:                  raise forms.ValidationError(_(u"Town section and parcel number " @@ -84,23 +97,49 @@ class ParcelForm(forms.Form):          return self.cleaned_data  class ParcelFormSet(FormSet): +    def add_fields(self, form, index): +        super(FormSet, self).add_fields(form, index) +      def clean(self):          """Checks that no parcels are duplicated.""" -        return self.check_duplicate(('town', 'parcel_number', 'year'), -                                    _(u"There are identical parcels.")) +        return self.check_duplicate(('town', 'section', +                                     'parcel_number', 'year'), +                                     _(u"There are identical parcels."))  ParcelFormSet = formset_factory(ParcelForm, can_delete=True,                                  formset=ParcelFormSet)  ParcelFormSet.form_label = _(u"Parcels") -class OperationSelect(forms.Form): +class OperationSelect(TableSelect):      common_name = forms.CharField(label=_(u"Name"), max_length=30) +    if settings.COUNTRY == 'fr': +        code_patriarche = forms.IntegerField( +         widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ +                     'autocomplete-patriarche/'), +         label="Code PATRIARCHE")      towns = get_town_field()      operation_type = forms.ChoiceField(label=_(u"Operation type"),                                         choices=[]) +    in_charge = forms.IntegerField( +        widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', +          args=["_".join( +         [unicode(PersonType.objects.get(txt_idx='head_scientist').pk), +          unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])]), +        associated_model=Person, new=True), label=_(u"In charge"))      remains = forms.ChoiceField(label=_(u"Remains"),                                  choices=models.RemainType.get_types()) +    periods = forms.ChoiceField(label=_(u"Periods"), +                                choices=models.Period.get_types())      year = forms.IntegerField(label=_("Year")) +    start_before = forms.DateField(label=_(u"Started before"), +                                   widget=widgets.JQueryDate) +    start_after = forms.DateField(label=_(u"Started after"), +                                  widget=widgets.JQueryDate) +    end_before = forms.DateField(label=_(u"Ended before"), +                                 widget=widgets.JQueryDate) +    end_after = forms.DateField(label=_(u"Ended after"), +                                widget=widgets.JQueryDate) +    parcel = ParcelField(label=_("Parcel (section/number)"))      end_date = forms.NullBooleanField(label=_(u"Is open?"))      def __init__(self, *args, **kwargs): @@ -108,6 +147,13 @@ class OperationSelect(forms.Form):          self.fields['operation_type'].choices = models.OperationType.get_types()          self.fields['operation_type'].help_text = models.OperationType.get_help() +    def get_input_ids(self): +        ids = super(OperationSelect, self).get_input_ids() +        ids.pop(ids.index('parcel')) +        ids.append('parcel_0') +        ids.append('parcel_1') +        return ids +  class OperationFormSelection(forms.Form):      form_label = _(u"Operation search")      associated_models = {'pk':models.Operation} @@ -406,7 +452,7 @@ OperationSourceFormSelection = get_form_selection(  # Administrative act management for operations #  ################################################ -class AdministrativeActOpeSelect(forms.Form): +class AdministrativeActOpeSelect(TableSelect):      operation__towns = get_town_field()      act_type = forms.ChoiceField(label=_("Act type"), choices=[]) diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 399b536e2..02ec1a912 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2012 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2012-2013 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -18,6 +18,7 @@  # See the file COPYING for details.  import datetime +from itertools import groupby  from django.conf import settings  from django.contrib.gis.db import models @@ -137,6 +138,9 @@ class Operation(BaseHistorizedItem, OwnPerms):                                 unicode(self.operation_code))))          return settings.JOINT.join(items) +    def grouped_parcels(self): +        return Parcel.grouped_parcels(list(self.parcels.all())) +      @classmethod      def get_available_operation_code(cls, year=None):          if not year: @@ -163,6 +167,7 @@ class Operation(BaseHistorizedItem, OwnPerms):      def year_index(self):          if not self.operation_code:              return "" +        lbl = unicode(self.operation_code)          lbl = u"%d-%s%s" % (self.year, (3-len(lbl))*"0", lbl)          return lbl @@ -327,6 +332,21 @@ class Parcel(LightHistorizedItem):      def __unicode__(self):          return self.short_label() +    @staticmethod +    def grouped_parcels(parcels): +        sortkeyfn = lambda s:(getattr(s, 'year'), getattr(s, 'town'), +                              getattr(s, 'section')) +        parcels.sort(key=sortkeyfn) +        grouped = [] +        for keys, parcel_grp in groupby(parcels, key=sortkeyfn): +            for idx, parcel in enumerate(parcel_grp): +                if not idx: +                    grouped.append(parcel) +                    grouped[-1].parcel_numbers = [] +                grouped[-1].parcel_numbers.append(parcel.parcel_number) +            grouped[-1].parcel_numbers.sort() +        return grouped +      def long_label(self):          items = [unicode(self.operation or self.associated_file)]          items += [unicode(item) for item in [self.section, self.parcel_number] diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html new file mode 100644 index 000000000..491304125 --- /dev/null +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -0,0 +1,183 @@ +{% extends "ishtar/sheet.html" %} +{% load i18n %} +{% block content %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-operation item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-operation item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<h3>{% trans "General"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.year }}</span></p> +{% if item.operation.operation_code %}<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.operation_code }}</span></p>{% endif %} + +{% if item.code_patriarche %}<p><label>{%trans "Patriarche OA code:"%}</label> <span class='value'>{{ item.code_patriarche }}</span></p>{%else%} +<p class='alert'>{%trans "Patriarche OA code not yet recorded!"%}</p>{%endif%} + +{#<p><label>{%trans "Operation's name:"%}</label> <span class='value'>{{ item.internal_reference }}</span></p>#} + +<p><label>{%trans "Edition date:"%}</label> <span class='value'>{{ item.history.all.0.history_date }}</span></p> <!-- date = now --> + +{% if item.start_date %}<p><label>{%trans "Begining date:"%}</label> <span class='value'>{{ item.start_date }}</span></p> +<p><label>{%trans "Excavation end date:"%}</label> <span class='value'>{{ item.excavation_end_date|default:"-" }}</span></p> +{%endif%} +{% if item.in_charge %}<p><label>{%trans "Head scientist:"%}</label> <span class='value'>{{ item.in_charge.full_label }}</span></p>{%endif%} +<p><label>{%trans "State:"%}</label> <span class='value'>{% if item.is_active %}{%trans "Active file"%}</span></p> +{% else %}{%trans "Closed operation"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.closing.date }} <strong>{%trans "by" %}</strong> {{ item.closing.user }}</span></p> +{% endif %} +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.operation_type }}</span></p> +{% if item.surface  %}<p><label>{%trans "Surface:"%}</label> <span class='value'>{{ item.surface }} m<sup>2</sup> ({{ item.surface_ha }} ha)</span></p>{% endif %} +{% if item.cost %}<p><label>{%trans "Cost:"%}</label> <span class='value'>{{ item.cost }} €{% if item.cost_by_m2 %}, ({{ item.cost_by_m2 }} €/m<sup>2</sup>){%endif%}</span></p>{%endif%} +{% if item.duration %}<p><label>{%trans "Duration:"%}</label> <span class='value'>{{ item.duration }} {%trans "Day"%}s</span></p>{%endif%} + +<p><label>{%trans "Remains:"%}</label> <span class='value'>{{ item.remains.all|join:", " }}</span></p> +<p><label>{%trans "Periods:"%}</label> <span class='value'>{{ item.periods.all|join:", " }}</span></p> + +{% if item.associated_file %} +<p><label>{%trans "Associated file:"%}</label> <span class='value'><a href='#' onclick='load_window("{% url show-file item.associated_file.pk ''%}")'>{{ item.associated_file }}</a></span></p><!-- Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related file --> +{% if item.associated_file.is_preventive %} +{#{% if item.operator_reference_code %}<p><label>{%trans "Operator's reference code:"%}</label> <span class='value'>{{ item.operator_reference_code }}</span></p>{% endif %}#} +{% if item.associated_file.town_planning_service %}<p><label>{%trans "Town planning service:"%}</label> <span class='value'>{{ item.associated_file.town_planning_service }}</span></p>{% endif %} +{% if item.associated_file.permit_type %}<p><label>{%trans "Permit type:"%}</label> <span class='value'>{{ item.associated_file.permit_type }}</span></p>{% endif %} +{% if item.associated_file.permit_reference %}<p><label>{%trans "Permit reference:"%}</label> <span class='value'>{{ item.associated_file.permit_reference }}</span></p>{% endif %} +{% if item.associated_file.general_contractor.attached_to %}<p><label>{%trans "General contractor organisation:"%}</label> <span class='value'>{{ item.associated_file.general_contractor.attached_to }}</span></p>{% endif %} <!-- Contractor's organisation displayed as concat of Name/Adress/postal_code/city --> +{% if item.associated_file.general_contractor %}<p><label>{%trans "General contractor:"%}</label> <span class='value'>{{ item.associated_file.general_contractor.full_label }}</span></p>{% endif %} +{% endif %} +{% endif %} +  +{% if item.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.comment }}</span></p>{%endif%} + +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.towns.all|join:", " }}</span></p> + +<p><label>{%trans "Main address:"%}</label> <span class='value'>{{ item.associated_file.address }}</span></p> +{% if item.associated_file.address_complement %}<p><label>{%trans "Complement:"%}</label> <span class='value'>{{ item.associated_file.address_complement }}</span></p>{%endif%} +{% if item.associated_file.postal_code %}<p><label>{%trans "Postal code:"%}</label> <span class='value'>{{ item.associated_file.postal_code }}</span></p>{%endif%} + +{% comment %} +<p><label>{%trans "Lambert X:"%}</label> <span class='value'>{{ item.lambert_x }}</span></p> +<p><label>{%trans "Lambert Y:"%}</label> <span class='value'>{{ item.lambert_y }}</span></p> +<p><label>{%trans "Altitude (m NGF):"%}</label> <span class='value'>{{ item.altitude }}</span></p> +{% endcomment %} +<table> +  <caption>{%trans "Associated parcels"%}</caption> +  <tr> +    <th>{% trans "Commune" %}</th> +    <th>{% trans "Year" %}</th> +    <th>{% trans "Section" %}</th> +    <th>{% trans "Parcels" %}</th> +    {#<th>{% trans "Owner" %}</th>#} +  </tr> +  {% for parcel in item.grouped_parcels %} +  <tr> +    <td class='string'>{{parcel.town}}</td> +    <td>{{parcel.year}}</td> +    <td>{{parcel.section}}</td> +    <td>{{parcel.parcel_numbers|join:", "}}</td> +    {#<td class='string'>{{operation.parcel.owner}}</td>#} +  </tr> +  {% empty %} +  <tr><td colspan="4" class='no_items'>{% trans "No parcel associated to this operation" %}</td></tr> +  {% endfor %} +</table> + +<table> +  <caption>{%trans "Administrative acts"%}</caption> +  <tr> +    <th>{% trans "Year" %}</th> +    <th>{% trans "Reference" %}</th> +    <th>{% trans "Type" %}</th> +    <th>{% trans "Date" %}</th> +  </tr> +  {% for act in item.administrative_act.all %} +  <tr> +    <td>{{act.signature_date.year}}</td> +    <td>{{act.ref_sra}}</td> +    <td class='string'>{{act.act_type}}</td> +    <td class="string">{{act.signature_date}}</td> +  </tr> +  {% empty %} +  <tr><td colspan="4" class='no_items'>{% trans "No acts associated to this operation" %}</td></tr> +  {% endfor %} +</table> + +<h3>{% trans "Scientific documentation"%}</h3> +<table> +  <caption>{%trans "Documents"%}</caption> +  <tr> +    <th>{% trans "Title" %}</th> +    <th>{% trans "Type" %}</th> +    <th>{% trans "Authors" %}</th> +    {#<th>{% trans "Localisation" %}</th>#} +  </tr> +  {% for doc in item.source.all %} +  <tr> +    <td class='string'>{{ doc.title }}</td> +    <td class='string'>{{doc.source_type}}</td> +    <td class='string'>{{ doc.authors.all|join:", " }}</td> +    {#<td>{{ doc.localisation }}</td>#} +  </tr> +  {% empty %} +  <tr><td colspan="4" class='no_items'>{% trans "No scientific document associated to this operation" %}</td></tr> +  {% endfor %} +</table> + +<table> +  <caption>{%trans "Context records"%}</caption> +  <tr> +    <th>{% trans "ID" %}</th> +    <th>{% trans "Type" %}</th> +    <th>{% trans "Chronology" %}</th> +    <th>{% trans "Description" %}</th> +    <th>{% trans "Parcel" %}</th> +    <th class='link'> </th> +  </tr> +  {% for context_record in item.context_record.all %} +  <tr> +    <td class='string'>{{ context_record.label }}</td> +    <td class='string'>{{context_record.unit|default:""}}</td> +    <td class='string'>{{ context_record.datings.all|join:", " }}</td>{# periods ?#} +    <td class='string'>{{ context_record.description }}</td> +    <td class='string'>{{ context_record.parcel.section }} - {{context_record.parcel.parcel_number}}</td> +    <td class='link'><a href="#" onclick='load_window("{%url show-contextrecord context_record.pk ''%}")'>{% trans "Details" %}</a></td> +  </tr> +  {% empty %} +  <tr><td colspan="6" class='no_items'>{% trans "No context record associated to this operation" %}</td></tr> +  {% endfor %} +</table> +<div class='table'> +<table> +  <caption>{%trans "Finds"%}</caption> +  <tr> +    <th>{% trans "Find" %}</th> +    <th>{% trans "Material type" %}</th> +    <th>{% trans "Context record" %}</th>  +    <th>{% trans "Periods" %}</th> +    <th>{% trans "Description" %}</th> +    <th>{% trans "Weight" %}</th> +    <th>{% trans "Numbers" %}</th> +    <th>{% trans "Parcel" %}</th> +    <th class='link'> </th> +  </tr> +  {% for context_record in item.context_record.all %} +  {% for find in context_record.base_finds.all %} +  <tr> +    <td class="ref">{{ find.full_label }}</td> +{# Displayed as (Patriarche operation code)-(Record unit label)-(Finds label). #} +{# or displayed as (Year)-(index)-(Record unit label)-(Finds label). #} +    <td class="ref">{{ find.material_type_label }}</td> +    <td>{{find.context_record.label}}</td> +    <td class='string'>{{ find.get_last_find.dating}}</td>{# TODO .all|join:", " ? #} +    <td class='string'>{{ find.get_last_find.description }}</td> +    <td>{{ find.get_last_find.weight }}</td> +    <td>{{ find.get_last_find.item_number }}</td> +    <td class="ref">{{ context_record.parcel.short_label }}</td> +    <td class='link'><a href="#">{% trans "Details" %}</a></td> +    {#<a href="#" onclick='load_window("{% url show-find find.pk%}");'>{%trans "Details"%}</a></td>#} +  </tr> +  {% empty %} +  <tr><td colspan="9" class='no_items'>{% trans "No find associated to context record" %} {{context_record.short_label}}</td></tr> +  {% endfor %} +  {% empty %} +  <tr><td colspan="9" class='no_items'>{% trans "No find associated to parcel" %} {{parcel.short_label}} {% trans "(no context record)" %}</td></tr> +  {% endfor %} +</table> +</div> + +{% endblock %} diff --git a/archaeological_operations/templates/ishtar/sheet_operation_pdf.html b/archaeological_operations/templates/ishtar/sheet_operation_pdf.html new file mode 100644 index 000000000..9ef0edbf7 --- /dev/null +++ b/archaeological_operations/templates/ishtar/sheet_operation_pdf.html @@ -0,0 +1,18 @@ +{% extends "ishtar/sheet_operation.html" %} +{% block css_head %} +<link rel="stylesheet" href="{{MEDIA_URL}}/media/style_basic.css" /> +{% endblock %} +{% block main_head %} +{{ block.super }} +<div id="pdfheader"> +Ishtar – {{APP_NAME}} – {{item}} +</div> +{% endblock %} +{%block head_sheet%}{%endblock%} +{%block main_foot%} +<div id="pdffooter"> +– <pdf:pagenumber/> – +</div> +</body> +</html> +{%endblock%} diff --git a/archaeological_operations/templates/ishtar/sheet_operation_window.html b/archaeological_operations/templates/ishtar/sheet_operation_window.html new file mode 100644 index 000000000..3accaff42 --- /dev/null +++ b/archaeological_operations/templates/ishtar/sheet_operation_window.html @@ -0,0 +1,3 @@ +{% extends "ishtar/sheet_operation.html" %} +{% block main_head %}{%endblock%} +{% block main_foot %}{%endblock%} diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 23632f1cf..0da649d2d 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2012 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2013 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -72,5 +72,7 @@ urlpatterns += patterns('archaeological_operations.views',       url(r'get-operationsource/(?P<type>.+)?$',             'get_operationsource', name='get-operationsource'),       url(r'dashboard_operation/$', 'dashboard_operation', -         name='dashboard-operation') +         name='dashboard-operation'), +     url(r'autocomplete-patriarche/$', 'autocomplete_patriarche', +           name='autocomplete-patriarche'),  ) diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 9aa2222ba..1ce4c4622 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2012  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2013  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -30,6 +30,30 @@ from wizards import *  from forms import *  import models +def autocomplete_patriarche(request, non_closed=True): +    person_types = request.user.ishtaruser.person.person_type +    if (not request.user.has_perm('ishtar_common.view_operation', +                                  models.Operation) +        and not request.user.has_perm('ishtar_common.view_own_operation', +                                      models.Operation) +        and not person_types.rights.filter( +                                  wizard__url_name='operation_search').count()): +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    for q in q.split(' '): +        query = query & Q(code_patriarche__startswith=q) +    if non_closed: +        query = query & Q(end_date__isnull=True) +    limit = 15 +    operations = models.Operation.objects.filter(query)[:limit] +    data = json.dumps([{'id':operation.code_patriarche, +                        'value':operation.code_patriarche} +                         for operation in operations]) +    return HttpResponse(data, mimetype='text/plain') +  def autocomplete_operation(request, non_closed=True):      person_types = request.user.ishtaruser.person.person_type      if (not request.user.has_perm('ishtar_common.view_operation', @@ -70,9 +94,19 @@ def get_available_operation_code(request, year=None):  get_operation = get_item(models.Operation, 'get_operation', 'operation',      bool_fields = ['end_date__isnull'], +    dated_fields = ['start_date__lte', 'start_date__gte', +                    'excavation_end_date__lte', 'excavation_end_date__gte'],      extra_request_keys={'common_name':'common_name__icontains',                          'end_date':'end_date__isnull', -                        'year_index':('year', 'operation_code')}) +                        'year_index':('year', 'operation_code'), +                        'start_before':'start_date__lte', +                        'start_after':'start_date__gte', +                        'end_before':'excavation_end_date__lte', +                        'end_after':'excavation_end_date__gte', +                        'parcel_0':'parcels__section', +                        'parcel_1':'parcels__parcel_number', +                        }, +    )  show_operation = show_item(models.Operation, 'operation')  revert_operation = revert_item(models.Operation) @@ -88,7 +122,6 @@ get_administrativeactop = get_item(models.AdministrativeAct,                          'operation__towns':'operation__towns__pk',                          'act_type__intented_to':'act_type__intented_to'}) -  def dashboard_operation(request, *args, **kwargs):      """      Operation dashboard diff --git a/archaeological_operations/widgets.py b/archaeological_operations/widgets.py new file mode 100644 index 000000000..0e84b2047 --- /dev/null +++ b/archaeological_operations/widgets.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2013 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django import forms +from django.forms import widgets + +class ParcelWidget(widgets.MultiWidget): +    def __init__(self, attrs=None): +        if not attrs: +            attrs = {'class':'widget-parcel'} +        elif 'class' not in attrs: +            attrs['class'] = 'widget-parcel' +        else: +            attrs['class'] += ' widget-parcel' +        _widgets = ( +            widgets.TextInput(attrs=attrs), +            widgets.TextInput(attrs=attrs), +            ) +        super(ParcelWidget, self).__init__(_widgets, attrs) + +    def decompress(self, value): +        if value: +            return value +        return [None, None] + +    def format_output(self, rendered_widgets): +        return u' / '.join(rendered_widgets) diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index 3281a5723..4205144e6 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -27,16 +27,22 @@ from django.utils.translation import ugettext_lazy as _  from ishtar_common.wizards import Wizard, ClosingWizard, DeletionWizard, \                                    SourceWizard  import models +from forms import ParcelForm  class OperationWizard(Wizard):      model = models.Operation      object_parcel_type = 'operation' +    parcel_step_key = 'parcelsgeneral-'      def get_template_names(self):          templates = super(OperationWizard, self).get_template_names() -        current_step = self.steps. current +        current_step = self.steps.current          if current_step.startswith('towns-'): -            templates = ['ishtar/wizard/towns_wizard.html'] + templates +            #templates = ['ishtar/wizard/towns_wizard.html'] + templates +            pass +        if current_step.startswith('parcels-') or \ +           current_step.startswith('parcelsgeneral-') : +            templates = ['ishtar/wizard/parcels_wizard.html'] + templates          return templates      def get_context_data(self, form, **kwargs): @@ -121,7 +127,7 @@ class OperationWizard(Wizard):          Show a specific warning if no archaelogical file is provided          """          datas = super(OperationWizard, self).get_formated_datas(forms) -        # if the general town form is used the advertissement is pertinent +        # if the general town form is used the advertissement is relevant          has_no_af = [form.prefix for form in forms                    if form.prefix == 'townsgeneral-operation'] and True          if has_no_af: @@ -130,6 +136,33 @@ class OperationWizard(Wizard):                  + datas          return datas +    def get_form_initial(self, step, data=None): +        initial = super(OperationWizard, self).get_form_initial(step) +        self.form_initialized = False +        if not step.startswith(self.parcel_step_key): +            return initial +        if initial: +            default = initial[-1].copy() +            if 'parcel_number' in default: +                default.pop('parcel_number') +            initial.append(default) +            # necessary to get the appropriate form number +            self.form_initialized = True +        elif data: +            numbers, keys = set(), set() +            for k in data: +                items = k.split('-') +                try: +                    numbers.add(int(items[-2])) +                except (ValueError, IndexError): +                    continue +                keys.add(items[-1]) +            if max(numbers) - 1: +                initial = [dict([(k, data[step+'-'+unicode(max(numbers)-1)+'-'+k]) +                                           for k in keys if k != 'parcel_number'])] +            self.form_initialized = True +        return initial +  class OperationModificationWizard(OperationWizard):      modification = True @@ -145,7 +178,7 @@ class OperationDeletionWizard(DeletionWizard):  class OperationSourceWizard(SourceWizard):      model = models.OperationSource -    def get_form_initial(self, step): +    def get_form_initial(self, step, data=None):          initial = super(OperationSourceWizard, self).get_form_initial(step)          # put default index and operation_id field in the main source form          general_form_key = 'selec-' + self.url_name  | 
