summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root@viserion.(none)>2013-04-04 22:43:13 +0000
committerroot <root@viserion.(none)>2013-04-04 22:43:13 +0000
commit0b9a486b5e79d36c7eb7fa9592e1ebb4ec9ae668 (patch)
treea2c624b1ce76c6d57a8a156766e4863710d8ae19
parent199f535e39880d6ddbbe6a068378fec7ff9fc084 (diff)
parentb2a879890cef5721accff66904be478de488b120 (diff)
downloadIshtar-0b9a486b5e79d36c7eb7fa9592e1ebb4ec9ae668.tar.bz2
Ishtar-0b9a486b5e79d36c7eb7fa9592e1ebb4ec9ae668.zip
Merge branch 'master' of lysithea.proxience.net:/home/proxience/git/ishtar
-rw-r--r--archaeological_context_records/forms.py16
-rw-r--r--archaeological_context_records/templates/ishtar/sheet_contextrecord.html (renamed from ishtar_common/templates/sheet_contextrecord.html)2
-rw-r--r--archaeological_context_records/templates/ishtar/sheet_contextrecord_window.html (renamed from ishtar_common/templates/sheet_contextrecord_window.html)2
-rw-r--r--archaeological_context_records/views.py7
-rw-r--r--archaeological_files/forms.py17
-rw-r--r--archaeological_files/models.py6
-rw-r--r--archaeological_files/templates/ishtar/sheet_file.html (renamed from ishtar_common/templates/sheet_file.html)24
-rw-r--r--archaeological_files/templates/ishtar/sheet_file_pdf.html (renamed from ishtar_common/templates/sheet_file_pdf.html)2
-rw-r--r--archaeological_files/templates/ishtar/sheet_file_window.html (renamed from ishtar_common/templates/sheet_file_window.html)2
-rw-r--r--archaeological_files/views.py8
-rw-r--r--archaeological_files/wizards.py8
-rw-r--r--archaeological_finds/forms.py4
-rw-r--r--archaeological_finds/models.py8
-rw-r--r--archaeological_operations/forms.py70
-rw-r--r--archaeological_operations/models.py22
-rw-r--r--archaeological_operations/templates/ishtar/sheet_operation.html (renamed from ishtar_common/templates/sheet_operation.html)10
-rw-r--r--archaeological_operations/templates/ishtar/sheet_operation_pdf.html (renamed from ishtar_common/templates/sheet_operation_pdf.html)2
-rw-r--r--archaeological_operations/templates/ishtar/sheet_operation_window.html (renamed from ishtar_common/templates/sheet_operation_window.html)2
-rw-r--r--archaeological_operations/urls.py6
-rw-r--r--archaeological_operations/views.py39
-rw-r--r--archaeological_operations/widgets.py43
-rw-r--r--archaeological_operations/wizards.py41
-rw-r--r--archaeological_warehouse/forms.py5
-rw-r--r--ishtar_common/forms.py6
-rw-r--r--ishtar_common/forms_common.py4
-rw-r--r--ishtar_common/models.py1
-rw-r--r--ishtar_common/static/media/style.css16
-rw-r--r--ishtar_common/templates/blocks/form_snippet.html (renamed from ishtar_common/templates/form_snippet.html)0
-rw-r--r--ishtar_common/templates/blocks/inline_formset.html25
-rw-r--r--ishtar_common/templates/ishtar/sheet.html (renamed from ishtar_common/templates/sheet.html)0
-rw-r--r--ishtar_common/templates/ishtar/wizard/default_wizard.html4
-rw-r--r--ishtar_common/templates/ishtar/wizard/parcels_wizard.html28
-rw-r--r--ishtar_common/templates/ishtar/wizard/towns_wizard.html10
-rw-r--r--ishtar_common/templatetags/inline_formset.py18
-rw-r--r--ishtar_common/templatetags/table_form.py2
-rw-r--r--ishtar_common/views.py25
-rw-r--r--ishtar_common/widgets.py8
-rw-r--r--ishtar_common/wizards.py21
38 files changed, 429 insertions, 85 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py
index 41e4a1e20..fce5193d6 100644
--- a/archaeological_context_records/forms.py
+++ b/archaeological_context_records/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
@@ -36,16 +36,17 @@ import models
from ishtar_common import widgets
from ishtar_common.forms import FinalForm, FinalForm, FormSet, \
- formset_factory, get_now, reverse_lazy, get_form_selection
+ formset_factory, get_now, reverse_lazy, get_form_selection, TableSelect
from ishtar_common.forms_common import get_town_field, SourceForm, \
SourceSelect, AuthorFormset
-from archaeological_operations.forms import OperationSelect
+from archaeological_operations.forms import OperationSelect, ParcelField
-class RecordSelect(forms.Form):
+class RecordSelect(TableSelect):
parcel__town = get_town_field()
operation__year = forms.IntegerField(label=_(u"Year"))
datings__period = forms.ChoiceField(label=_(u"Period"), choices=[])
unit = forms.ChoiceField(label=_(u"Unit type"), choices=[])
+ parcel = ParcelField(label=_("Parcel (section/number)"))
def __init__(self, *args, **kwargs):
super(RecordSelect, self).__init__(*args, **kwargs)
self.fields['datings__period'].choices = Period.get_types()
@@ -53,6 +54,13 @@ class RecordSelect(forms.Form):
self.fields['unit'].choices = models.Unit.get_types()
self.fields['unit'].help_text = models.Unit.get_help()
+ def get_input_ids(self):
+ ids = super(RecordSelect, self).get_input_ids()
+ ids.pop(ids.index('parcel'))
+ ids.append('parcel_0')
+ ids.append('parcel_1')
+ return ids
+
class RecordFormSelection(forms.Form):
form_label = _("Context record search")
associated_models = {'pk':models.ContextRecord}
diff --git a/ishtar_common/templates/sheet_contextrecord.html b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html
index 806b06288..d8e06f022 100644
--- a/ishtar_common/templates/sheet_contextrecord.html
+++ b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html
@@ -1,4 +1,4 @@
-{% extends "sheet.html" %}
+{% extends "ishtar/sheet.html" %}
{% load i18n %}
{% block content %}
<div class='tool'>{%trans "Export as:"%} <a href='{% url show-file item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-file item.pk "pdf" %}'>{%trans "PDF file"%}</a></div>
diff --git a/ishtar_common/templates/sheet_contextrecord_window.html b/archaeological_context_records/templates/ishtar/sheet_contextrecord_window.html
index 7ff65d1e7..b485ebd47 100644
--- a/ishtar_common/templates/sheet_contextrecord_window.html
+++ b/archaeological_context_records/templates/ishtar/sheet_contextrecord_window.html
@@ -1,3 +1,3 @@
-{% extends "sheet_contextrecord.html" %}
+{% extends "ishtar/sheet_contextrecord.html" %}
{% block main_head %}{%endblock%}
{% block main_foot %}{%endblock%}
diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py
index bd18ffa49..c59446bcf 100644
--- a/archaeological_context_records/views.py
+++ b/archaeological_context_records/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,7 +30,10 @@ get_contextrecord = get_item(models.ContextRecord,
'get_contextrecord', 'contextrecord',
extra_request_keys={'parcel__town':'parcel__town__pk',
'operation__year':'operation__year__contains',
- 'datings__period':'datings__period__pk'},)
+ 'datings__period':'datings__period__pk',
+ 'parcel_0':'operation__parcels__section',
+ 'parcel_1':'operation__parcels__parcel_number',
+ },)
get_contextrecordsource = get_item(models.ContextRecordSource,
'get_contextrecordsource', 'contextrecordsource',
extra_request_keys={
diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py
index 564d0c6fc..ea12c984c 100644
--- a/archaeological_files/forms.py
+++ b/archaeological_files/forms.py
@@ -36,13 +36,14 @@ from ishtar_common.models import Person, PersonType, Town, Organization, \
from archaeological_operations.models import ActType, AdministrativeAct
import models
from ishtar_common.forms import FinalForm, FormSet, ClosingDateFormSelection, \
- formset_factory, get_now, reverse_lazy
+ formset_factory, get_now, reverse_lazy, TableSelect
from ishtar_common.forms_common import get_town_field, get_person_field
from archaeological_operations.forms import AdministrativeActOpeForm, \
- AdministrativeActOpeFormSelection, FinalAdministrativeActDeleteForm
+ AdministrativeActOpeFormSelection, FinalAdministrativeActDeleteForm, \
+ ParcelField
from ishtar_common import widgets
-class FileSelect(forms.Form):
+class FileSelect(TableSelect):
towns = get_town_field()
in_charge = get_person_field(label=_(u"Person in charge"),
person_type='sra_agent')
@@ -50,12 +51,20 @@ class FileSelect(forms.Form):
choices=models.FileType.get_types())
saisine_type = forms.ChoiceField(label=_("Saisine type"), choices=[])
year = forms.IntegerField(label=_("Year"))
+ parcel = ParcelField(label=_("Parcel (section/number)"))
def __init__(self, *args, **kwargs):
super(FileSelect, self).__init__(*args, **kwargs)
self.fields['saisine_type'].choices = models.SaisineType.get_types()
self.fields['saisine_type'].help_text = models.SaisineType.get_help()
+ def get_input_ids(self):
+ ids = super(FileSelect, self).get_input_ids()
+ ids.pop(ids.index('parcel'))
+ ids.append('parcel_0')
+ ids.append('parcel_1')
+ return ids
+
class FileFormSelection(forms.Form):
form_label = _("Archaeological file search")
associated_models = {'pk':models.File}
@@ -170,7 +179,7 @@ class FinalFileDeleteForm(FinalForm):
confirm_msg = " "
confirm_end_msg = _(u"Would you like to delete this archaelogical file ?")
-class AdministrativeActFileSelect(forms.Form):
+class AdministrativeActFileSelect(TableSelect):
associated_file__towns = get_town_field()
act_type = forms.ChoiceField(label=_("Act type"), choices=[])
diff --git a/archaeological_files/models.py b/archaeological_files/models.py
index a91f6ed69..1e2c36ed0 100644
--- a/archaeological_files/models.py
+++ b/archaeological_files/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
@@ -133,6 +133,10 @@ class File(BaseHistorizedItem, OwnPerms):
for k in ['internal_reference',] if getattr(self, k)]
return settings.JOINT.join(items)
+ def grouped_parcels(self):
+ from archaeological_operations.models import Parcel
+ return Parcel.grouped_parcels(list(self.parcels.all()))
+
@classmethod
def get_query_owns(cls, user):
return Q(history_modifier=user) & Q(end_date__isnull=True)
diff --git a/ishtar_common/templates/sheet_file.html b/archaeological_files/templates/ishtar/sheet_file.html
index 88ef1b3a2..bdf0bd4ff 100644
--- a/ishtar_common/templates/sheet_file.html
+++ b/archaeological_files/templates/ishtar/sheet_file.html
@@ -1,4 +1,4 @@
-{% extends "sheet.html" %}
+{% extends "ishtar/sheet.html" %}
{% load i18n %}
{% block content %}
{% if previous or next %}
@@ -63,6 +63,28 @@
{% endif %}
<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 "Admninistrative acts"%}</caption>
<tr>
<th>{% trans "Year" %}</th>
diff --git a/ishtar_common/templates/sheet_file_pdf.html b/archaeological_files/templates/ishtar/sheet_file_pdf.html
index 3c77c75f8..29a4f4dec 100644
--- a/ishtar_common/templates/sheet_file_pdf.html
+++ b/archaeological_files/templates/ishtar/sheet_file_pdf.html
@@ -1,4 +1,4 @@
-{% extends "sheet_file.html" %}
+{% extends "ishtar/sheet_file.html" %}
{% block css_head %}
<link rel="stylesheet" href="{{MEDIA_URL}}/media/style_basic.css" />
{% endblock %}
diff --git a/ishtar_common/templates/sheet_file_window.html b/archaeological_files/templates/ishtar/sheet_file_window.html
index e9debdd0d..e3486c052 100644
--- a/ishtar_common/templates/sheet_file_window.html
+++ b/archaeological_files/templates/ishtar/sheet_file_window.html
@@ -1,3 +1,3 @@
-{% extends "sheet_file.html" %}
+{% extends "ishtar/sheet_file.html" %}
{% block main_head %}{%endblock%}
{% block main_foot %}{%endblock%}
diff --git a/archaeological_files/views.py b/archaeological_files/views.py
index 3ef8c0f28..2b5003911 100644
--- a/archaeological_files/views.py
+++ b/archaeological_files/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
@@ -60,7 +60,11 @@ def autocomplete_file(request):
for file in files])
return HttpResponse(data, mimetype='text/plain')
-get_file = get_item(models.File, 'get_file', 'file')
+get_file = get_item(models.File, 'get_file', 'file',
+ extra_request_keys={'parcel_0':'operations__parcels__section',
+ 'parcel_1':'operations__parcels__parcel_number',
+ },
+ )
show_file = show_item(models.File, 'file')
revert_file = revert_item(models.File)
diff --git a/archaeological_files/wizards.py b/archaeological_files/wizards.py
index e2f6722ef..c475de47d 100644
--- a/archaeological_files/wizards.py
+++ b/archaeological_files/wizards.py
@@ -25,16 +25,18 @@ from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from ishtar_common.wizards import Wizard, ClosingWizard
-from archaeological_operations.wizards import OperationAdministrativeActWizard,\
+from archaeological_operations.wizards import OperationWizard,\
+ OperationAdministrativeActWizard,\
AdministrativeActDeletionWizard
from ishtar_common.models import Town
from archaeological_operations.models import AdministrativeAct, Parcel, \
Operation
import models
-class FileWizard(Wizard):
+class FileWizard(OperationWizard):
model = models.File
object_parcel_type = 'associated_file'
+ parcel_step_key = 'parcels-'
def get_form(self, step=None, data=None, files=None):
"""
@@ -103,7 +105,7 @@ class FileWizard(Wizard):
continue
try:
dct['town'] = models.Town.objects.get(pk=int(dct['town']))
- except (ValueError, ObjectDoesNotExist):
+ except (ValueError, ObjectDoesNotExist, KeyError):
continue
dct['associated_file'], dct['operation'] = None, None
dct[self.object_parcel_type] = obj
diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py
index c5480d8a8..feaad0e23 100644
--- a/archaeological_finds/forms.py
+++ b/archaeological_finds/forms.py
@@ -39,7 +39,7 @@ import models
from ishtar_common import widgets
from ishtar_common.forms import FinalForm, FormSet, FloatField, \
- formset_factory, get_now, get_form_selection, reverse_lazy
+ formset_factory, get_now, get_form_selection, reverse_lazy, TableSelect
from ishtar_common.forms_common import get_town_field, \
SourceForm, SourceSelect, SourceDeletionForm, AuthorFormset
from archaeological_context_records.forms import RecordFormSelection
@@ -81,7 +81,7 @@ class DateForm(forms.Form):
self.fields['dating__dating_type'].choices = DatingType.get_types()
self.fields['dating__dating_type'].help_text = DatingType.get_help()
-class FindSelect(forms.Form):
+class FindSelect(TableSelect):
base_finds__context_record__parcel__town = get_town_field()
base_finds__context_record__operation__year = forms.IntegerField(
label=_(u"Year"))
diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py
index a02cb4402..ce0df10cf 100644
--- a/archaeological_finds/models.py
+++ b/archaeological_finds/models.py
@@ -82,7 +82,9 @@ class BaseFind(BaseHistorizedItem, OwnPerms):
return settings.JOINT.join(finds)
def _real_label(self):
- if not self.context_record.parcel.operation.code_patriarche:
+ if not self.context_record.parcel \
+ or not self.context_record.parcel.operation \
+ or not self.context_record.parcel.operation.code_patriarche:
return
find = self.get_last_find()
lbl = find.label or self.label
@@ -92,7 +94,9 @@ class BaseFind(BaseHistorizedItem, OwnPerms):
lbl) if it])
def _temp_label(self):
- if self.context_record.parcel.operation.code_patriarche:
+ if not self.context_record.parcel \
+ or not self.context_record.parcel.operation \
+ or not self.context_record.parcel.operation.code_patriarche:
return
find = self.get_last_find()
lbl = find.label or self.label
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/ishtar_common/templates/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html
index 7b161f641..491304125 100644
--- a/ishtar_common/templates/sheet_operation.html
+++ b/archaeological_operations/templates/ishtar/sheet_operation.html
@@ -1,4 +1,4 @@
-{% extends "sheet.html" %}
+{% 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>
@@ -61,15 +61,15 @@
<th>{% trans "Commune" %}</th>
<th>{% trans "Year" %}</th>
<th>{% trans "Section" %}</th>
- <th>{% trans "Parcel" %}</th>
+ <th>{% trans "Parcels" %}</th>
{#<th>{% trans "Owner" %}</th>#}
</tr>
- {% for parcel in item.parcels.all %}
+ {% for parcel in item.grouped_parcels %}
<tr>
<td class='string'>{{parcel.town}}</td>
<td>{{parcel.year}}</td>
<td>{{parcel.section}}</td>
- <td>{{parcel.parcel_number}}</td>
+ <td>{{parcel.parcel_numbers|join:", "}}</td>
{#<td class='string'>{{operation.parcel.owner}}</td>#}
</tr>
{% empty %}
@@ -78,7 +78,7 @@
</table>
<table>
- <caption>{%trans "Admninistrative acts"%}</caption>
+ <caption>{%trans "Administrative acts"%}</caption>
<tr>
<th>{% trans "Year" %}</th>
<th>{% trans "Reference" %}</th>
diff --git a/ishtar_common/templates/sheet_operation_pdf.html b/archaeological_operations/templates/ishtar/sheet_operation_pdf.html
index 3397d5f43..9ef0edbf7 100644
--- a/ishtar_common/templates/sheet_operation_pdf.html
+++ b/archaeological_operations/templates/ishtar/sheet_operation_pdf.html
@@ -1,4 +1,4 @@
-{% extends "sheet_operation.html" %}
+{% extends "ishtar/sheet_operation.html" %}
{% block css_head %}
<link rel="stylesheet" href="{{MEDIA_URL}}/media/style_basic.css" />
{% endblock %}
diff --git a/ishtar_common/templates/sheet_operation_window.html b/archaeological_operations/templates/ishtar/sheet_operation_window.html
index 9c595a1e9..3accaff42 100644
--- a/ishtar_common/templates/sheet_operation_window.html
+++ b/archaeological_operations/templates/ishtar/sheet_operation_window.html
@@ -1,3 +1,3 @@
-{% extends "sheet_operation.html" %}
+{% 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
diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py
index 2e1bfcc05..69bb2cae3 100644
--- a/archaeological_warehouse/forms.py
+++ b/archaeological_warehouse/forms.py
@@ -27,7 +27,8 @@ from ishtar_common.models import Person, valid_id
from archaeological_finds.models import TreatmentType
import models
from ishtar_common import widgets
-from ishtar_common.forms import name_validator, reverse_lazy, get_form_selection
+from ishtar_common.forms import name_validator, reverse_lazy, \
+ get_form_selection, TableSelect
from archaeological_finds.forms import FindMultipleFormSelection
def get_warehouse_field(label=_(u"Warehouse"), required=True):
@@ -109,7 +110,7 @@ class ContainerForm(forms.Form):
new_item.save()
return new_item
-class ContainerSelect(forms.Form):
+class ContainerSelect(TableSelect):
location = get_warehouse_field()
container_type = forms.ChoiceField(label=_(u"Container type"), choices=[])
reference = forms.CharField(label=_(u"Reference"))
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index d66d6d4cc..cb007442e 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2010-2011 É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
@@ -101,6 +101,10 @@ class FormSet(BaseFormSet):
form.fields[DELETION_FIELD_NAME].label = ''
form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget()
+class TableSelect(forms.Form):
+ def get_input_ids(self):
+ return self.fields.keys()
+
def get_now():
format = formats.get_format('DATE_INPUT_FORMATS')[0]
value = datetime.datetime.now().strftime(format)
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 34a930e36..52fcfc97a 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -37,7 +37,7 @@ from django.utils.translation import ugettext_lazy as _
import models
import widgets
-from forms import FinalForm, FormSet, reverse_lazy, name_validator
+from forms import FinalForm, FormSet, reverse_lazy, name_validator, TableSelect
def get_town_field(label=_(u"Town"), required=True):
help_text = _(u"<p>Type name, department code and/or postal code of the "
@@ -234,7 +234,7 @@ class SourceForm(forms.Form):
super(SourceForm, self).__init__(*args, **kwargs)
self.fields['source_type'].choices = models.SourceType.get_types()
-class SourceSelect(forms.Form):
+class SourceSelect(TableSelect):
authors = forms.IntegerField(
widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \
'autocomplete-author', associated_model=models.Author),
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index e5d966bf9..fd5bb5871 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -451,6 +451,7 @@ class Dashboard:
operation_mode_pk = self.get_mode(dict(zip(operations,
operation_numbers)))
if operation_mode_pk:
+ from archaeological_operations.models import Operation
self.operation_mode = unicode(Operation.objects.get(
pk=operation_mode_pk))
diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css
index 2aa673b51..fe078fa3c 100644
--- a/ishtar_common/static/media/style.css
+++ b/ishtar_common/static/media/style.css
@@ -528,3 +528,19 @@ a.remove{
border:1px solid;
}
+.form table.inline-table th{
+ text-align:center;
+ font-weight:bold;
+}
+
+.form table.inline-table td{
+ text-align:center;
+}
+
+.inline-table input[type=text]{
+ width:60px;
+}
+
+.widget-parcel{
+ width:60px;
+}
diff --git a/ishtar_common/templates/form_snippet.html b/ishtar_common/templates/blocks/form_snippet.html
index 2f841e078..2f841e078 100644
--- a/ishtar_common/templates/form_snippet.html
+++ b/ishtar_common/templates/blocks/form_snippet.html
diff --git a/ishtar_common/templates/blocks/inline_formset.html b/ishtar_common/templates/blocks/inline_formset.html
new file mode 100644
index 000000000..e36405118
--- /dev/null
+++ b/ishtar_common/templates/blocks/inline_formset.html
@@ -0,0 +1,25 @@
+{% load i18n %}
+ {% if extra_formset.non_form_errors %}<div class='errors'>{{extra_formset.non_form_errors.as_ul}}</div>{% endif %}
+ {% if header %}<table class='inline-table'>
+ <caption>{% trans caption %}</caption>
+ {% endif %}{% for frm in formset%}{% if header %}<thead>
+ <tr>{% for field in frm.visible_fields%}
+ <th>{{field.label}}</th>{%endfor%}
+ </tr>
+ </thead>{% endif %}
+ {% if forloop.first and not skip %}<tbody>{%endif%}
+ {% if not skip or not forloop.first %}<tr>{% endif %}{% for field in frm.visible_fields %}
+ <td>
+ {% if field.errors %}<div class='errors'>{{ field.errors.as_ul }}</div>{% endif %}
+ {{ field }}
+ {# Include the hidden fields in the form #}
+ {% if forloop.first %}
+ {{ formset.management_form }}
+ {% for hidden in frm.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ {% endif %}
+ </td>{% endfor %}
+ {% if not skip or not forloop.last %}</tr>{% endif %}{%endfor%}
+ {% if not skip %}</tbody>{% endif %}{% if header %}
+ </table>{% endif %}
diff --git a/ishtar_common/templates/sheet.html b/ishtar_common/templates/ishtar/sheet.html
index 5608a684f..5608a684f 100644
--- a/ishtar_common/templates/sheet.html
+++ b/ishtar_common/templates/ishtar/sheet.html
diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html
index e2abc80b6..b56324a78 100644
--- a/ishtar_common/templates/ishtar/wizard/default_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html
@@ -6,6 +6,7 @@
{{form.media}}
{% endblock %}
{% block content %}
+{% block wizard_head %}
<h2>{{wizard_label}}</h2>
<form action="." method="post" name='wizard'>{% csrf_token %}
<ul id='form_path'>
@@ -17,6 +18,8 @@
<li>&raquo;&nbsp;<button name="form_prev_step" value="{{forloop.counter|add:previous_step_counter}}">{{step.form_label}}</button></li>
{% endfor %}
</ul>
+{% endblock %}
+{% block wizard_form %}
<div class='form'>
{% if reminder %}<div class='reminder'>{{ reminder }}</div>{%endif%}
{{ wizard.form.media }}
@@ -43,3 +46,4 @@
</div>
</form>
{% endblock %}
+{% endblock %}
diff --git a/ishtar_common/templates/ishtar/wizard/parcels_wizard.html b/ishtar_common/templates/ishtar/wizard/parcels_wizard.html
new file mode 100644
index 000000000..94e9820ab
--- /dev/null
+++ b/ishtar_common/templates/ishtar/wizard/parcels_wizard.html
@@ -0,0 +1,28 @@
+{% extends "ishtar/wizard/default_wizard.html" %}
+{% load i18n range inline_formset %}
+{% block extra_head %}
+{{wizard.form.media}}
+{% endblock %}
+{% block wizard_form %}
+<div class='form'>
+{% if reminder %}<div class='reminder'>{{ reminder }}</div>{%endif%}
+{{ wizard.form.media }}
+{{ wizard.management_form }}
+ {{ wizard.form.management_form }}
+<div class='top_button'><input type="submit" id="submit_form" value="{% trans "Validate" %}"/></div>
+ {%if wizard.form.non_form_errors%}
+<table class='formset'>
+<tr class='error'><th colspan='2'>{{wizard.form.non_form_errors}}</th></tr>
+</table>{%endif%}
+<table class='inline-table'>
+ <tr>{% for field in wizard.form.forms.0 %}<th>{{ field.label_tag }}</th>{% endfor %}</tr>
+ {% inline_formset 'Parcels' wizard.form.forms False %}
+</table>
+<p><button name="formset_modify" value="{{wizard.steps.current}}">{% trans "Add/Modify" %}</button></p>
+<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
+{{ previous_fields|safe }}
+<input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/>
+{% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %}
+</div>
+</form>
+{% endblock %}
diff --git a/ishtar_common/templates/ishtar/wizard/towns_wizard.html b/ishtar_common/templates/ishtar/wizard/towns_wizard.html
index cd40e6049..cc3487df3 100644
--- a/ishtar_common/templates/ishtar/wizard/towns_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/towns_wizard.html
@@ -4,15 +4,7 @@
{% block extra_head %}
{{wizard.form.media}}
{% endblock %}
-{% block content %}
-<h2>{{wizard_label}}</h2>
-<form action="." method="post" name='wizard'>{% csrf_token %}
-<ul id='form_path'>
-{% for step in previous_steps %}
- <li>&raquo;&nbsp;<button name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li>
-{% endfor %}
- <li class='current'>&raquo;&nbsp;<a href='#'>{{current_step.form_label}}</a></li>
-</ul>
+{% block wizard_form %}
<div class='form'>
{% if TOWNS %}
{% if wizard.form.forms %}
diff --git a/ishtar_common/templatetags/inline_formset.py b/ishtar_common/templatetags/inline_formset.py
new file mode 100644
index 000000000..c3220f207
--- /dev/null
+++ b/ishtar_common/templatetags/inline_formset.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from django import template
+from django.utils.translation import ugettext as _
+import re
+
+register = template.Library()
+
+@register.inclusion_tag('blocks/inline_formset.html')
+def inline_formset(caption, formset, header=True, skip=False):
+ u"""
+ Render a formset as an inline table.
+ For i18n of the caption be carreful to add manualy the caption label to
+ the translated fields
+ """
+ return {'caption':caption, 'formset':formset, 'header':header, 'skip':skip}
+
diff --git a/ishtar_common/templatetags/table_form.py b/ishtar_common/templatetags/table_form.py
index 7adb54d65..0ab49d93f 100644
--- a/ishtar_common/templatetags/table_form.py
+++ b/ishtar_common/templatetags/table_form.py
@@ -5,6 +5,6 @@ from django.template import Library
register = Library()
-@register.inclusion_tag('form_snippet.html')
+@register.inclusion_tag('blocks/form_snippet.html')
def table_form(form):
return {'form': form}
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 4a1a656d9..641ca8046 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/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
@@ -170,10 +170,10 @@ def format_val(val):
return unicode(val)
HIERARCHIC_LEVELS = 5
-HIERARCHIC_FIELDS = ['period', 'unit', 'material_type']
+HIERARCHIC_FIELDS = ['periods', 'period', 'unit', 'material_type']
PRIVATE_FIELDS = ('id', 'history_modifier', 'order')
def get_item(model, func_name, default_name, extra_request_keys=[],
- base_request={}, bool_fields=[]):
+ base_request={}, bool_fields=[], dated_fields=[]):
"""
Generic treatment of tables
"""
@@ -213,7 +213,18 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
dct.pop(k)
else:
dct[k] = dct[k] == u"2" and True or False
-
+ for k in dated_fields:
+ if k in dct:
+ if not dct[k]:
+ dct.pop(k)
+ try:
+ items = dct[k].split('/')
+ assert len(items) == 3
+ dct[k] = datetime.date(*map(lambda x: int(x),
+ reversed(items))
+ ).strftime('%Y-%m-%d')
+ except AssertionError:
+ dct.pop(k)
# manage hierarchic conditions
or_reqs = []
for req in dct.copy():
@@ -373,7 +384,7 @@ def show_item(model, name):
n.strftime('%Y%m%d-%H%M%S'))
if doc_type == "odt" and settings.XHTML2ODT_PATH and \
settings.ODT_TEMPLATE:
- tpl = loader.get_template('sheet_%s.html' % name)
+ tpl = loader.get_template('ishtar/sheet_%s.html' % name)
content = tpl.render(context_instance)
try:
tidy_options = dict(output_xhtml=1, add_xml_decl=1, indent=1,
@@ -413,7 +424,7 @@ def show_item(model, name):
response.write(odtfile)
return response
elif doc_type == 'pdf':
- tpl = loader.get_template('sheet_%s_pdf.html' % name)
+ tpl = loader.get_template('ishtar/sheet_%s_pdf.html' % name)
content = tpl.render(context_instance)
result = StringIO.StringIO()
html = content.encode('utf-8')
@@ -427,7 +438,7 @@ def show_item(model, name):
return response
return HttpResponse(content, content_type="application/xhtml")
else:
- tpl = loader.get_template('sheet_%s_window.html' % name)
+ tpl = loader.get_template('ishtar/sheet_%s_window.html' % name)
content = tpl.render(context_instance)
return HttpResponse(content, content_type="application/xhtml")
return func
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index ecc48a1e8..06d6f20f0 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -206,7 +206,7 @@ class JQueryJqGrid(forms.RadioSelect):
self.source_full = source_full
def render(self, name, value=None, attrs=None):
- t = loader.get_template('form_snippet.html')
+ t = loader.get_template('blocks/form_snippet.html')
rendered = t.render(Context({'form':self.form}))
rendered += u"\n</table>\n"\
u"<button id='search_%s' class='submit'>%s</button>" % (
@@ -219,8 +219,8 @@ class JQueryJqGrid(forms.RadioSelect):
rendered += "\n<h4>%s</h4>\n" % unicode(_("Search and select an item"))
extra_cols = []
col_names, col_idx = [], []
- for k in self.form.fields:
- field = self.form.fields[k]
+ for k in self.form.get_input_ids():
+ #field = self.form.fields[k]
col_idx.append(u'"%s"' % k)
for field_name in getattr(self.associated_model, self.table_cols):
field = self.associated_model
@@ -292,7 +292,7 @@ class JQueryJqGrid(forms.RadioSelect):
}
}
var mygrid = jQuery("#grid_%(name)s");
- var url = "%(source)s?submited=1&amp;" + data;
+ var url = "%(source)s?submited=1&" + data;
mygrid.setGridParam({url:url});
mygrid.trigger("reloadGrid");
return false;
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 8b6e1a50d..e421c25dd 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.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
@@ -461,15 +461,26 @@ class Wizard(NamedUrlWizardView):
k = u'-'.join(items)
data[k] = data.pop(key)[0]
# get a form key
- base_key = form.form.base_fields.keys()[0]
- init = self.get_form_initial(step)
+ frm = form.form
+ if callable(frm):
+ frm = frm()
+ base_key = frm.base_fields.keys()[-1]
+ init = self.get_form_initial(step, data=data)
total_field = len([key for key in data.keys()
if base_key in key.split('-')
and data[key]])
- if init and not to_delete:
+ if init and not to_delete and (
+ not hasattr(self, 'form_initialized') or
+ not self.form_initialized):
total_field = max((total_field, len(init)))
data[step + u'-INITIAL_FORMS'] = unicode(total_field)
data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1)
+ # update initialization
+ if request.POST and init and hasattr(self, 'form_initialized') \
+ and self.form_initialized:
+ for k in init[0]:
+ data[step + '-' + unicode(total_field) + '-' + k] = \
+ init[0][k]
data = data or None
form = super(Wizard, self).get_form(step, data, files)
return form
@@ -561,7 +572,7 @@ class Wizard(NamedUrlWizardView):
pass
return current_obj
- def get_form_initial(self, step):
+ def get_form_initial(self, step, data=None):
current_obj = self.get_current_object()
current_step = self.steps.current
request = self.request