summaryrefslogtreecommitdiff
path: root/archaeological_files
diff options
context:
space:
mode:
Diffstat (limited to 'archaeological_files')
-rw-r--r--archaeological_files/admin.py42
-rw-r--r--archaeological_files/forms.py389
-rw-r--r--archaeological_files/ishtar_menu.py8
-rw-r--r--archaeological_files/models.py124
-rw-r--r--archaeological_files/urls.py64
-rw-r--r--archaeological_files/views.py66
6 files changed, 688 insertions, 5 deletions
diff --git a/archaeological_files/admin.py b/archaeological_files/admin.py
new file mode 100644
index 000000000..339b19661
--- /dev/null
+++ b/archaeological_files/admin.py
@@ -0,0 +1,42 @@
+#!/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 FileAdmin(HistorizedObjectAdmin):
+ list_display = ['year', 'numeric_reference', 'internal_reference',
+ 'end_date', 'file_type', 'general_contractor',]
+ if settings.COUNTRY == 'fr':
+ list_display += ['saisine_type', 'reference_number']
+ list_filter = ("file_type", "year",)
+ search_fields = ('towns__name',)
+ model = models.File
+
+admin.site.register(models.File, FileAdmin)
+
+basic_models = [models.FileType, models.PermitType]
+if settings.COUNTRY == 'fr':
+ basic_models.append(models.SaisineType)
+for model in basic_models:
+ admin.site.register(model)
diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py
new file mode 100644
index 000000000..368c57843
--- /dev/null
+++ b/archaeological_files/forms.py
@@ -0,0 +1,389 @@
+#!/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.
+
+"""
+Files forms definitions
+"""
+import datetime
+
+from django import forms
+from django.conf import settings
+from django.core import validators
+from django.core.exceptions import ObjectDoesNotExist
+from django.db.models import Max
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.utils.translation import ugettext_lazy as _
+
+from ishtar_common.models import Town
+import models
+from ishtar_common.views import Wizard
+from ishtar_common.forms import FinalForm, FormSet, ClosingWizard, \
+ ClosingDateFormSelection, SearchWizard, formset_factory, get_now, \
+ reverse_lazy
+from ishtar_common.forms_common import TownFormset, ParcelFormSet, \
+ get_town_field, get_person_field
+from archaeological_operations.forms import OperationAdministrativeActWizard, \
+ AdministrativeActOpeForm, AdministrativeActOpeFormSelection, \
+ AdministrativeActDeletionWizard, FinalAdministrativeActDeleteForm, \
+ is_preventive
+from ishtar_common import widgets
+
+class FileWizard(Wizard):
+ model = models.File
+ object_parcel_type = 'associated_file'
+
+ def get_form(self, request, storage, step=None, data=None, files=None):
+ """
+ Manage towns
+ """
+ if data:
+ data = data.copy()
+ else:
+ data = {}
+ # manage the dynamic choice of towns
+ if not step:
+ step = self.determine_step(request, storage)
+ form = self.get_form_list(request, storage)[step]
+ town_form_key = 'towns-' + self.url_name
+ if step.startswith('parcels-') and hasattr(form, 'management_form') \
+ and self.session_has_key(request, storage, town_form_key):
+ towns = []
+ qdict = request.session[storage.prefix]['step_data'][town_form_key]
+ for k in qdict.keys():
+ if k.endswith("town") and qdict[k]:
+ try:
+ town = Town.objects.get(pk=int(qdict[k]))
+ towns.append((town.pk, unicode(town)))
+ except (ObjectDoesNotExist, ValueError):
+ pass
+ data['TOWNS'] = sorted(towns, key=lambda x:x[1])
+ form = super(FileWizard, self).get_form(request, storage, step, data,
+ files)
+ return form
+
+ def get_extra_model(self, dct, request, storage, form_list):
+ dct = super(FileWizard, self).get_extra_model(dct, request, storage,
+ form_list)
+ if not dct['numeric_reference']:
+ current_ref = models.File.objects.filter(year=dct['year']
+ ).aggregate(Max('numeric_reference'))["numeric_reference__max"]
+ dct['numeric_reference'] = current_ref and current_ref + 1 or 1
+ return dct
+
+ def done(self, request, storage, form_list, **kwargs):
+ '''
+ Save parcels
+ '''
+ r = super(FileWizard, self).done(request, storage, form_list,
+ return_object=True, **kwargs)
+ if type(r) not in (list, tuple) or len(r) != 2:
+ return r
+ obj, res = r
+ obj.parcels.clear()
+ for form in form_list:
+ if not hasattr(form, 'prefix') \
+ or not form.prefix.startswith('parcels-') \
+ or not hasattr(form, 'forms'):
+ continue
+ for frm in form.forms:
+ if not frm.is_valid():
+ continue
+ dct = frm.cleaned_data.copy()
+ if 'parcel' in dct:
+ try:
+ parcel = models.Parcel.objects.get(pk=dct['parcel'])
+ setattr(parcel, self.object_parcel_type, obj)
+ parcel.save()
+ except (ValueError, ObjectDoesNotExist):
+ continue
+ continue
+ try:
+ dct['town'] = models.Town.objects.get(pk=int(dct['town']))
+ except (ValueError, ObjectDoesNotExist):
+ continue
+ dct['associated_file'], dct['operation'] = None, None
+ dct[self.object_parcel_type] = obj
+ if 'DELETE' in dct:
+ dct.pop('DELETE')
+ parcel = models.Parcel.objects.filter(**dct).count()
+ if not parcel:
+ dct['history_modifier'] = request.user
+ parcel = models.Parcel(**dct)
+ parcel.save()
+ return res
+
+class FileSelect(forms.Form):
+ towns = get_town_field()
+ in_charge = get_person_field(label=_(u"Person in charge"),
+ person_type='sra_agent')
+ file_type = forms.ChoiceField(label=_("File type"),
+ choices=models.FileType.get_types())
+ saisine_type = forms.ChoiceField(label=_("Saisine type"), choices=[])
+ year = forms.IntegerField(label=_("Year"))
+
+ 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()
+
+class FileFormSelection(forms.Form):
+ form_label = _("Archaeological file search")
+ associated_models = {'pk':models.File}
+ currents = {'pk':models.File}
+ pk = forms.IntegerField(label="", required=False,
+ widget=widgets.JQueryJqGrid(reverse_lazy('get-file'),
+ FileSelect(), models.File, source_full=reverse_lazy('get-file-full')),
+ validators=[models.valid_id(models.File)])
+
+ 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 a file."))
+ return cleaned_data
+
+class FileFormGeneral(forms.Form):
+ form_label = _("General")
+ associated_models = {'in_charge':models.Person,
+ 'related_file':models.File,
+ 'file_type':models.FileType}
+ in_charge = forms.IntegerField(label=_("Person in charge"),
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person',
+ args=[models.PersonType.objects.get(txt_idx='sra_agent').pk]),
+ associated_model=models.Person, new=True),
+ validators=[models.valid_id(models.Person)])
+ year = forms.IntegerField(label=_("Year"),
+ initial=lambda:datetime.datetime.now().year,
+ validators=[validators.MinValueValidator(1900),
+ validators.MaxValueValidator(2100)])
+ numeric_reference = forms.IntegerField(label=_("Numeric reference"),
+ widget=forms.HiddenInput, required=False)
+ internal_reference = forms.CharField(label=_(u"Internal reference"),
+ max_length=60,
+ validators=[models.is_unique(models.File, 'internal_reference')])
+ creation_date = forms.DateField(label=_(u"Creation date"),
+ initial=get_now, widget=widgets.JQueryDate)
+ file_type = forms.ChoiceField(label=_("File type"),
+ choices=models.FileType.get_types())
+ related_file = forms.IntegerField(label=_("Related file"), required=False,
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'),
+ associated_model=models.File),
+ validators=[models.valid_id(models.File)])
+ comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,
+ required=False)
+
+class FileFormGeneralRO(FileFormGeneral):
+ year = forms.IntegerField(label=_(u"Year"),
+ widget=forms.TextInput(attrs={'readonly':True}))
+ numeric_reference = forms.IntegerField(label=_(u"Numeric reference"),
+ widget=forms.TextInput(attrs={'readonly':True}))
+ internal_reference = forms.CharField(label=_(u"Internal reference"),
+ widget=forms.TextInput(attrs={'readonly':True},))
+
+class FileFormAddress(forms.Form):
+ form_label = _(u"Address")
+ associated_models = {'town':models.Town}
+ total_surface = forms.IntegerField(required=False,
+ widget=widgets.AreaWidget,
+ label=_(u"Total surface (m²)"),
+ validators=[validators.MinValueValidator(0),
+ validators.MaxValueValidator(999999999)])
+ address = forms.CharField(label=_(u"Main address"), widget=forms.Textarea)
+ address_complement = forms.CharField(label=_(u"Main address - complement"),
+ required=False)
+ postal_code = forms.CharField(label=_(u"Main address - postal code"),
+ max_length=10)
+
+class FileFormPreventive(forms.Form):
+ form_label = _(u"Preventive informations")
+ associated_models = {'general_contractor':models.Person,
+ 'saisine_type':models.SaisineType,
+ 'permit_type':models.PermitType,
+ 'town_planning_service':models.Organization}
+ general_contractor = forms.IntegerField(label=_(u"General contractor"),
+ widget=widgets.JQueryAutoComplete(
+ reverse_lazy('autocomplete-person',
+ args=[models.PersonType.objects.get(txt_idx='general_contractor').pk]),
+ associated_model=models.Person, new=True),
+ validators=[models.valid_id(models.Person)])
+ town_planning_service = forms.IntegerField(required=False,
+ label=_(u"Town planning service"),
+ widget=widgets.JQueryAutoComplete(
+ reverse_lazy('autocomplete-organization',
+ args=[models.OrganizationType.objects.get(txt_idx='planning_service').pk]),
+ associated_model=models.Organization, new=True),
+ validators=[models.valid_id(models.Organization)])
+ permit_type = forms.ChoiceField(label=_(u"Permit type"), required=False,
+ choices=models.PermitType.get_types())
+ permit_reference = forms.CharField(label=_(u"Permit reference"),
+ required=False, validators=[validators.MaxLengthValidator(60)])
+ total_developed_surface = forms.IntegerField(widget=widgets.AreaWidget,
+ label=_(u"Total developed surface (m²)"),
+ required=False, validators=[validators.MinValueValidator(0),
+ validators.MaxValueValidator(999999999)])
+ if settings.COUNTRY == 'fr':
+ saisine_type = forms.ChoiceField(label=_(u"Saisine type"),
+ choices=[])
+ reception_date = forms.DateField(label=_(u"Reception date"),
+ initial=get_now, widget=widgets.JQueryDate)
+ def __init__(self, *args, **kwargs):
+ super(FileFormPreventive, self).__init__(*args, **kwargs)
+ self.fields['saisine_type'].choices = models.SaisineType.get_types()
+ self.fields['saisine_type'].help_text = models.SaisineType.get_help()
+
+file_search_wizard = SearchWizard([('general-file_search', FileFormSelection)],
+ url_name='file_search',)
+
+file_creation_wizard = FileWizard([
+ ('general-file_creation', FileFormGeneral),
+ ('address-file_creation', FileFormAddress),
+ ('towns-file_creation', TownFormset),
+ ('parcels-file_creation', ParcelFormSet),
+ ('preventive-file_creation', FileFormPreventive),
+ ('final-file_creation', FinalForm)],
+ condition_list={
+'preventive-file_creation':is_preventive('general-file_creation',
+ models.FileType, type_key='file_type')
+ },
+ url_name='file_creation',)
+
+class FileModificationWizard(FileWizard):
+ modification = True
+
+file_modification_wizard = FileModificationWizard([
+ ('selec-file_modification', FileFormSelection),
+ ('general-file_modification', FileFormGeneralRO),
+ ('adress-file_modification', FileFormAddress),
+ ('towns-file_modification', TownFormset),
+ ('parcels-file_modification', ParcelFormSet),
+ ('preventive-file_modification', FileFormPreventive),
+ ('final-file_modification', FinalForm)],
+ condition_list={
+'preventive-file_modification':is_preventive('general-file_modification',
+ models.FileType, type_key='file_type')
+ },
+ url_name='file_modification',)
+
+class FileClosingWizard(ClosingWizard):
+ model = models.File
+ fields = ['year', 'numeric_reference', 'internal_reference',
+ 'file_type', 'in_charge', 'general_contractor', 'creation_date',
+ 'reception_date', 'total_surface', 'total_developed_surface',
+ 'address', 'address_complement', 'postal_code', 'comment']
+ if settings.COUNTRY == 'fr':
+ fields += ['saisine_type', 'reference_number']
+ fields += ['towns']
+
+class FinalFileClosingForm(FinalForm):
+ confirm_msg = " "
+ confirm_end_msg = _(u"Would you like to close this archaeological file?")
+
+file_closing_wizard = FileClosingWizard([
+ ('selec-file_closing', FileFormSelection),
+ ('date-file_closing', ClosingDateFormSelection),
+ ('final-file_closing', FinalFileClosingForm)],
+ url_name='file_closing',)
+
+class FileDeletionWizard(FileClosingWizard):
+ def get_formated_datas(self, forms):
+ datas = super(FileDeletionWizard, self).get_formated_datas(forms)
+ datas.append((_("Associated operations"), []))
+ for operation in models.Operation.objects.filter(
+ associated_file=self.current_obj).all():
+ if operation.end_date:
+ datas[-1][1].append(('', unicode(operation)))
+ return datas
+
+ def done(self, request, storage, form_list, **kwargs):
+ obj = self.get_current_object(request, storage)
+ for operation in models.Operation.objects.filter(
+ associated_file=obj).all():
+ operation.delete()
+ obj.delete()
+ return render_to_response('wizard_done.html', {},
+ context_instance=RequestContext(request))
+
+
+class FinalFileDeleteForm(FinalForm):
+ confirm_msg = " "
+ confirm_end_msg = _(u"Would you like to delete this archaelogical file ?")
+
+file_deletion_wizard = FileDeletionWizard([
+ ('selec-file_deletion', FileFormSelection),
+ ('final-file_deletion', FinalFileDeleteForm)],
+ url_name='file_deletion',)
+
+class FileAdministrativeActWizard(OperationAdministrativeActWizard):
+ model = models.File
+
+class FileEditAdministrativeActWizard(FileAdministrativeActWizard):
+ model = models.AdministrativeAct
+ edit = True
+ def get_associated_item(self, request, storage, dct):
+ return self.get_current_object(request, storage).associated_file
+
+class AdministrativeActFileSelect(forms.Form):
+ associated_file__towns = get_town_field()
+ act_type = forms.ChoiceField(label=_("Act type"), choices=[])
+
+ def __init__(self, *args, **kwargs):
+ super(AdministrativeActFileSelect, self).__init__(*args, **kwargs)
+ self.fields['act_type'].choices = models.ActType.get_types(
+ dct={'intented_to':'F'})
+ self.fields['act_type'].help_text = models.ActType.get_help(
+ dct={'intented_to':'F'})
+
+class AdministrativeActFileFormSelection(AdministrativeActOpeFormSelection):
+ pk = forms.IntegerField(label="", required=False,
+ widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactfile'),
+ AdministrativeActFileSelect(), models.AdministrativeAct,
+ table_cols='TABLE_COLS_FILE'),
+ validators=[models.valid_id(models.AdministrativeAct)])
+
+class AdministrativeActFileForm(AdministrativeActOpeForm):
+ act_type = forms.ChoiceField(label=_(u"Act type"), choices=[])
+
+ def __init__(self, *args, **kwargs):
+ super(AdministrativeActFileForm, self).__init__(*args, **kwargs)
+ self.fields['act_type'].choices = models.ActType.get_types(
+ dct={'intented_to':'F'})
+ self.fields['act_type'].help_text = models.ActType.get_help(
+ dct={'intented_to':'F'})
+
+file_administrativeactfile_wizard = FileAdministrativeActWizard([
+ ('selec-file_administrativeactfile', FileFormSelection),
+ ('administrativeact-file_administrativeactfile', AdministrativeActFileForm),
+ ('final-file_administrativeactfile', FinalForm)],
+ url_name='file_administrativeactfile',)
+
+file_administrativeactfile_modification_wizard = FileEditAdministrativeActWizard([
+ ('selec-file_administrativeactfile_modification',
+ AdministrativeActFileFormSelection),
+ ('administrativeact-file_administrativeactfile_modification',
+ AdministrativeActFileForm),
+ ('final-file_administrativeactfile_modification', FinalForm)],
+ url_name='file_administrativeactfile_modification',)
+
+file_administrativeactfile_deletion_wizard = AdministrativeActDeletionWizard([
+ ('selec-file_administrativeactfile_deletion',
+ AdministrativeActFileFormSelection),
+ ('final-file_administrativeactfile_deletion',
+ FinalAdministrativeActDeleteForm)],
+ url_name='file_administrativeactfile_deletion',)
+
diff --git a/archaeological_files/ishtar_menu.py b/archaeological_files/ishtar_menu.py
index 370320f69..398b43f4b 100644
--- a/archaeological_files/ishtar_menu.py
+++ b/archaeological_files/ishtar_menu.py
@@ -21,14 +21,13 @@ from django.utils.translation import ugettext_lazy as _
from archaeological_operations.models import Operation
from ishtar_common.menu_base import SectionItem, MenuItem
-from ishtar_common.models import AdministrativeAct
-import models
+from archaeological_operations.models import AdministrativeAct
-ORDER = 20
+import models
MENU_SECTIONS = [
- SectionItem('file_management', _(u"Archaeological file"),
+ (20, SectionItem('file_management', _(u"Archaeological file"),
childs=[
MenuItem('file_search', _(u"Search"),
model=models.File,
@@ -62,4 +61,5 @@ MENU_SECTIONS = [
access_controls=['delete_file', 'delete_own_file']),
],),
]),
+ )
]
diff --git a/archaeological_files/models.py b/archaeological_files/models.py
index 68a65f6de..90f60fe64 100644
--- a/archaeological_files/models.py
+++ b/archaeological_files/models.py
@@ -24,7 +24,8 @@ from django.contrib.gis.db import models
from django.utils.translation import ugettext_lazy as _, ugettext
from ishtar_common.models import GeneralType, BaseHistorizedItem, \
- HistoricalRecords, OwnPerms, Person, Organization, Department, Town
+ HistoricalRecords, OwnPerms, Person, Organization, Department, Town, \
+ Dashboard
class FileType(GeneralType):
class Meta:
@@ -183,3 +184,124 @@ class FileByDepartment(models.Model):
class Meta:
managed = False
db_table = 'file_department'
+
+class FileDashboard:
+ def __init__(self):
+ main_dashboard = Dashboard(File)
+
+ self.total_number = main_dashboard.total_number
+
+ types = File.objects.values('file_type', 'file_type__label')
+ self.types = types.annotate(number=Count('pk')).order_by('file_type')
+
+ by_year = File.objects.extra(
+ {'date':"date_trunc('year', creation_date)"})
+ self.by_year = by_year.values('date')\
+ .annotate(number=Count('pk')).order_by('-date')
+
+ now = datetime.date.today()
+ limit = datetime.date(now.year, now.month, 1) - datetime.timedelta(365)
+ by_month = File.objects.filter(creation_date__gt=limit).extra(
+ {'date':"date_trunc('month', creation_date)"})
+ self.by_month = by_month.values('date')\
+ .annotate(number=Count('pk')).order_by('-date')
+
+ # research
+ self.research = {}
+ prog_type = FileType.objects.get(txt_idx='prog')
+ researchs = File.objects.filter(file_type=prog_type)
+ self.research['total_number'] = researchs.count()
+ by_year = researchs.extra({'date':"date_trunc('year', creation_date)"})
+ self.research['by_year'] = by_year.values('date')\
+ .annotate(number=Count('pk'))\
+ .order_by('-date')
+ by_month = researchs.filter(creation_date__gt=limit)\
+ .extra({'date':"date_trunc('month', creation_date)"})
+ self.research['by_month'] = by_month.values('date')\
+ .annotate(number=Count('pk'))\
+ .order_by('-date')
+
+ self.research['by_dpt'] = FileByDepartment.objects\
+ .filter(file__file_type=prog_type,
+ department__isnull=False)\
+ .values('department__label')\
+ .annotate(number=Count('file'))\
+ .order_by('department__label')
+ FileTown = File.towns.through
+ self.research['towns'] = FileTown.objects\
+ .filter(file__file_type=prog_type)\
+ .values('town__name')\
+ .annotate(number=Count('file'))\
+ .order_by('-number','town__name')[:10]
+
+ # rescue
+ rescue_type = FileType.objects.get(txt_idx='preventive')
+ rescues = File.objects.filter(file_type=rescue_type)
+ self.rescue = {}
+ self.rescue['total_number'] = rescues.count()
+ self.rescue['saisine'] = rescues.values('saisine_type__label')\
+ .annotate(number=Count('pk'))\
+ .order_by('saisine_type__label')
+ self.rescue['administrative_act'] = AdministrativeAct.objects\
+ .filter(associated_file__isnull=False)\
+ .values('act_type__label')\
+ .annotate(number=Count('pk'))\
+ .order_by('act_type__pk')
+
+ by_year = rescues.extra({'date':"date_trunc('year', creation_date)"})
+ self.rescue['by_year'] = by_year.values('date')\
+ .annotate(number=Count('pk'))\
+ .order_by('-date')
+ by_month = rescues.filter(creation_date__gt=limit)\
+ .extra({'date':"date_trunc('month', creation_date)"})
+ self.rescue['by_month'] = by_month.values('date')\
+ .annotate(number=Count('pk'))\
+ .order_by('-date')
+
+ self.rescue['by_dpt'] = FileByDepartment.objects\
+ .filter(file__file_type=rescue_type,
+ department__isnull=False)\
+ .values('department__label')\
+ .annotate(number=Count('file'))\
+ .order_by('department__label')
+ self.rescue['towns'] = FileTown.objects\
+ .filter(file__file_type=rescue_type)\
+ .values('town__name')\
+ .annotate(number=Count('file'))\
+ .order_by('-number','town__name')[:10]
+
+ self.rescue['with_associated_operation'] = rescues\
+ .filter(operations__isnull=False).count()
+
+ self.rescue['with_associated_operation_percent'] = round(
+ float(self.rescue['with_associated_operation'])\
+ /self.rescue['total_number']*100, 2)
+
+ by_year_operationnal = rescues.filter(operations__isnull=False)\
+ .extra({'date':"date_trunc('year', creation_date)"})
+ by_year_operationnal = by_year_operationnal.values('date')\
+ .annotate(number=Count('pk'))\
+ .order_by('-date')
+ percents, idx = [], 0
+ for dct in self.rescue['by_year']:
+ if idx > len(by_year_operationnal):
+ break
+ if by_year_operationnal[idx]['date'] != dct['date'] or\
+ not dct['number']:
+ continue
+ val = round(float(by_year_operationnal[idx]['number'])/\
+ dct['number']*100, 2)
+ percents.append({'date':dct['date'], 'number':val})
+ self.rescue['operational_by_year'] = percents
+
+ self.rescue['surface_by_town'] = FileTown.objects\
+ .filter(file__file_type=rescue_type)\
+ .values('town__name')\
+ .annotate(number=Sum('file__total_surface'))\
+ .order_by('-number','town__name')[:10]
+ self.rescue['surface_by_dpt'] = FileByDepartment.objects\
+ .filter(file__file_type=rescue_type,
+ department__isnull=False)\
+ .values('department__label')\
+ .annotate(number=Sum('file__total_surface'))\
+ .order_by('department__label')
diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py
new file mode 100644
index 000000000..e32ab8294
--- /dev/null
+++ b/archaeological_files/urls.py
@@ -0,0 +1,64 @@
+#!/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'file_search/(?P<step>.+)$',
+ forms.file_search_wizard, name='file_search'),
+ url(r'file_creation/(?P<step>.+)$',
+ forms.file_creation_wizard, name='file_creation'),
+ url(r'file_modification/(?P<step>.+)$',
+ forms.file_modification_wizard, name='file_modification'),
+ url(r'file_closing/(?P<step>.+)$',
+ forms.file_closing_wizard, name='file_closing'),
+ url(r'file_deletion/(?P<step>.+)$',
+ forms.file_deletion_wizard, name='file_deletion'),
+ url(r'file_administrativeactfile/(?P<step>.+)$',
+ forms.file_administrativeactfile_wizard,
+ name='file_administrativeactfile'),
+ url(r'file_administrativeactfile_modification/(?P<step>.+)$',
+ forms.file_administrativeactfile_modification_wizard,
+ name='file_administrativeactfile_modification'),
+ url(r'file_administrativeactfile_deletion/(?P<step>.+)$',
+ forms.file_administrativeactfile_deletion_wizard,
+ name='file_administrativeactfile_deletion'),
+)
+
+urlpatterns += patterns('archaeological_files.views',
+ url(r'autocomplete-file/$', 'autocomplete_file',
+ name='autocomplete-file'),
+ url(r'get-file/(?P<type>.+)?$', 'get_file',
+ name='get-file'),
+ url(r'get-file-full/(?P<type>.+)?$', 'get_file',
+ name='get-file-full', kwargs={'full':True}),
+ url(r'get-administrativeactfile/(?P<type>.+)?$',
+ 'get_administrativeactfile', name='get-administrativeactfile'),
+ url(r'show-file/(?P<pk>.+)?/(?P<type>.+)?$', 'show_file',
+ name='show-file'),
+ url(r'show-historized-file/(?P<pk>.+)?/(?P<date>.+)?$',
+ 'show_file', name='show-historized-file'),
+ url(r'revert-file/(?P<pk>.+)/(?P<date>.+)$',
+ 'revert_file', name='revert-file'),
+)
+"""
diff --git a/archaeological_files/views.py b/archaeological_files/views.py
new file mode 100644
index 000000000..02332b629
--- /dev/null
+++ b/archaeological_files/views.py
@@ -0,0 +1,66 @@
+#!/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_file(request):
+ person_types = request.user.ishtaruser.person.person_type
+ if (not request.user.has_perm('ishtar_common.view_file', models.File) and \
+ not request.user.has_perm('ishtar_common.view_own_file', models.File)
+ and not person_types.rights.filter(wizard__url_name='file_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(internal_reference__icontains=q) | \
+ Q(towns__name__icontains=q)
+ try:
+ value = int(q)
+ extra = extra | Q(year=q) | Q(numeric_reference=q)
+ except ValueError:
+ pass
+ query = query & extra
+ limit = 20
+ files = models.File.objects.filter(query)[:limit]
+ data = json.dumps([{'id':file.pk, 'value':unicode(file)}
+ for file in files])
+ return HttpResponse(data, mimetype='text/plain')
+
+get_file = get_item(models.File, 'get_file', 'file')
+show_file = show_item(models.File, 'file')
+revert_file = revert_item(models.File)
+
+def dashboard_file(request, dct, obj_id=None, *args, **kwargs):
+ """
+ Main dashboard
+ """
+ dct = {'dashboard': models.FileDashboard()}
+ return render_to_response('dashboard_file.html', dct,
+ context_instance=RequestContext(request))
+