summaryrefslogtreecommitdiff
path: root/archaeological_operations
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2012-10-20 15:25:07 +0200
committerÉtienne Loks <etienne.loks@peacefrogs.net>2012-10-20 15:25:07 +0200
commitbeb45ac4d420034f9aec53eaf7ea783e178d5361 (patch)
treeb26e820671aa6af552a4b03147c44a9d2aa84be8 /archaeological_operations
parent666747d6371a908e6fe1968e2e802e3065d610c5 (diff)
downloadIshtar-beb45ac4d420034f9aec53eaf7ea783e178d5361.tar.bz2
Ishtar-beb45ac4d420034f9aec53eaf7ea783e178d5361.zip
Djangoization - Major refactoring (step 3)
Reorganization of views, urls, menus, admin, forms. Changes on models.
Diffstat (limited to 'archaeological_operations')
-rw-r--r--archaeological_operations/admin.py72
-rw-r--r--archaeological_operations/forms.py804
-rw-r--r--archaeological_operations/ishtar_menu.py98
-rw-r--r--archaeological_operations/migrations/0001_initial.py54
-rw-r--r--archaeological_operations/models.py500
-rw-r--r--archaeological_operations/urls.py75
-rw-r--r--archaeological_operations/views.py97
7 files changed, 1654 insertions, 46 deletions
diff --git a/archaeological_operations/admin.py b/archaeological_operations/admin.py
new file mode 100644
index 000000000..de8b47edc
--- /dev/null
+++ b/archaeological_operations/admin.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012 É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.conf import settings
+from django.contrib import admin
+
+from ishtar_common.admin import HistorizedObjectAdmin
+
+import models
+
+class AdministrativeActAdmin(HistorizedObjectAdmin):
+ list_display = ('operation', 'act_type', 'signature_date')
+ list_filter = ('act_type',)
+ search_fields = ('operation__name',)
+ model = models.AdministrativeAct
+
+admin.site.register(models.AdministrativeAct, AdministrativeActAdmin)
+
+class PeriodAdmin(admin.ModelAdmin):
+ list_display = ('label', 'start_date', 'end_date', 'parent')
+ model = models.Period
+
+admin.site.register(models.Period, PeriodAdmin)
+
+class OperationAdmin(HistorizedObjectAdmin):
+ list_display = ['year', 'operation_code', 'start_date',
+ 'excavation_end_date', 'end_date',
+ 'operation_type']
+ list_filter = ("year", "operation_type",)
+ search_fields = ['towns__name', 'operation_code']
+ if settings.COUNTRY == 'fr':
+ list_display += ['code_patriarche']
+ search_fields += ['code_patriarche']
+ model = models.Operation
+
+admin.site.register(models.Operation, OperationAdmin)
+
+class OperationSourceAdmin(admin.ModelAdmin):
+ list_display = ('operation', 'title', 'source_type',)
+ list_filter = ('source_type',)
+ search_fields = ('title', 'operation__name')
+ model = models.OperationSource
+
+admin.site.register(models.OperationSource, OperationSourceAdmin)
+
+class ParcelAdmin(HistorizedObjectAdmin):
+ list_display = ('section', 'parcel_number', 'operation', 'associated_file')
+ search_fields = ('operation__name',)
+ model = models.Parcel
+
+admin.site.register(models.Parcel, ParcelAdmin)
+
+basic_models = [models.OperationType, models.RemainType, models.ActType,
+ models.ParcelOwner]
+for model in basic_models:
+ admin.site.register(model)
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py
new file mode 100644
index 000000000..d4152d4fa
--- /dev/null
+++ b/archaeological_operations/forms.py
@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2010-2012 É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.
+
+"""
+Operations forms definitions
+"""
+import datetime
+
+from django import forms
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.core import validators
+from django.core.exceptions import ObjectDoesNotExist
+from django.db.models import Max
+from django.utils.translation import ugettext_lazy as _
+
+import models
+import widgets
+from ishtar_common.forms import Wizard, FinalForm, FormSet, SearchWizard, \
+ ClosingWizard, ClosingDateFormSelection, DeletionWizard, formset_factory, \
+ get_now, reverse_lazy, get_form_selection
+from ishtar_common.forms_common import TownForm, TownFormSet, TownFormset, \
+ AuthorFormset, SourceForm, SourceWizard, SourceSelect, \
+ SourceDeletionForm, get_town_field
+
+def is_preventive(form_name, model, type_key='operation_type', key=''):
+ def func(self, request, storage):
+ if storage.prefix not in request.session or \
+ 'step_data' not in request.session[storage.prefix] or \
+ form_name not in request.session[storage.prefix]['step_data'] or\
+ form_name + '-' + type_key not in \
+ request.session[storage.prefix]['step_data'][form_name]:
+ return False
+ try:
+ typ = int(request.session[storage.prefix]['step_data']\
+ [form_name][form_name+'-'+type_key])
+ return model.is_preventive(typ, key)
+ except ValueError:
+ return False
+ return func
+
+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=[models.valid_id(models.Town)])
+ 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']:
+ towns = kwargs['data']['TOWNS']
+ # clean data if not "real" data
+ prefix_value = kwargs['prefix'] + '-town'
+ if not [k for k in kwargs['data'].keys()
+ if k.startswith(prefix_value) and kwargs['data'][k]]:
+ kwargs['data'] = None
+ if 'files' in kwargs:
+ kwargs.pop('files')
+ super(ParcelForm, self).__init__(*args, **kwargs)
+ if towns:
+ self.fields['town'].choices = [('', '--')] + towns
+
+ def clean(self):
+ """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]:
+ 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 "
+ u"fields are required."))
+ return self.cleaned_data
+
+class ParcelFormSet(FormSet):
+ def clean(self):
+ """Checks that no parcels are duplicated."""
+ return self.check_duplicate(('town', 'parcel_number', 'year'),
+ _(u"There are identical parcels."))
+
+ParcelFormSet = formset_factory(ParcelForm, can_delete=True,
+ formset=ParcelFormSet)
+ParcelFormSet.form_label = _(u"Parcels")
+
+class OperationWizard(Wizard):
+ model = models.Operation
+ object_parcel_type = 'operation'
+
+ def get_template(self, request, storage):
+ templates = super(OperationWizard, self).get_template(request, storage)
+ current_step = storage.get_current_step() or self.get_first_step(
+ request, storage)
+ if current_step.startswith('towns-'):
+ templates = ['towns_wizard.html'] + templates
+ return templates
+
+ def get_extra_context(self, request, storage):
+ """
+ Return extra context for templates
+ """
+ context = super(OperationWizard, self).get_extra_context(request,
+ storage)
+ step = self.determine_step(request, storage)
+ if not step.startswith('towns-'):
+ return context
+ context['TOWNS'] = self.get_towns(request, storage)
+ return context
+
+ def get_towns(self, request, storage):
+ """
+ Obtention des villes disponibles
+ """
+ general_form_key = 'general-' + self.url_name
+ towns = []
+ file_id = self.session_get_value(request, storage, general_form_key,
+ "associated_file")
+ if file_id:
+ try:
+ for town in models.File.objects.get(pk=int(file_id)
+ ).towns.all():
+ towns.append((town.pk, unicode(town)))
+ except (ValueError, ObjectDoesNotExist):
+ pass
+ return sorted(towns, key=lambda x:x[1])
+ else:
+ return -1
+
+ def get_form(self, request, storage, step=None, data=None, files=None):
+ """
+ Manage specifics fields
+ """
+ if data:
+ data = data.copy()
+ else:
+ data = {}
+ if not step:
+ step = self.determine_step(request, storage)
+ form = self.get_form_list(request, storage)[step]
+ general_form_key = 'general-' + self.url_name
+ # manage the dynamic choice of towns
+ if step.startswith('towns-') and hasattr(form, 'management_form'):
+ data['TOWNS'] = self.get_towns(request, storage)
+ elif step.startswith('parcels') and hasattr(form, 'management_form'):
+ file_id = self.session_get_value(request, storage, general_form_key,
+ "associated_file")
+ if file_id:
+ parcels = []
+ try:
+ for parcel in models.File.objects.get(pk=int(file_id)
+ ).parcels.all():
+ parcels.append((parcel.pk, parcel.short_label()))
+ except (ValueError, ObjectDoesNotExist):
+ pass
+ data['PARCELS'] = sorted(parcels, key=lambda x:x[1])
+ else:
+ town_form_key = step.startswith('parcelsgeneral') \
+ and 'townsgeneral-' or 'towns-'
+ town_form_key += self.url_name
+ town_ids = self.session_get_value(request, storage,
+ town_form_key, 'town', multi=True) or []
+ towns = []
+ for town_id in town_ids:
+ try:
+ town = models.Town.objects.get(pk=int(town_id))
+ towns.append((town.pk, unicode(town)))
+ except (ValueError, ObjectDoesNotExist):
+ pass
+ data['TOWNS'] = sorted(towns, key=lambda x:x[1])
+ data = data or None
+ form = super(OperationWizard, self).get_form(request, storage, step,
+ data, files)
+ return form
+
+ def get_formated_datas(self, forms):
+ """
+ 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
+ has_no_af = [form.prefix for form in forms
+ if form.prefix == 'townsgeneral-operation'] and True
+ if has_no_af:
+ datas = [[_(u"Warning: No Archaelogical File is provided. "
+ u"If you have forget it return to the first step."), []]]\
+ + datas
+ return datas
+
+class OperationSelect(forms.Form):
+ common_name = forms.CharField(label=_(u"Name"), max_length=30)
+ towns = get_town_field()
+ operation_type = forms.ChoiceField(label=_(u"Operation type"),
+ choices=[])
+ remains = forms.ChoiceField(label=_(u"Remains"),
+ choices=models.RemainType.get_types())
+ year = forms.IntegerField(label=_("Year"))
+ end_date = forms.NullBooleanField(label=_(u"Is open?"))
+
+ def __init__(self, *args, **kwargs):
+ super(OperationSelect, self).__init__(*args, **kwargs)
+ self.fields['operation_type'].choices = models.OperationType.get_types()
+ self.fields['operation_type'].help_text = models.OperationType.get_help()
+
+class OperationFormSelection(forms.Form):
+ form_label = _(u"Operation search")
+ associated_models = {'pk':models.Operation}
+ currents = {'pk':models.Operation}
+ pk = forms.IntegerField(label="", required=False,
+ widget=widgets.JQueryJqGrid(reverse_lazy('get-operation'),
+ OperationSelect(), models.Operation,
+ source_full=reverse_lazy('get-operation-full')),
+ validators=[models.valid_id(models.Operation)])
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if 'pk' not in cleaned_data or not cleaned_data['pk']:
+ raise forms.ValidationError(_(u"You should select an operation."))
+ return cleaned_data
+
+class OperationCodeInput(forms.TextInput):
+ """Manage auto complete whene changing year in form"""
+ def render(self, *args, **kwargs):
+ name, value = args
+ base_name = '-'.join(name.split('-')[:-1])
+ rendered = super(OperationCodeInput, self).render(*args, **kwargs)
+ js = u"""\n <script type="text/javascript"><!--//
+ function initialyse_operation_code () {
+ // if the form is in creation mode
+ if(!$("#id_%(base_name)s-pk").val()){
+ $("#id_%(base_name)s-year").change(function() {
+ var year = $("#id_%(base_name)s-year").val();
+ var url = "%(url)s" + year;
+ $.getJSON(url, function(data) {
+ $("#id_%(name)s").val(data.id);
+ });
+ });
+ }
+ }
+ $(document).ready(initialyse_operation_code());
+ //--></script>\n""" % {'base_name':base_name, 'name':name,
+ 'url':reverse_lazy('get_available_operation_code')}
+ return rendered + js
+
+class OperationFormGeneral(forms.Form):
+ form_label = _(u"General")
+ associated_models = {'in_charge':models.Person,
+ 'associated_file':models.File,
+ 'operation_type':models.OperationType}
+ currents = {'associated_file':models.File}
+ pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
+ in_charge = forms.IntegerField(label=_("Person in charge of the operation"),
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person',
+ args=["_".join(
+ [unicode(models.PersonType.objects.get(txt_idx='head_scientist').pk),
+ unicode(models.PersonType.objects.get(txt_idx='sra_agent').pk)])]),
+ associated_model=models.Person, new=True),
+ validators=[models.valid_id(models.Person)], required=False)
+ associated_file = forms.IntegerField(label=_(u"Archaelogical file"),
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'),
+ associated_model=models.File),
+ validators=[models.valid_id(models.File)], required=False)
+ operation_type = forms.ChoiceField(label=_(u"Operation type"),
+ choices=[])
+ start_date = forms.DateField(label=_(u"Start date"), required=False,
+ widget=widgets.JQueryDate)
+ excavation_end_date = forms.DateField(label=_(u"Excavation end date"),
+ required=False, widget=widgets.JQueryDate)
+ surface = forms.IntegerField(required=False, widget=widgets.AreaWidget,
+ label=_(u"Total surface (m²)"),
+ validators=[validators.MinValueValidator(0),
+ validators.MaxValueValidator(999999999)])
+ year = forms.IntegerField(label=_(u"Year"),
+ initial=lambda:datetime.datetime.now().year,
+ validators=[validators.MinValueValidator(1900),
+ validators.MaxValueValidator(2100)])
+ operation_code = forms.IntegerField(label=_(u"Operation code"),
+ initial=models.Operation.get_available_operation_code,
+ widget=OperationCodeInput)
+ common_name = forms.CharField(label=_(u"Generic name"), required=False,
+ max_length=120, widget=forms.Textarea)
+ operator_reference = forms.CharField(label=_(u"Operator reference"),
+ required=False, max_length=20)
+ if settings.COUNTRY == 'fr':
+ code_patriarche = forms.IntegerField(label=u"Code PATRIARCHE",
+ required=False)
+ code_dracar = forms.CharField(label=u"Code DRACAR", required=False,
+ validators=[validators.MaxLengthValidator(10)])
+ comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,
+ required=False)
+
+ def __init__(self, *args, **kwargs):
+ super(OperationFormGeneral, self).__init__(*args, **kwargs)
+ self.fields['operation_type'].choices = models.OperationType.get_types()
+ self.fields['operation_type'].help_text = models.OperationType.get_help()
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ # verify the logic between start date and excavation end date
+ if cleaned_data['excavation_end_date']:
+ if not self.cleaned_data['start_date']:
+ raise forms.ValidationError(_(u"If you want to set an "
+ u"excavation end date you have to provide a start date."))
+ if cleaned_data['excavation_end_date'] < cleaned_data['start_date']:
+ raise forms.ValidationError(_(u"The excavation end date "\
+ u"cannot be before the start date."))
+ year = self.cleaned_data.get("year")
+ operation_code = cleaned_data.get("operation_code")
+ ops = models.Operation.objects.filter(year=year,
+ operation_code=operation_code)
+ # manage unique operation ID
+ if 'pk' in cleaned_data and cleaned_data['pk']:
+ ops = ops.exclude(pk=cleaned_data['pk'])
+ if ops.count():
+ max_val = models.Operation.objects.filter(year=year).aggregate(
+ Max('operation_code'))["operation_code__max"]
+ raise forms.ValidationError(_(u"Operation code already exist for "
+ u"year: %(year)d - use a value bigger than %(last_val)d") % {
+ 'year':year, 'last_val':max_val})
+ return self.cleaned_data
+
+class OperationFormPreventive(forms.Form):
+ form_label = _(u"Preventive informations - excavation")
+ cost = forms.IntegerField(label=_(u"Cost (€)"), required=False)
+ scheduled_man_days = forms.IntegerField(label=_(u"Scheduled man-days"),
+ required=False)
+ optional_man_days = forms.IntegerField(label=_(u"Optional man-days"),
+ required=False)
+ effective_man_days = forms.IntegerField(label=_(u"Effective man-days"),
+ required=False)
+ if settings.COUNTRY == 'fr':
+ fnap_financing = forms.FloatField(required=False,
+ label=u"Pourcentage de financement FNAP",
+ validators=[validators.MinValueValidator(0),
+ validators.MaxValueValidator(100)])
+
+class OperationFormPreventiveDiag(forms.Form):
+ form_label = _("Preventive informations - diagnostic")
+ if settings.COUNTRY == 'fr':
+ zoning_prescription = forms.NullBooleanField(required=False,
+ label=_(u"Prescription on zoning"))
+ large_area_prescription = forms.NullBooleanField(required=False,
+ label=_(u"Prescription on large area"))
+ geoarchaeological_context_prescription = forms.NullBooleanField(
+ required=False, label=_(u"Prescription on geoarchaeological context"))
+
+class SelectedTownForm(forms.Form):
+ form_label = _("Towns")
+ associated_models = {'town':models.Town}
+ town = forms.ChoiceField(label=_("Town"), choices=(),
+ validators=[models.valid_id(models.Town)])
+ def __init__(self, *args, **kwargs):
+ towns = None
+ if 'data' in kwargs and 'TOWNS' in kwargs['data']:
+ towns = kwargs['data']['TOWNS']
+ # clean data if not "real" data
+ prefix_value = kwargs['prefix'] + '-town'
+ if not [k for k in kwargs['data'].keys()
+ if k.startswith(prefix_value) and kwargs['data'][k]]:
+ kwargs['data'] = None
+ if 'files' in kwargs:
+ kwargs.pop('files')
+ super(SelectedTownForm, self).__init__(*args, **kwargs)
+ if towns and towns != -1:
+ self.fields['town'].choices = [('', '--')] + towns
+
+SelectedTownFormset = formset_factory(SelectedTownForm, can_delete=True,
+ formset=TownFormSet)
+SelectedTownFormset.form_label = _(u"Towns")
+
+class SelectedParcelForm(forms.Form):
+ form_label = _("Parcels")
+ associated_models = {'parcel':models.Parcel}
+ parcel = forms.ChoiceField(label=_("Parcel"), choices=(),
+ validators=[models.valid_id(models.Parcel)])
+ def __init__(self, *args, **kwargs):
+ parcels = None
+ if 'data' in kwargs and 'PARCELS' in kwargs['data']:
+ parcels = kwargs['data']['PARCELS']
+ # clean data if not "real" data
+ prefix_value = kwargs['prefix'] + '-parcel'
+ if not [k for k in kwargs['data'].keys()
+ if k.startswith(prefix_value) and kwargs['data'][k]]:
+ kwargs['data'] = None
+ if 'files' in kwargs:
+ kwargs.pop('files')
+ super(SelectedParcelForm, self).__init__(*args, **kwargs)
+ if parcels:
+ self.fields['parcel'].choices = [('', '--')] + parcels
+
+SelectedParcelFormSet = formset_factory(SelectedParcelForm, can_delete=True,
+ formset=ParcelFormSet)
+SelectedParcelFormSet.form_label = _("Parcels")
+
+SelectedParcelGeneralFormSet = formset_factory(ParcelForm, can_delete=True,
+ formset=ParcelFormSet)
+SelectedParcelGeneralFormSet.form_label = _("Parcels")
+
+class RemainForm(forms.Form):
+ form_label = _("Remain types")
+ base_model = 'remain'
+ associated_models = {'remain':models.RemainType}
+ remain = forms.ChoiceField(label=_("Remain type"), required=False,
+ choices=models.RemainType.get_types())
+
+class RemainFormSet(FormSet):
+ def clean(self):
+ """Checks that no remain types are duplicated."""
+ return self.check_duplicate(['remain_type'],
+ _(u"There are identical remain types"))
+
+RemainFormset = formset_factory(RemainForm, can_delete=True,
+ formset=RemainFormSet)
+RemainFormset.form_label = _("Remain types")
+
+class PeriodForm(forms.Form):
+ form_label = _("Periods")
+ base_model = 'period'
+ associated_models = {'period':models.Period}
+ period = forms.ChoiceField(label=_("Period"), required=False,
+ choices=models.Period.get_types())
+
+class PeriodFormSet(FormSet):
+ def clean(self):
+ """Checks that no period are duplicated."""
+ return self.check_duplicate(['period'],
+ _(u"There are identical periods"))
+
+PeriodFormset = formset_factory(PeriodForm, can_delete=True,
+ formset=PeriodFormSet)
+PeriodFormset.form_label = _("Periods")
+
+operation_search_wizard = SearchWizard([
+ ('general-operation_search', OperationFormSelection)],
+ url_name='operation_search',)
+
+def has_associated_file(form_name, file_key='associated_file', negate=False):
+ def func(self, request, storage):
+ if storage.prefix not in request.session or \
+ 'step_data' not in request.session[storage.prefix] or \
+ form_name not in request.session[storage.prefix]['step_data'] or\
+ form_name + '-' + file_key not in \
+ request.session[storage.prefix]['step_data'][form_name]:
+ return negate
+ try:
+ file_id = int(request.session[storage.prefix]['step_data']\
+ [form_name][form_name+'-'+file_key])
+ return not negate
+ except ValueError:
+ return negate
+ return func
+
+operation_creation_wizard = OperationWizard([
+ ('general-operation_creation', OperationFormGeneral),
+ ('preventive-operation_creation', OperationFormPreventive),
+ ('preventivediag-operation_creation', OperationFormPreventiveDiag),
+ ('townsgeneral-operation_creation', TownFormset),
+ ('towns-operation_creation', SelectedTownFormset),
+ ('parcelsgeneral-operation_creation', SelectedParcelGeneralFormSet),
+ ('parcels-operation_creation', SelectedParcelFormSet),
+ ('remains-operation_creation', RemainFormset),
+ ('periods-operation_creation', PeriodFormset),
+ ('final-operation_creation', FinalForm)],
+ condition_list={
+'preventive-operation_creation':is_preventive('general-operation_creation',
+ models.OperationType, 'operation_type', 'prev_excavation'),
+'preventivediag-operation_creation':is_preventive('general-operation_creation',
+ models.OperationType, 'operation_type', 'arch_diagnostic'),
+'townsgeneral-operation_creation':has_associated_file(
+ 'general-operation_creation', negate=True),
+'towns-operation_creation':has_associated_file('general-operation_creation'),
+'parcelsgeneral-operation_creation':has_associated_file(
+ 'general-operation_creation', negate=True),
+'parcels-operation_creation':has_associated_file('general-operation_creation'),
+ },
+ url_name='operation_creation',)
+
+class OperationModificationWizard(OperationWizard):
+ modification = True
+
+operation_modification_wizard = OperationModificationWizard([
+ ('selec-operation_modification', OperationFormSelection),
+ ('general-operation_modification', OperationFormGeneral),
+ ('preventive-operation_modification', OperationFormPreventive),
+ ('preventivediag-operation_modification', OperationFormPreventiveDiag),
+ ('towns-operation_modification', SelectedTownFormset),
+ ('townsgeneral-operation_modification', TownFormset),
+ ('parcels-operation_modification', SelectedParcelFormSet),
+ ('parcelsgeneral-operation_modification', SelectedParcelGeneralFormSet),
+ ('remains-operation_modification', RemainFormset),
+ ('periods-operation_modification', PeriodFormset),
+ ('final-operation_modification', FinalForm)],
+ condition_list={
+'preventive-operation_modification':is_preventive(
+ 'general-operation_modification', models.OperationType,
+ 'operation_type', 'prev_excavation'),
+'preventivediag-operation_modification':is_preventive(
+ 'general-operation_modification', models.OperationType,
+ 'operation_type', 'arch_diagnostic'),
+'townsgeneral-operation_modification':has_associated_file(
+ 'general-operation_modification', negate=True),
+'towns-operation_modification':has_associated_file(
+ 'general-operation_modification'),
+'parcelsgeneral-operation_modification':has_associated_file(
+ 'general-operation_modification', negate=True),
+'parcels-operation_modification':has_associated_file(
+ 'general-operation_modification'),
+ },
+ url_name='operation_modification',)
+
+class OperationClosingWizard(ClosingWizard):
+ model = models.Operation
+ fields = ['year', 'operation_code', 'operation_type', 'associated_file',
+'in_charge', 'start_date', 'excavation_end_date', 'comment', 'towns', 'remains']
+
+class FinalOperationClosingForm(FinalForm):
+ confirm_msg = " "
+ confirm_end_msg = _(u"Would you like to close this operation?")
+
+operation_closing_wizard = OperationClosingWizard([
+ ('selec-operation_closing', OperationFormSelection),
+ ('date-operation_closing', ClosingDateFormSelection),
+ ('final-operation_closing', FinalOperationClosingForm)],
+ url_name='operation_closing',)
+
+class OperationDeletionWizard(DeletionWizard):
+ model = models.Operation
+ fields = OperationClosingWizard.fields
+
+class OperationDeletionForm(FinalForm):
+ confirm_msg = " "
+ confirm_end_msg = _(u"Would you like to delete this operation?")
+
+operation_deletion_wizard = OperationDeletionWizard([
+ ('selec-operation_deletion', OperationFormSelection),
+ ('final-operation_deletion', OperationDeletionForm)],
+ url_name='operation_deletion',)
+
+####################################
+# Source management for operations #
+####################################
+
+class OperationSourceWizard(SourceWizard):
+ model = models.OperationSource
+ def get_form_initial(self, request, storage, step):
+ initial = super(OperationSourceWizard, self).get_form_initial(request,
+ storage, step)
+ # put default index and operation_id field in the main source form
+ general_form_key = 'selec-' + self.url_name
+ if step.startswith('source-') \
+ and self.session_has_key(request, storage, general_form_key):
+ gen_storage = request.session[storage.prefix]['step_data']\
+ [general_form_key]
+ if general_form_key+"-operation" in gen_storage:
+ operation_id = int(gen_storage[general_form_key+"-operation"])
+ elif general_form_key+"-pk" in gen_storage:
+ pk = int(gen_storage[general_form_key+"-pk"])
+ try:
+ source = models.OperationSource.objects.get(pk=pk)
+ operation_id = source.operation.pk
+ except ObjectDoesNotExist:
+ pass
+ if operation_id:
+ initial['hidden_operation_id'] = operation_id
+ if 'index' not in initial:
+ max_val = models.OperationSource.objects.filter(
+ operation__pk=operation_id).aggregate(
+ Max('index'))["index__max"]
+ initial['index'] = max_val and (max_val + 1) or 1
+ return initial
+
+class OperationSourceForm(SourceForm):
+ pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
+ index = forms.IntegerField(label=_(u"Index"))
+ hidden_operation_id = forms.IntegerField(label="", widget=forms.HiddenInput)
+
+ def __init__(self, *args, **kwargs):
+ super(OperationSourceForm, self).__init__(*args, **kwargs)
+ keyOrder = self.fields.keyOrder
+ keyOrder.pop(keyOrder.index('index'))
+ keyOrder.insert(keyOrder.index('source_type') + 1, 'index')
+
+ def clean(self):
+ # manage unique operation ID
+ cleaned_data = self.cleaned_data
+ operation_id = cleaned_data.get("hidden_operation_id")
+ index = cleaned_data.get("index")
+ srcs = models.OperationSource.objects.filter(index=index,
+ operation__pk=operation_id)
+ if 'pk' in cleaned_data and cleaned_data['pk']:
+ srcs = srcs.exclude(pk=cleaned_data['pk'])
+ if srcs.count():
+ max_val = models.OperationSource.objects.filter(
+ operation__pk=operation_id
+ ).aggregate(Max('index'))["index__max"]
+ operation = models.Operation.objects.get(pk=operation_id)
+ raise forms.ValidationError(_(u"Index already exist for "
+"operation: %(operation)s - use a value bigger than %(last_val)d") % {
+ "operation":unicode(operation), 'last_val':max_val})
+ return cleaned_data
+
+SourceOperationFormSelection = get_form_selection(
+ 'SourceOperationFormSelection', _(u"Operation search"), 'operation',
+ models.Operation, OperationSelect, 'get-operation',
+ _(u"You should select an operation."))
+
+operation_source_creation_wizard = OperationSourceWizard([
+ ('selec-operation_source_creation', SourceOperationFormSelection),
+ ('source-operation_source_creation',OperationSourceForm),
+ ('authors-operation_source_creation', AuthorFormset),
+ ('final-operation_source_creation', FinalForm)],
+ url_name='operation_source_creation',)
+
+class OperationSourceSelect(SourceSelect):
+ operation__towns = get_town_field(label=_(u"Operation's town"))
+ operation__operation_type = forms.ChoiceField(label=_(u"Operation type"),
+ choices=[])
+ operation__year = forms.IntegerField(label=_(u"Operation's year"))
+
+ def __init__(self, *args, **kwargs):
+ super(OperationSourceSelect, self).__init__(*args, **kwargs)
+ self.fields['operation__operation_type'].choices = \
+ models.OperationType.get_types()
+ self.fields['operation__operation_type'].help_text = \
+ models.OperationType.get_help()
+
+
+OperationSourceFormSelection = get_form_selection(
+ 'OperationSourceFormSelection', _(u"Documentation search"), 'pk',
+ models.OperationSource, OperationSourceSelect, 'get-operationsource',
+ _(u"You should select a document."))
+
+operation_source_modification_wizard = OperationSourceWizard([
+ ('selec-operation_source_modification', OperationSourceFormSelection),
+ ('source-operation_source_modification', OperationSourceForm),
+ ('authors-operation_source_modification', AuthorFormset),
+ ('final-operation_source_modification', FinalForm)],
+ url_name='operation_source_modification',)
+
+class OperationSourceDeletionWizard(DeletionWizard):
+ model = models.OperationSource
+ fields = ['operation', 'title', 'source_type', 'authors',]
+
+operation_source_deletion_wizard = OperationSourceDeletionWizard([
+ ('selec-operation_source_deletion', OperationSourceFormSelection),
+ ('final-operation_source_deletion', SourceDeletionForm)],
+ url_name='operation_source_deletion',)
+
+################################################
+# Administrative act management for operations #
+################################################
+
+class OperationAdministrativeActWizard(OperationWizard):
+ edit = False
+
+ def get_extra_model(self, dct, request, storage, form_list):
+ dct['history_modifier'] = request.user
+ return dct
+
+ def get_associated_item(self, request, storage, dct):
+ return self.get_current_object(request, storage)
+
+ def save_model(self, dct, m2m, whole_associated_models, request, storage,
+ form_list, return_object):
+ associated_item = self.get_associated_item(request, storage, dct)
+ if not associated_item:
+ return self.render(request, storage, form_list[-1])
+ if isinstance(associated_item, models.File):
+ dct['associated_file'] = associated_item
+ elif isinstance(associated_item, models.Operation):
+ dct['operation'] = associated_item
+ dct['history_modifier'] = request.user
+ if 'pk' in dct:
+ dct.pop('pk')
+ if self.edit:
+ admact = self.get_current_object(request, storage)
+ for k in dct:
+ if hasattr(admact, k):
+ setattr(admact, k, dct[k])
+ else:
+ admact = models.AdministrativeAct(**dct)
+ admact.save()
+ res = render_to_response('wizard_done.html', {},
+ context_instance=RequestContext(request))
+ return res
+
+class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard):
+ model = models.AdministrativeAct
+ edit = True
+ def get_associated_item(self, request, storage, dct):
+ return self.get_current_object(request, storage).operation
+
+class AdministrativeActOpeSelect(forms.Form):
+ operation__towns = get_town_field()
+ act_type = forms.ChoiceField(label=_("Act type"), choices=[])
+
+ def __init__(self, *args, **kwargs):
+ super(AdministrativeActOpeSelect, self).__init__(*args, **kwargs)
+ self.fields['act_type'].choices = models.ActType.get_types(
+ dct={'intented_to':'O'})
+ self.fields['act_type'].help_text = models.ActType.get_help(
+ dct={'intented_to':'O'})
+
+class AdministrativeActOpeFormSelection(forms.Form):
+ form_label = _("Administrative act search")
+ associated_models = {'pk':models.AdministrativeAct}
+ currents = {'pk':models.AdministrativeAct}
+ pk = forms.IntegerField(label="", required=False,
+ widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactop'),
+ AdministrativeActOpeSelect(), models.AdministrativeAct,
+ table_cols='TABLE_COLS_OPE'),
+ validators=[models.valid_id(models.AdministrativeAct)])
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if 'pk' not in cleaned_data or not cleaned_data['pk']:
+ raise forms.ValidationError(_(u"You should select an administrative"
+ " act."))
+ return cleaned_data
+
+class AdministrativeActOpeForm(forms.Form):
+ form_label = _("General")
+ associated_models = {'act_type':models.ActType,
+ 'signatory':models.Person}
+ act_type = forms.ChoiceField(label=_("Act type"), choices=[])
+ signatory = forms.IntegerField(label=_("Signatory"),
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'),
+ associated_model=models.Person, new=True),
+ validators=[models.valid_id(models.Person)])
+ act_object = forms.CharField(label=_(u"Object"), max_length=200,
+ widget=forms.Textarea)
+ signature_date = forms.DateField(label=_(u"Signature date"),
+ widget=widgets.JQueryDate)
+ if settings.COUNTRY == 'fr':
+ ref_sra = forms.CharField(label=u"Référence SRA", max_length=15)
+
+ def __init__(self, *args, **kwargs):
+ super(AdministrativeActOpeForm, self).__init__(*args, **kwargs)
+ self.fields['act_type'].choices = models.ActType.get_types(
+ dct={'intented_to':'O'})
+ self.fields['act_type'].help_text = models.ActType.get_help(
+ dct={'intented_to':'O'})
+
+class AdministrativeActDeletionWizard(ClosingWizard):
+ model = models.AdministrativeAct
+ fields = ['act_type', 'in_charge', 'operator', 'scientific', 'signatory',
+ 'operation', 'associated_file', 'signature_date', 'act_object',]
+ if settings.COUNTRY == 'fr':
+ fields += ['ref_sra']
+
+ def done(self, request, storage, form_list, **kwargs):
+ obj = self.get_current_object(request, storage)
+ obj.delete()
+ return render_to_response('wizard_done.html', {},
+ context_instance=RequestContext(request))
+
+class FinalAdministrativeActDeleteForm(FinalForm):
+ confirm_msg = " "
+ confirm_end_msg = _(u"Would you like to delete this administrative act?")
+
+operation_administrativeactop_wizard = OperationAdministrativeActWizard([
+ ('selec-operation_administrativeactop', OperationFormSelection),
+ ('administrativeact-operation_administrativeactop', AdministrativeActOpeForm),
+ ('final-operation_administrativeactop', FinalForm)],
+ url_name='operation_administrativeactop',)
+
+operation_administrativeactop_modification_wizard = \
+ OperationEditAdministrativeActWizard([
+ ('selec-operation_administrativeactop_modification',
+ AdministrativeActOpeFormSelection),
+ ('administrativeact-operation_administrativeactop_modification',
+ AdministrativeActOpeForm),
+ ('final-operation_administrativeactop_modification', FinalForm)],
+ url_name='operation_administrativeactop_modification',)
+
+operation_administrativeactop_deletion_wizard = AdministrativeActDeletionWizard([
+ ('selec-operation_administrativeactop_deletion',
+ AdministrativeActOpeFormSelection),
+ ('final-operation_administrativeactop_deletion',
+ FinalAdministrativeActDeleteForm)],
+ url_name='operation_administrativeactop_deletion',)
diff --git a/archaeological_operations/ishtar_menu.py b/archaeological_operations/ishtar_menu.py
index dfd45a167..faf749480 100644
--- a/archaeological_operations/ishtar_menu.py
+++ b/archaeological_operations/ishtar_menu.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2010-2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2012 É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
@@ -20,53 +20,69 @@
from django.utils.translation import ugettext_lazy as _
from ishtar_common.menu_base import SectionItem, MenuItem
-from ishtar_common.models import AdministrativeAct
import models
-ORDER = 30
-
MENU_SECTIONS = [
- SectionItem('operation_management', _(u"Operation"),
+ (30, SectionItem('operation_management', _(u"Operation"),
+ childs=[
+ MenuItem('operation_search', _(u"Search"),
+ model=models.Operation,
+ access_controls=['view_operation',
+ 'view_own_operation']),
+ MenuItem('operation_creation', _(u"Creation"),
+ model=models.Operation,
+ access_controls=['add_operation',
+ 'add_own_operation']),
+ MenuItem('operation_modification', _(u"Modification"),
+ model=models.Operation,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_closing', _(u"Closing"),
+ model=models.Operation,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_deletion', _(u"Deletion"),
+ model=models.Operation,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ SectionItem('admin_act_operations',
+ _(u"Administrative act"),
childs=[
- MenuItem('operation_search', _(u"Search"),
- model=models.Operation,
- access_controls=['view_operation',
- 'view_own_operation']),
- MenuItem('operation_creation', _(u"Creation"),
- model=models.Operation,
- access_controls=['add_operation',
- 'add_own_operation']),
- MenuItem('operation_modification', _(u"Modification"),
- model=models.Operation,
- access_controls=['change_operation',
- 'change_own_operation']),
- MenuItem('operation_closing', _(u"Closing"),
- model=models.Operation,
- access_controls=['change_operation',
- 'change_own_operation']),
- MenuItem('operation_deletion', _(u"Deletion"),
- model=models.Operation,
- access_controls=['change_operation',
- 'change_own_operation']),
- SectionItem('admin_act_operations',
- _(u"Administrative act"),
+ MenuItem('operation_administrativeactop',
+ _(u"Add"),
+ model=models.Operation,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_administrativeactop_modification',
+ _(u"Modification"),
+ model=models.AdministrativeAct,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_administrativeactop_deletion',
+ _(u"Deletion"),
+ model=models.AdministrativeAct,
+ access_controls=['operation_deletion',
+ 'delete_own_operation']),
+ ],),
+ SectionItem('operation_source', _(u"Documentation"),
childs=[
- MenuItem('operation_administrativeactop',
+ MenuItem('operation_source_creation',
_(u"Add"),
- model=models.Operation,
- access_controls=['change_operation',
- 'change_own_operation']),
- MenuItem('operation_administrativeactop_modification',
+ model=models.OperationSource,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_source_modification',
_(u"Modification"),
- model=AdministrativeAct,
- access_controls=['change_operation',
- 'change_own_operation']),
- MenuItem('operation_administrativeactop_deletion',
+ model=models.OperationSource,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ MenuItem('operation_source_deletion',
_(u"Deletion"),
- model=AdministrativeAct,
- access_controls=['operation_deletion',
- 'delete_own_operation']),
- ],),
- ]),
+ model=models.OperationSource,
+ access_controls=['change_operation',
+ 'change_own_operation']),
+ ])
+ ]),
+ )
]
diff --git a/archaeological_operations/migrations/0001_initial.py b/archaeological_operations/migrations/0001_initial.py
index e472e5e4d..2039268aa 100644
--- a/archaeological_operations/migrations/0001_initial.py
+++ b/archaeological_operations/migrations/0001_initial.py
@@ -200,6 +200,32 @@ class Migration(SchemaMigration):
))
db.send_create_signal('archaeological_operations', ['AdministrativeAct'])
+ # Adding model 'Parcel'
+ db.create_table('archaeological_operations_parcel', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('history_modifier', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', to=orm['auth.User'])),
+ ('history_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('associated_file', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='parcels', null=True, to=orm['archaeological_files.File'])),
+ ('operation', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='parcels', null=True, to=orm['archaeological_operations.Operation'])),
+ ('year', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('town', self.gf('django.db.models.fields.related.ForeignKey')(related_name='parcels', to=orm['ishtar_common.Town'])),
+ ('section', self.gf('django.db.models.fields.CharField')(max_length=4)),
+ ('parcel_number', self.gf('django.db.models.fields.CharField')(max_length=6)),
+ ))
+ db.send_create_signal('archaeological_operations', ['Parcel'])
+
+ # Adding model 'ParcelOwner'
+ db.create_table('archaeological_operations_parcelowner', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('history_modifier', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', to=orm['auth.User'])),
+ ('history_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('owner', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ishtar_common.Person'])),
+ ('parcel', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['archaeological_operations.Parcel'])),
+ ('start_date', self.gf('django.db.models.fields.DateField')()),
+ ('end_date', self.gf('django.db.models.fields.DateField')()),
+ ))
+ db.send_create_signal('archaeological_operations', ['ParcelOwner'])
+
def backwards(self, orm):
# Deleting model 'OperationType'
@@ -241,6 +267,12 @@ class Migration(SchemaMigration):
# Deleting model 'AdministrativeAct'
db.delete_table('archaeological_operations_administrativeact')
+ # Deleting model 'Parcel'
+ db.delete_table('archaeological_operations_parcel')
+
+ # Deleting model 'ParcelOwner'
+ db.delete_table('archaeological_operations_parcelowner')
+
models = {
'archaeological_files.file': {
@@ -427,6 +459,28 @@ class Migration(SchemaMigration):
'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
+ 'archaeological_operations.parcel': {
+ 'Meta': {'object_name': 'Parcel'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parcels'", 'null': 'True', 'to': "orm['archaeological_files.File']"}),
+ 'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'operation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parcels'", 'null': 'True', 'to': "orm['archaeological_operations.Operation']"}),
+ 'parcel_number': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'section': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'town': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'parcels'", 'to': "orm['ishtar_common.Town']"}),
+ 'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.parcelowner': {
+ 'Meta': {'object_name': 'ParcelOwner'},
+ 'end_date': ('django.db.models.fields.DateField', [], {}),
+ 'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Person']"}),
+ 'parcel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Parcel']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {})
+ },
'archaeological_operations.period': {
'Meta': {'object_name': 'Period'},
'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 48baa57ba..9b3631114 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -23,7 +23,8 @@ from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _, ugettext
from ishtar_common.models import GeneralType, BaseHistorizedItem, \
- HistoricalRecords, OwnPerms, Department, Source, Person, Organization, Town
+ HistoricalRecords, LightHistorizedItem, OwnPerms, Department, Source,\
+ Person, Organization, Town, Dashboard
FILES_AVAILABLE = 'archaeological_files' in settings.INSTALLED_APPS
if FILES_AVAILABLE:
from archaeological_files.models import File
@@ -288,13 +289,502 @@ related_name='+', verbose_name=_(u"Person in charge of the scientific part"))
verbose_name = _(u"Administrative act")
verbose_name_plural = _(u"Administrative acts")
permissions = (
-("view_own_administrativeact", ugettext(u"Can view own Administrative act")),
-("add_own_administrativeact", ugettext(u"Can add own Administrative act")),
-("change_own_administrativeact", ugettext(u"Can change own Administrative act")),
-("delete_own_administrativeact", ugettext(u"Can delete own Administrative act")),
+ ("view_own_administrativeact",
+ ugettext(u"Can view own Administrative act")),
+ ("add_own_administrativeact",
+ ugettext(u"Can add own Administrative act")),
+ ("change_own_administrativeact",
+ ugettext(u"Can change own Administrative act")),
+ ("delete_own_administrativeact",
+ ugettext(u"Can delete own Administrative act")),
)
def __unicode__(self):
return JOINT.join([unicode(item)
for item in [self.operation, self.associated_file, self.act_object]
if item])
+
+class Parcel(LightHistorizedItem):
+ if FILES_AVAILABLE:
+ associated_file = models.ForeignKey(File, related_name='parcels',
+ blank=True, null=True, verbose_name=_(u"File"))
+ operation = models.ForeignKey(Operation, related_name='parcels', blank=True,
+ null=True, verbose_name=_(u"Operation"))
+ year = models.IntegerField(_(u"Year"), blank=True, null=True)
+ town = models.ForeignKey(Town, related_name='parcels',
+ verbose_name=_(u"Town"))
+ section = models.CharField(_(u"Section"), max_length=4)
+ parcel_number = models.CharField(_(u"Parcel number"), max_length=6)
+
+ class Meta:
+ verbose_name = _(u"Parcel")
+ verbose_name_plural = _(u"Parcels")
+
+ def short_label(self):
+ return JOINT.join([unicode(item) for item in [self.section,
+ self.parcel_number] if item])
+
+ def __unicode__(self):
+ return self.short_label()
+
+ def long_label(self):
+ items = [unicode(self.operation or self.associated_file)]
+ items += [unicode(item) for item in [self.section, self.parcel_number]
+ if item]
+ return JOINT.join(items)
+
+class ParcelOwner(LightHistorizedItem):
+ owner = models.ForeignKey(Person, verbose_name=_(u"Owner"))
+ parcel = models.ForeignKey(Parcel, verbose_name=_(u"Parcel"))
+ start_date = models.DateField(_(u"Start date"))
+ end_date = models.DateField(_(u"End date"))
+
+ class Meta:
+ verbose_name = _(u"Parcel owner")
+ verbose_name_plural = _(u"Parcel owners")
+
+ def __unicode__(self):
+ return self.owner + JOINT + self.parcel
+
+class OperationDashboard:
+ def __init__(self):
+ main_dashboard = Dashboard(Operation)
+
+ self.total_number = main_dashboard.total_number
+
+ self.filters_keys = ['recorded', 'effective', 'active', 'field',
+ 'documented', 'closed', 'documented_closed']
+ filters = {
+ 'recorded':{},
+ 'effective':{'in_charge__isnull':False},
+ 'active':{'in_charge__isnull':False, 'end_date__isnull':True},
+ 'field':{'excavation_end_date__isnull':True},
+ 'documented':{'source__isnull':False},
+ 'documented_closed':{'source__isnull':False,
+ 'end_date__isnull':False},
+ 'closed':{'end_date__isnull':False}
+ }
+ filters_label = {
+ 'recorded':_(u"Recorded"),
+ 'effective':_(u"Effective"),
+ 'active':_(u"Active"),
+ 'field':_(u"Field completed"),
+ 'documented':_(u"Associated report"),
+ 'closed':_(u"Closed"),
+ 'documented_closed':_(u"Documented and closed"),
+ }
+ self.filters_label = [filters_label[k] for k in self.filters_keys]
+ self.total = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ nb = Operation.objects.filter(**fltr).count()
+ self.total.append((lbl, nb))
+
+ self.surface_by_type = Operation.objects\
+ .values('operation_type__label')\
+ .annotate(number=Sum('surface'))\
+ .order_by('-number','operation_type__label')
+
+ self.by_type = []
+ self.types = OperationType.objects.filter(available=True).all()
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ type_res = Operation.objects.filter(**fltr).\
+ values('operation_type', 'operation_type__label').\
+ annotate(number=Count('pk')).\
+ order_by('operation_type')
+ types_dct = {}
+ for typ in type_res.all():
+ types_dct[typ['operation_type']] = typ["number"]
+ types = []
+ for typ in self.types:
+ if typ.pk in types_dct:
+ types.append(types_dct[typ.pk])
+ else:
+ types.append(0)
+ self.by_type.append((lbl, types))
+
+ self.by_year = []
+ self.years = [res['year'] for res in Operation.objects.values('year')\
+ .order_by('-year').distinct()]
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ year_res = Operation.objects.filter(**fltr).\
+ values('year').\
+ annotate(number=Count('pk')).\
+ order_by('year')
+ years_dct = {}
+ for yr in year_res.all():
+ years_dct[yr['year']] = yr["number"]
+ years = []
+ for yr in self.years:
+ if yr in years_dct:
+ years.append(years_dct[yr])
+ else:
+ years.append(0)
+ self.by_year.append((lbl, years))
+
+ self.by_realisation_year = []
+ self.realisation_years = [res['date'] for res in \
+ Operation.objects.extra(
+ {'date':"date_trunc('year', start_date)"}).values('date')\
+ .filter(start_date__isnull=False).order_by('-date').distinct()]
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ year_res = Operation.objects.filter(**fltr).extra(
+ {'date':"date_trunc('year', start_date)"}).values('date').\
+ values('date').filter(start_date__isnull=False).\
+ annotate(number=Count('pk')).\
+ order_by('-date')
+ years_dct = {}
+ for yr in year_res.all():
+ years_dct[yr['date']] = yr["number"]
+ years = []
+ for yr in self.realisation_years:
+ if yr in years_dct:
+ years.append(years_dct[yr])
+ else:
+ years.append(0)
+ self.by_realisation_year.append((lbl, years))
+
+ self.effective = []
+ for typ in self.types:
+ year_res = Operation.objects.filter(**{'in_charge__isnull':False,
+ 'operation_type':typ}).\
+ values('year').\
+ annotate(number=Count('pk')).\
+ order_by('-year').distinct()
+ years_dct = {}
+ for yr in year_res.all():
+ years_dct[yr['year']] = yr["number"]
+ years = []
+ for yr in self.years:
+ if yr in years_dct:
+ years.append(years_dct[yr])
+ else:
+ years.append(0)
+ self.effective.append((typ, years))
+
+ # TODO: by date
+ now = datetime.date.today()
+ limit = datetime.date(now.year, now.month, 1) - datetime.timedelta(365)
+ by_realisation_month = Operation.objects.filter(start_date__gt=limit,
+ start_date__isnull=False).extra(
+ {'date':"date_trunc('month', start_date)"})
+ self.last_months = []
+ date = datetime.datetime(now.year, now.month, 1)
+ for mt_idx in xrange(12):
+ self.last_months.append(date)
+ if date.month > 1:
+ date = datetime.datetime(date.year, date.month - 1, 1)
+ else:
+ date = datetime.datetime(date.year - 1, 12, 1)
+ self.by_realisation_month = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ month_res = by_realisation_month.filter(**fltr).\
+ annotate(number=Count('pk')).\
+ order_by('-date')
+ month_dct = {}
+ for mt in month_res.all():
+ month_dct[mt.date] = mt.number
+ date = datetime.date(now.year, now.month, 1)
+ months = []
+ for date in self.last_months:
+ if date in month_dct:
+ months.append(month_dct[date])
+ else:
+ months.append(0)
+ self.by_realisation_month.append((lbl, months))
+
+ # survey and excavations
+ self.survey, self.excavation = {}, {}
+ for dct_res, ope_types in ((self.survey, ('arch_diagnostic',)),
+ (self.excavation, ('prev_excavation',
+ 'prog_excavation'))):
+ dct_res['total'] = []
+ operation_type = {'operation_type__txt_idx__in':ope_types}
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ fltr.update(operation_type)
+ nb = Operation.objects.filter(**fltr).count()
+ dct_res['total'].append((lbl, nb))
+
+ dct_res['by_year'] = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ fltr.update(operation_type)
+ year_res = Operation.objects.filter(**fltr).\
+ values('year').\
+ annotate(number=Count('pk')).\
+ order_by('year')
+ years_dct = {}
+ for yr in year_res.all():
+ years_dct[yr['year']] = yr["number"]
+ years = []
+ for yr in self.years:
+ if yr in years_dct:
+ years.append(years_dct[yr])
+ else:
+ years.append(0)
+ dct_res['by_year'].append((lbl, years))
+
+ dct_res['by_realisation_year'] = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ fltr.update(operation_type)
+ year_res = Operation.objects.filter(**fltr).extra(
+ {'date':"date_trunc('year', start_date)"}).values('date').\
+ filter(start_date__isnull=False).\
+ annotate(number=Count('pk')).\
+ order_by('-date')
+ years_dct = {}
+ for yr in year_res.all():
+ years_dct[yr['date']] = yr["number"]
+ years = []
+ for yr in self.realisation_years:
+ if yr in years_dct:
+ years.append(years_dct[yr])
+ else:
+ years.append(0)
+ dct_res['by_realisation_year'].append((lbl, years))
+
+ current_year_ope = Operation.objects.filter(**operation_type)\
+ .filter(year=datetime.date.today().year)
+ current_realisation_year_ope = Operation.objects\
+ .filter(**operation_type)\
+ .filter(start_date__year=datetime.date.today().year)
+ res_keys = [('area_realised', current_realisation_year_ope)]
+ if dct_res == self.survey:
+ res_keys.append(('area',
+ current_year_ope))
+ for res_key, base_ope in res_keys:
+ dct_res[res_key] = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ area_res = base_ope.filter(**fltr)\
+ .annotate(number=Sum('surface')).all()
+ val = 0
+ if area_res:
+ val = area_res[0].number
+ dct_res[res_key].append(val)
+ # TODO...
+ res_keys = [('manday_realised', current_realisation_year_ope)]
+ if dct_res == self.survey:
+ res_keys.append(('manday',
+ current_year_ope))
+ for res_key, base_ope in res_keys:
+ dct_res[res_key] = []
+ for fltr_key in self.filters_keys:
+ dct_res[res_key].append('-')
+ # TODO...
+ res_keys = [('mandayhect_realised', current_realisation_year_ope)]
+ if dct_res == self.survey:
+ res_keys.append(('mandayhect',
+ current_year_ope))
+ for res_key, base_ope in res_keys:
+ dct_res[res_key] = []
+ for fltr_key in self.filters_keys:
+ dct_res[res_key].append('-')
+ # TODO...
+ dct_res['mandayhect_real_effective'] = '-'
+ if dct_res == self.survey:
+ dct_res['mandayhect_effective'] = '-'
+
+
+ res_keys = [('org_realised', current_realisation_year_ope)]
+ if dct_res == self.survey:
+ res_keys.append(('org', current_year_ope))
+ for res_key, base_ope in res_keys:
+ org_res = base_ope.filter(in_charge__attached_to__isnull=False)\
+ .values('in_charge__attached_to',
+ 'in_charge__attached_to__name')\
+ .annotate(area=Sum('surface'))\
+ .order_by('in_charge__attached_to__name').all()
+ # TODO: man-days, man-days/hectare
+ dct_res[res_key] = org_res
+
+
+ year_ope = Operation.objects.filter(**operation_type)
+ res_keys = ['org_by_year']
+ if dct_res == self.survey:
+ res_keys.append('org_by_year_realised')
+ q = year_ope.values('in_charge__attached_to',
+ 'in_charge__attached_to__name').\
+ filter(in_charge__attached_to__isnull=False).\
+ order_by('in_charge__attached_to__name').distinct()
+ org_list = [(org['in_charge__attached_to'],
+ org['in_charge__attached_to__name']) for org in q]
+ org_list_dct = dict(org_list)
+ for res_key in res_keys:
+ dct_res[res_key] = []
+ years = self.years
+ if res_key == 'org_by_year_realised':
+ years = self.realisation_years
+ for org_id, org_label in org_list:
+ org_res = year_ope.filter(in_charge__attached_to__pk=org_id)
+ key_date = ''
+ if res_key == 'org_by_year':
+ org_res = org_res.values('year')
+ key_date = 'year'
+ else:
+ org_res = org_res.extra(
+ {'date':"date_trunc('year', start_date)"}).values('date').\
+ filter(start_date__isnull=False)
+ key_date = 'date'
+ org_res = org_res.annotate(area=Sum('surface'),
+ cost=Sum('cost'))
+ years_dct = {}
+ for yr in org_res.all():
+ area = yr['area'] if yr['area'] else 0
+ cost = yr['cost'] if yr['cost'] else 0
+ years_dct[yr[key_date]] = (area, cost)
+ r_years = []
+ for yr in years:
+ if yr in years_dct:
+ r_years.append(years_dct[yr])
+ else:
+ r_years.append((0, 0))
+ dct_res[res_key].append((org_label, r_years))
+ area_means, area_sums = [], []
+ cost_means, cost_sums = [], []
+ for idx, year in enumerate(years):
+ vals = [r_years[idx] for lbl, r_years in dct_res[res_key]]
+ sum_area = sum([a for a, c in vals])
+ sum_cost = sum([c for a, c in vals])
+ area_means.append(sum_area/len(vals))
+ area_sums.append(sum_area)
+ cost_means.append(sum_cost/len(vals))
+ cost_sums.append(sum_cost)
+ dct_res[res_key+'_area_mean'] = area_means
+ dct_res[res_key+'_area_sum'] = area_sums
+ dct_res[res_key+'_cost_mean'] = cost_means
+ dct_res[res_key+'_cost_mean'] = cost_sums
+
+ if dct_res == self.survey:
+ self.survey['effective'] = []
+ for yr in self.years:
+ year_res = Operation.objects.filter(in_charge__isnull=False,
+ year=yr).\
+ annotate(number=Sum('surface'),
+ mean=Avg('surface'))
+ nb = year_res[0].number if year_res.count() else 0
+ nb = nb if nb else 0
+ mean = year_res[0].mean if year_res.count() else 0
+ mean = mean if mean else 0
+ self.survey['effective'].append((nb, mean))
+
+ # TODO:Man-Days/hectare by Year
+
+ # CHECK: month of realisation or month?
+ dct_res['by_month'] = []
+ for fltr_key in self.filters_keys:
+ fltr, lbl = filters[fltr_key], filters_label[fltr_key]
+ fltr.update(operation_type)
+ month_res = by_realisation_month.filter(**fltr).\
+ annotate(number=Count('pk')).\
+ order_by('-date')
+ month_dct = {}
+ for mt in month_res.all():
+ month_dct[mt.date] = mt.number
+ date = datetime.date(now.year, now.month, 1)
+ months = []
+ for date in self.last_months:
+ if date in month_dct:
+ months.append(month_dct[date])
+ else:
+ months.append(0)
+ dct_res['by_month'].append((lbl, months))
+
+ operation_type = {'operation_type__txt_idx__in':ope_types}
+ self.departments = [(fd['department__pk'], fd['department__label'])
+ for fd in OperationByDepartment.objects\
+ .filter(department__isnull=False)\
+ .values('department__label', 'department__pk')\
+ .order_by('department__label').distinct()]
+ dct_res['by_dpt'] = []
+ for dpt_id, dpt_label in self.departments:
+ vals = OperationByDepartment.objects\
+ .filter(department__pk=dpt_id,
+ operation__operation_type__txt_idx__in=ope_types)\
+ .values('department__pk', 'operation__year')\
+ .annotate(number=Count('operation'))\
+ .order_by('operation__year')
+ dct_years = {}
+ for v in vals:
+ dct_years[v['operation__year']] = v['number']
+ years = []
+ for y in self.years:
+ if y in dct_years:
+ years.append(dct_years[y])
+ else:
+ years.append(0)
+ years.append(sum(years))
+ dct_res['by_dpt'].append((dpt_label, years))
+ dct_res['effective_by_dpt'] = []
+ for dpt_id, dpt_label in self.departments:
+ vals = OperationByDepartment.objects\
+ .filter(department__pk=dpt_id,
+ operation__in_charge__isnull=False,
+ operation__operation_type__txt_idx__in=ope_types)\
+ .values('department__pk', 'operation__year')\
+ .annotate(number=Count('operation'),
+ area=Sum('operation__surface'),
+ fnap=Sum('operation__fnap_cost'),
+ cost=Sum('operation__cost'))\
+ .order_by('operation__year')
+ dct_years = {}
+ for v in vals:
+ values = []
+ for value in (v['number'], v['area'], v['cost'], v['fnap']):
+ values.append(value if value else 0)
+ dct_years[v['operation__year']] = values
+ years = []
+ for y in self.years:
+ if y in dct_years:
+ years.append(dct_years[y])
+ else:
+ years.append((0, 0, 0, 0))
+ nbs, areas, costs, fnaps = zip(*years)
+ years.append((sum(nbs), sum(areas), sum(costs), sum(fnaps)))
+ dct_res['effective_by_dpt'].append((dpt_label, years))
+
+ OperationTown = Operation.towns.through
+ query = OperationTown.objects\
+ .filter(operation__in_charge__isnull=False,
+ operation__operation_type__txt_idx__in=ope_types)\
+ .values('town__name', 'town__departement__number')\
+ .annotate(nb=Count('operation'))\
+ .order_by('-nb', 'town__name')[:10]
+ dct_res['towns'] = []
+ for r in query:
+ dct_res['towns'].append((u"%s (%s)" % (r['town__name'],
+ r['town__departement__number']),
+ r['nb']))
+
+ if dct_res == self.survey:
+ query = OperationTown.objects\
+ .filter(operation__in_charge__isnull=False,
+ operation__operation_type__txt_idx__in=ope_types,
+ operation__surface__isnull=False)\
+ .values('town__name', 'town__departement__number')\
+ .annotate(nb=Sum('operation__surface'))\
+ .order_by('-nb', 'town__name')[:10]
+ dct_res['towns_surface'] = []
+ for r in query:
+ dct_res['towns_surface'].append((u"%s (%s)" % (
+ r['town__name'], r['town__departement__number']),
+ r['nb']))
+ else:
+ query = OperationTown.objects\
+ .filter(operation__in_charge__isnull=False,
+ operation__operation_type__txt_idx__in=ope_types,
+ operation__cost__isnull=False)\
+ .values('town__name', 'town__departement__number')\
+ .annotate(nb=Sum('operation__cost'))\
+ .order_by('-nb', 'town__name')[:10]
+ dct_res['towns_cost'] = []
+ for r in query:
+ dct_res['towns_cost'].append((u"%s (%s)" % (r['town__name'],
+ r['town__departement__number']),
+ r['nb']))
diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py
new file mode 100644
index 000000000..a761b4ccc
--- /dev/null
+++ b/archaeological_operations/urls.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2010-2012 É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.conf.urls.defaults import *
+
+"""
+import forms
+
+# forms
+urlpatterns = patterns('',
+ url(r'operation_search/(?P<step>.+)$',
+ forms.operation_search_wizard, name='operation_search'),
+ url(r'operation_creation/(?P<step>.+)$',
+ forms.operation_creation_wizard, name='operation_creation'),
+ url(r'operation_modification/(?P<step>.+)$',
+ forms.operation_modification_wizard,
+ name='operation_modification'),
+ url(r'operation_closing/(?P<step>.+)$',
+ forms.operation_closing_wizard, name='operation_closing'),
+ url(r'operation_deletion/(?P<step>.+)$',
+ forms.operation_deletion_wizard, name='operation_deletion'),
+ url(r'operation_administrativeactop/(?P<step>.+)$',
+ forms.operation_administrativeactop_wizard,
+ name='operation_administrativeactop'),
+ url(r'operation_administrativeactop_modification/(?P<step>.+)$',
+ forms.operation_administrativeactop_modification_wizard,
+ name='operation_administrativeactop_modification'),
+ url(r'operation_administrativeactop_deletion/(?P<step>.+)$',
+ forms.operation_administrativeactop_deletion_wizard,
+ name='operation_administrativeactop_deletion'),
+ url(r'operation_source_creation/(?P<step>.+)$',
+ forms.operation_source_creation_wizard,
+ name='operation_source_creation'),
+ url(r'operation_source_modification/(?P<step>.+)$',
+ forms.operation_source_modification_wizard,
+ name='operation_source_modification'),
+ url(r'operation_source_deletion/(?P<step>.+)$',
+ forms.operation_source_deletion_wizard,
+ name='operation_source_deletion'),
+)
+
+urlpatterns += patterns('archaeological_operations.views',
+ url(r'autocomplete-operation/$', 'autocomplete_operation',
+ name='autocomplete-operation'),
+ url(r'get-operation/(?P<type>.+)?$', 'get_operation',
+ name='get-operation'),
+ url(r'get-operation-full/(?P<type>.+)?$', 'get_operation',
+ name='get-operation-full', kwargs={'full':True}),
+ url(r'get-available-operation-code/(?P<year>.+)?$',
+ 'get_available_operation_code', name='get_available_operation_code'),
+ url(r'revert-operation/(?P<pk>.+)/(?P<date>.+)$',
+ 'revert_operation', name='revert-operation'),
+ url(r'show-operation/(?P<pk>.+)?/(?P<type>.+)?$',
+ 'show_operation', name='show-operation'),
+ url(r'get-administrativeactop/(?P<type>.+)?$',
+ 'get_administrativeactop', name='get-administrativeactop'),
+ url(r'get-operationsource/(?P<type>.+)?$',
+ 'get_operationsource', name='get-operationsource'),
+)"""
diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py
new file mode 100644
index 000000000..27ebd60e9
--- /dev/null
+++ b/archaeological_operations/views.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2010-2012 É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.
+
+import json
+
+from django.db.models import Q
+from django.http import HttpResponse
+from django.shortcuts import render_to_response
+
+from ishtar_common.views import get_item, show_item, revert_item
+import models
+
+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', 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(' '):
+ extra = Q(towns__name__icontains=q)
+ try:
+ value = int(q)
+ extra = extra | Q(year=q) | Q(operation_code=q)
+ except ValueError:
+ pass
+ query = query & extra
+ if non_closed:
+ query = query & Q(end_date__isnull=True)
+ limit = 15
+ operations = models.Operation.objects.filter(query)[:limit]
+ data = json.dumps([{'id':operation.pk, 'value':unicode(operation)}
+ for operation in operations])
+ return HttpResponse(data, mimetype='text/plain')
+
+def get_available_operation_code(request, year=None):
+ 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):
+ return HttpResponse(mimetype='text/plain')
+ data = json.dumps({'id':models.Operation.get_available_operation_code(year)})
+ return HttpResponse(data, mimetype='text/plain')
+
+get_operation = get_item(models.Operation, 'get_operation', 'operation',
+ bool_fields = ['end_date__isnull'],
+ extra_request_keys={'common_name':'common_name__icontains',
+ 'end_date':'end_date__isnull',
+ 'year_index':('year', 'operation_code')})
+show_operation = show_item(models.Operation, 'operation')
+revert_operation = revert_item(models.Operation)
+
+get_operationsource = get_item(models.OperationSource,
+ 'get_operationsource', 'operationsource',
+ extra_request_keys={'operation__towns':'operation__towns__pk',
+ 'operation__operation_type':'operation__operation_type__pk',
+ 'operation__year':'operation__year'})
+
+get_administrativeactfile = get_item(models.AdministrativeAct,
+ 'get_administrativeactfile', 'administrativeactfile',
+ extra_request_keys={'associated_file__towns':'associated_file__towns__pk',
+ 'operation__towns':'operation__towns__pk',
+ 'act_type__intented_to':'act_type__intented_to'})
+get_administrativeactop = get_item(models.AdministrativeAct,
+ 'get_administrativeactop', 'administrativeactop',
+ extra_request_keys={'associated_file__towns':'associated_file__towns__pk',
+ 'operation__towns':'operation__towns__pk',
+ 'act_type__intented_to':'act_type__intented_to'})
+
+
+def dashboard_operation(request, dct, obj_id=None, *args, **kwargs):
+ """
+ Operation dashboard
+ """
+ dct = {'dashboard': models.OperationDashboard()}
+ return render_to_response('dashboard_operation.html', dct,
+ context_instance=RequestContext(request))