diff options
44 files changed, 1650 insertions, 111 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 5160c1c51..0683b695f 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016  É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 @@ -299,4 +299,5 @@ class RecordSourceSelect(SourceSelect):  RecordSourceFormSelection = get_form_selection(      'RecordSourceFormSelection', _(u"Documentation search"), 'pk',      models.ContextRecordSource, RecordSourceSelect, 'get-contextrecordsource', -    _(u"You should select a document.")) +    _(u"You should select a document."), +    get_full_url='get-contextrecordsource-full') diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index bd18ab5d4..ddd9c8609 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2012-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2012-2016 É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 @@ -112,9 +112,8 @@ class ContextRecord(BaseHistorizedItem, OwnPerms, ShortMenuItem):                    'label', 'unit']      if settings.COUNTRY == 'fr':          TABLE_COLS.insert(1, 'operation.code_patriarche') -    TABLE_COLS_FOR_OPE = [ -        'label', ['parcel.section', 'parcel.parcel_number'], 'unit', -        'datings.period', 'description'] +    TABLE_COLS_FOR_OPE = ['label', 'parcel', 'unit', +                          'datings.period', 'description']      TABLE_COLS_FOR_OPE_LBL = {'section__parcel_number': _("Parcel")}      external_id = models.CharField(_(u"External ID"), blank=True, null=True,                                     max_length=120) @@ -210,6 +209,7 @@ class ContextRecord(BaseHistorizedItem, OwnPerms, ShortMenuItem):              Q(history_creator=user)      def full_label(self): +        return unicode(self)          if not self.operation:              return unicode(self)          return self._real_label() or self._temp_label() diff --git a/archaeological_context_records/urls.py b/archaeological_context_records/urls.py index da6d80a98..52af8bda9 100644 --- a/archaeological_context_records/urls.py +++ b/archaeological_context_records/urls.py @@ -59,6 +59,8 @@ urlpatterns = patterns(  urlpatterns += patterns(      'archaeological_context_records.views', +    url(r'autocomplete-contextrecord/$', 'autocomplete_contextrecord', +        name='autocomplete-contextrecord'),      url(r'show-contextrecord(?:/(?P<pk>.+))?/(?P<type>.+)?$',          'show_contextrecord', name=models.ContextRecord.SHOW_URL),      url(r'show-historized-contextrecord/(?P<pk>.+)?/(?P<date>.+)?$', @@ -85,4 +87,7 @@ urlpatterns += patterns(          'show_contextrecordsource', name=models.ContextRecordSource.SHOW_URL),      url(r'get-contexrecordsource/(?P<type>.+)?$',          'get_contextrecordsource', name='get-contextrecordsource'), +    url(r'get-contexrecordsource-full/(?P<type>.+)?$', +        'get_contextrecordsource', name='get-contextrecordsource-full', +        kwargs={'full': True}),  ) diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index 883b2c85e..839dbed9e 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016  É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 @@ -17,7 +17,11 @@  # See the file COPYING for details. +import json +  from django.core.urlresolvers import reverse +from django.db.models import Q +from django.http import HttpResponse  from django.shortcuts import redirect  from django.utils.translation import ugettext_lazy as _ @@ -43,6 +47,35 @@ contextrecord_extra_keys = {      'archaeological_sites': 'operation__archaeological_sites__pk',  } + +def autocomplete_contextrecord(request): +    if (not request.user.has_perm( +            'archaeological_context_records.view_contextrecord', +            models.ContextRecord) +        and not request.user.has_perm( +            'archaeological_context_records.view_own_contextrecord', +            models.ArchaeologicalSite)): +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    if request.GET.get('operation__pk'): +        query = Q(operation__pk=request.GET.get('operation__pk')) +    for q in q.split(' '): +        qt = Q(parcel__section__icontains=q) | \ +            Q(parcel__parcel_number__icontains=q) | \ +            Q(label__icontains=q) +        query = query & qt +    limit = 15 +    items = models.ContextRecord.objects\ +        .filter(query).order_by('parcel__section', 'parcel__parcel_number', +                                'label')[:limit] +    data = json.dumps([{'id': item.pk, +                        'value': unicode(item)[:60]} +                       for item in items]) +    return HttpResponse(data, mimetype='text/plain') +  get_contextrecord = get_item(      models.ContextRecord,      'get_contextrecord', 'contextrecord', diff --git a/archaeological_files/ishtar_menu.py b/archaeological_files/ishtar_menu.py index 326fec23b..dfff7d0ab 100644 --- a/archaeological_files/ishtar_menu.py +++ b/archaeological_files/ishtar_menu.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2014 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 É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 diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 519d3ced3..0258cb16d 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -331,7 +331,7 @@ class File(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem,      @classmethod      def get_owns(cls, user):          owns = super(File, cls).get_owns(user) -        return sorted(owns.all(), key=lambda x: x.cached_label) +        return sorted(owns, key=lambda x: x.cached_label)      def get_values(self, prefix=''):          values = super(File, self).get_values(prefix=prefix) diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 3cfe13ea9..99907781b 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -24,13 +24,15 @@ Finds forms definitions  from django import forms  from django.conf import settings  from django.core import validators +from django.core.exceptions import PermissionDenied  from django.forms.formsets import formset_factory  from django.utils.safestring import mark_safe  from django.utils.translation import ugettext_lazy as _  from ishtar_common.models import Person, valid_id, valid_ids  from archaeological_operations.models import Period, ArchaeologicalSite -from archaeological_context_records.models import DatingType, DatingQuality +from archaeological_context_records.models import DatingType, DatingQuality, \ +    ContextRecord  from archaeological_warehouse.models import Warehouse  import models @@ -40,6 +42,38 @@ from ishtar_common.forms import FormSet, FloatField, \  from ishtar_common.forms_common import get_town_field, SourceSelect +class RecordFormSelection(forms.Form): +    form_label = _("Context record") +    base_models = ['get_first_base_find'] +    associated_models = {'get_first_base_find__context_record': ContextRecord} +    get_first_base_find__context_record = forms.IntegerField( +        label=_(u"Context record"), required=False, +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-contextrecord'), +            associated_model=ContextRecord), +        validators=[valid_id(ContextRecord)]) + +    def __init__(self, *args, **kwargs): +        super(RecordFormSelection, self).__init__(*args, **kwargs) +        # get the current operation and restrict search to it +        cr_pk = None +        if 'data' in kwargs and kwargs['data']: +            cr_pk = kwargs['data'].get( +                'get_first_base_find__context_record') +        if not cr_pk and 'initial' in kwargs and kwargs['initial']: +            cr_pk = kwargs['initial'].get( +                'get_first_base_find__context_record') +        if not cr_pk: +            return +        try: +            cr = ContextRecord.objects.get(pk=cr_pk) +        except ContextRecord.DoesNotExist: +            return +        widget = self.fields['get_first_base_find__context_record'].widget +        widget.source = unicode(widget.source) + "?operation__pk={}".format( +            cr.operation.pk) + +  class FindForm(forms.Form):      file_upload = True      form_label = _("Find") @@ -217,6 +251,20 @@ class FindFormSelection(forms.Form):          validators=[valid_id(models.Find)]) +class MultipleFindFormSelection(forms.Form): +    form_label = _("Find search") +    associated_models = {'pk': models.Find} +    currents = {'pk': models.Find} +    pk = forms.IntegerField( +        label="", required=False, +        widget=widgets.JQueryJqGrid( +            reverse_lazy('get-find'), +            FindSelect, models.Find, +            multiple_select=True, +            source_full=reverse_lazy('get-find-full')), +        validators=[valid_id(models.Find)]) + +  class BaseTreatmentForm(forms.Form):      form_label = _(u"Base treatment")      associated_models = {'treatment_type': models.TreatmentType, @@ -354,9 +402,77 @@ class FindSourceSelect(SourceSelect):  FindSourceFormSelection = get_form_selection(      'FindSourceFormSelection', _(u"Documentation search"), 'pk',      models.FindSource, FindSourceSelect, 'get-findsource', -    _(u"You should select a document.")) +    _(u"You should select a document."), +    get_full_url='get-findsource-full') +class NewFindBasketForm(forms.ModelForm): +    class Meta: +        model = models.FindBasket +        fields = ('label', 'comment') + +    def __init__(self, *args, **kwargs): +        self.user = kwargs.pop('user') +        super(NewFindBasketForm, self).__init__(*args, **kwargs) + +    def clean(self): +        q = models.FindBasket.objects.filter(user=self.user, +                                             label=self.cleaned_data['label']) +        if q.count(): +            raise forms.ValidationError(_(u"Another basket already exist with " +                                          u"this name.")) +        return self.cleaned_data + +    def save(self, commit=True): +        self.instance.user = self.user +        return super(NewFindBasketForm, self).save(commit) + + +class SelectFindBasketForm(forms.Form): +    basket = forms.ChoiceField(label=_(u"Basket"), required=True, choices=[]) + +    def __init__(self, *args, **kwargs): +        self.user = kwargs.pop('user') +        super(SelectFindBasketForm, self).__init__(*args, **kwargs) +        self.fields['basket'].choices = [('', '--')] + [ +            (b.pk, unicode(b)) +            for b in models.FindBasket.objects.filter(user=self.user)] + + +class DeleteFindBasketForm(SelectFindBasketForm): +    def save(self): +        try: +            models.FindBasket.objects.get(pk=self.cleaned_data['basket'], +                                          user=self.user).delete() +        except models.FindBasket.DoesNotExist: +            # something strange... TODO: log it +            pass +        return + + +class FindBasketAddItemForm(forms.Form): +    basket_id = forms.IntegerField(required=True) +    item_id = forms.IntegerField(required=True) + +    def save(self, user): +        try: +            basket = models.FindBasket.objects.get( +                pk=self.cleaned_data['basket_id'], user=user.ishtaruser) +            item = models.Find.objects.get( +                pk=self.cleaned_data['item_id']) +        except models.FindBasket.DoesNotExist or\ +                models.Find.DoesNotExist: +            # something strange... TODO: log it +            raise PermissionDenied +        # check rights +        if not user.is_superuser and \ +                not user.ishtaruser.has_right('change_find') and \ +                not (user.ishtaruser.has_right('change_own_find') +                     and item.is_own(user)): +            raise PermissionDenied +        basket.items.add(item) +        return basket +  """  ####################################  # Source management for treatments # diff --git a/archaeological_finds/ishtar_menu.py b/archaeological_finds/ishtar_menu.py index daa12a37b..d7a67091a 100644 --- a/archaeological_finds/ishtar_menu.py +++ b/archaeological_finds/ishtar_menu.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2012-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2012-2016 É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 @@ -56,6 +56,26 @@ MENU_SECTIONS = [                   access_controls=['change_find',                                    'change_own_find']),               SectionItem( +                 'find_basket', _(u"Basket"), +                 childs=[ +                     MenuItem('find_basket_creation', +                              _(u"Creation"), +                              model=models.FindBasket, +                              access_controls=['change_find', +                                               'change_own_find']), +                     MenuItem('find_basket_modification_add', +                              _(u"Manage items"), +                              model=models.FindBasket, +                              access_controls=[ +                                  'change_find', +                                  'change_own_find']), +                     MenuItem('find_basket_deletion', +                              _(u"Deletion"), +                              model=models.FindBasket, +                              access_controls=['change_find', +                                               'change_own_find']), +                 ]), +             SectionItem(                   'find_source', _(u"Documentation"),                   childs=[                       MenuItem('find_source_creation', diff --git a/archaeological_finds/migrations/0045_auto__add_findbasket__add_unique_findbasket_label_user.py b/archaeological_finds/migrations/0045_auto__add_findbasket__add_unique_findbasket_label_user.py new file mode 100644 index 000000000..2879e422a --- /dev/null +++ b/archaeological_finds/migrations/0045_auto__add_findbasket__add_unique_findbasket_label_user.py @@ -0,0 +1,951 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + +    def forwards(self, orm): +        # Adding model 'FindBasket' +        db.create_table('archaeological_finds_findbasket', ( +            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), +            ('label', self.gf('django.db.models.fields.CharField')(max_length=1000)), +            ('comment', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), +            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ishtar_common.IshtarUser'], null=True, blank=True)), +            ('available', self.gf('django.db.models.fields.BooleanField')(default=True)), +        )) +        db.send_create_signal('archaeological_finds', ['FindBasket']) + +        # Adding M2M table for field items on 'FindBasket' +        db.create_table('archaeological_finds_findbasket_items', ( +            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), +            ('findbasket', models.ForeignKey(orm['archaeological_finds.findbasket'], null=False)), +            ('find', models.ForeignKey(orm['archaeological_finds.find'], null=False)) +        )) +        db.create_unique('archaeological_finds_findbasket_items', ['findbasket_id', 'find_id']) + +        # Adding unique constraint on 'FindBasket', fields ['label', 'user'] +        db.create_unique('archaeological_finds_findbasket', ['label', 'user_id']) + + +    def backwards(self, orm): +        # Removing unique constraint on 'FindBasket', fields ['label', 'user'] +        db.delete_unique('archaeological_finds_findbasket', ['label', 'user_id']) + +        # Deleting model 'FindBasket' +        db.delete_table('archaeological_finds_findbasket') + +        # Removing M2M table for field items on 'FindBasket' +        db.delete_table('archaeological_finds_findbasket_items') + + +    models = { +        'archaeological_context_records.activitytype': { +            'Meta': {'ordering': "('order',)", 'object_name': 'ActivityType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_context_records.contextrecord': { +            'Meta': {'object_name': 'ContextRecord'}, +            'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.ActivityType']", 'null': 'True', 'blank': 'True'}), +            'closing_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'datings': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['archaeological_context_records.Dating']", 'symmetrical': 'False'}), +            'depth': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'filling': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'has_furniture': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'identification': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.IdentificationType']", 'null': 'True', 'blank': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_context_records_contextrecord'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'interpretation': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '200'}), +            'length': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'location': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'opening_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'operation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'context_record'", 'to': "orm['archaeological_operations.Operation']"}), +            'parcel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'context_record'", 'to': "orm['archaeological_operations.Parcel']"}), +            'related_context_records': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_context_records.ContextRecord']", 'null': 'True', 'through': "orm['archaeological_context_records.RecordRelations']", 'blank': 'True'}), +            'taq': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'taq_estimated': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'thickness': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'tpq': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'tpq_estimated': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'unit': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['archaeological_context_records.Unit']"}), +            'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_context_records.dating': { +            'Meta': {'object_name': 'Dating'}, +            'dating_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.DatingType']", 'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'period': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Period']"}), +            'precise_dating': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'quality': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.DatingQuality']", 'null': 'True', 'blank': 'True'}), +            'start_date': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_context_records.datingquality': { +            'Meta': {'ordering': "('label',)", 'object_name': 'DatingQuality'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_context_records.datingtype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'DatingType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_context_records.identificationtype': { +            'Meta': {'ordering': "('order',)", 'object_name': 'IdentificationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_context_records.recordrelations': { +            'Meta': {'object_name': 'RecordRelations'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'left_record': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'right_relations'", 'to': "orm['archaeological_context_records.ContextRecord']"}), +            'relation_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.RelationType']"}), +            'right_record': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'left_relations'", 'to': "orm['archaeological_context_records.ContextRecord']"}) +        }, +        'archaeological_context_records.relationtype': { +            'Meta': {'ordering': "('order',)", 'object_name': 'RelationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'inverse_relation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.RelationType']", 'null': 'True', 'blank': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'symmetrical': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_context_records.unit': { +            'Meta': {'ordering': "('order',)", 'object_name': 'Unit'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_context_records.Unit']", 'null': 'True', 'blank': 'True'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_files.file': { +            'Meta': {'ordering': "('cached_label',)", 'object_name': 'File'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'cached_label': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'cira_advised': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'classified_area': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'corporation_general_contractor': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'general_contractor_files'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'creation_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today', 'null': 'True', 'blank': 'True'}), +            'departments': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'file_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.FileType']"}), +            'general_contractor': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'general_contractor_files'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imported_line': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_files_file'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'file_responsability'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'instruction_deadline': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'internal_reference': ('django.db.models.fields.CharField', [], {'max_length': '60', 'null': 'True', 'blank': 'True'}), +            'locality': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'main_town': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'file_main'", 'null': 'True', 'to': "orm['ishtar_common.Town']"}), +            'mh_listing': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'mh_register': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'numeric_reference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'organization': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'files'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'permit_reference': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'permit_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.PermitType']", 'null': 'True', 'blank': 'True'}), +            'planning_service': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'planning_service_files'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'protected_area': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'raw_general_contractor': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'raw_town_planning_service': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'reception_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'related_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.File']", 'null': 'True', 'blank': 'True'}), +            'requested_operation_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.OperationType']"}), +            'research_comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'responsible_town_planning_service': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'responsible_town_planning_service_files'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'saisine_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.SaisineType']", 'null': 'True', 'blank': 'True'}), +            'scientist': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'scientist'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'total_developed_surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'total_surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'towns': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'file'", 'symmetrical': 'False', 'to': "orm['ishtar_common.Town']"}), +            'year': ('django.db.models.fields.IntegerField', [], {'default': '2016'}) +        }, +        'archaeological_files.filetype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'FileType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_files.permittype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'PermitType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_files.saisinetype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'SaisineType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'delay': ('django.db.models.fields.IntegerField', [], {'default': '30'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.basefind': { +            'Meta': {'object_name': 'BaseFind'}, +            'batch': ('django.db.models.fields.CharField', [], {'default': "'U'", 'max_length': '1'}), +            'cache_complete_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'cache_short_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'context_record': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'base_finds'", 'to': "orm['archaeological_context_records.ContextRecord']"}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'discovery_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_finds_basefind'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'label': ('django.db.models.fields.TextField', [], {}), +            'material_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'special_interest': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'topographic_localisation': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.conservatorystate': { +            'Meta': {'ordering': "('label',)", 'object_name': 'ConservatoryState'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.ConservatoryState']", 'null': 'True', 'blank': 'True'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.find': { +            'Meta': {'object_name': 'Find'}, +            'base_finds': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'find'", 'symmetrical': 'False', 'to': "orm['archaeological_finds.BaseFind']"}), +            'check_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}), +            'checked': ('django.db.models.fields.CharField', [], {'default': "'NC'", 'max_length': '2'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'conservatory_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.ConservatoryState']", 'null': 'True', 'blank': 'True'}), +            'container': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'finds'", 'null': 'True', 'to': "orm['archaeological_warehouse.Container']"}), +            'dating_comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'datings': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'find'", 'symmetrical': 'False', 'to': "orm['archaeological_context_records.Dating']"}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'diameter': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'downstream_treatment': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'upstream_treatment'", 'null': 'True', 'to': "orm['archaeological_finds.Treatment']"}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'find_number': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'height': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_finds_find'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'integrities': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'find'", 'symmetrical': 'False', 'to': "orm['archaeological_finds.IntegrityType']"}), +            'is_complete': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'label': ('django.db.models.fields.TextField', [], {}), +            'length': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'mark': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'material_types': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'finds'", 'symmetrical': 'False', 'to': "orm['archaeological_finds.MaterialType']"}), +            'object_types': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'find'", 'symmetrical': 'False', 'to': "orm['archaeological_finds.ObjectType']"}), +            'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'preservation_to_considers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'finds'", 'symmetrical': 'False', 'to': "orm['archaeological_finds.PreservationType']"}), +            'previous_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'thumbnail': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'upstream_treatment': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'downstream_treatment'", 'null': 'True', 'to': "orm['archaeological_finds.Treatment']"}), +            'volume': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'weight_unit': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), +            'width': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.findbasket': { +            'Meta': {'unique_together': "(('label', 'user'),)", 'object_name': 'FindBasket'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'items': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_finds.Find']", 'null': 'True', 'blank': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '1000'}), +            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.IshtarUser']", 'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.findsource': { +            'Meta': {'object_name': 'FindSource'}, +            'additional_information': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'associated_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'authors': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'findsource_related'", 'symmetrical': 'False', 'to': "orm['ishtar_common.Author']"}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'duplicate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '12', 'null': 'True', 'blank': 'True'}), +            'find': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source'", 'to': "orm['archaeological_finds.Find']"}), +            'format_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Format']", 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'internal_reference': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'item_number': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'receipt_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'receipt_date_in_documentation': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'reference': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'scale': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'source_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.SourceType']"}), +            'support_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.SupportType']", 'null': 'True', 'blank': 'True'}), +            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}) +        }, +        'archaeological_finds.historicalbasefind': { +            'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalBaseFind'}, +            'batch': ('django.db.models.fields.CharField', [], {'default': "'U'", 'max_length': '1'}), +            'cache_complete_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'cache_short_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'context_record_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'discovery_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'history_creator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), +            'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), +            'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), +            'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}), +            'index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'label': ('django.db.models.fields.TextField', [], {}), +            'material_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'special_interest': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'topographic_localisation': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.historicalfind': { +            'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalFind'}, +            'check_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}), +            'checked': ('django.db.models.fields.CharField', [], {'default': "'NC'", 'max_length': '2'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'conservatory_state_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'container_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'dating_comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'diameter': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'downstream_treatment_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'find_number': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'height': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'history_creator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), +            'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), +            'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), +            'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}), +            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'index': ('django.db.models.fields.IntegerField', [], {'default': '0'}), +            'is_complete': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'label': ('django.db.models.fields.TextField', [], {}), +            'length': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'mark': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'previous_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'thumbnail': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'upstream_treatment_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'volume': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'weight_unit': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), +            'width': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.historicaltreatment': { +            'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalTreatment'}, +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'container_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'history_creator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), +            'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), +            'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), +            'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}), +            'location_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'other_location': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'person_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'treatment_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_finds.integritytype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'IntegrityType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.materialtype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'MaterialType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.MaterialType']", 'null': 'True', 'blank': 'True'}), +            'recommendation': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.objecttype': { +            'Meta': {'ordering': "('parent__label', 'label')", 'object_name': 'ObjectType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.ObjectType']", 'null': 'True', 'blank': 'True'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.preservationtype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'PreservationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_finds.property': { +            'Meta': {'object_name': 'Property'}, +            'administrative_act': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.AdministrativeAct']"}), +            'end_date': ('django.db.models.fields.DateField', [], {}), +            'find': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.Find']"}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_finds_property'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'properties'", 'to': "orm['ishtar_common.Person']"}), +            'start_date': ('django.db.models.fields.DateField', [], {}) +        }, +        'archaeological_finds.treatment': { +            'Meta': {'object_name': 'Treatment'}, +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'container': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_warehouse.Container']", 'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_finds_treatment'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'location': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_warehouse.Warehouse']", 'null': 'True', 'blank': 'True'}), +            'other_location': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'person': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'treatments'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'treatment_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_finds.TreatmentType']"}) +        }, +        'archaeological_finds.treatmentsource': { +            'Meta': {'object_name': 'TreatmentSource'}, +            'additional_information': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'associated_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'authors': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'treatmentsource_related'", 'symmetrical': 'False', 'to': "orm['ishtar_common.Author']"}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'duplicate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '12', 'null': 'True', 'blank': 'True'}), +            'format_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Format']", 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'internal_reference': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'item_number': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'receipt_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'receipt_date_in_documentation': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'reference': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'scale': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'source_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.SourceType']"}), +            'support_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.SupportType']", 'null': 'True', 'blank': 'True'}), +            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), +            'treatment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source'", 'to': "orm['archaeological_finds.Treatment']"}) +        }, +        'archaeological_finds.treatmenttype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'TreatmentType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), +            'virtual': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) +        }, +        'archaeological_operations.acttype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'ActType'}, +            'associated_template': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'acttypes'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.DocumentTemplate']"}), +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'indexed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'intented_to': ('django.db.models.fields.CharField', [], {'max_length': '1'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_operations.administrativeact': { +            'Meta': {'ordering': "('year', 'signature_date', 'index', 'act_type')", 'object_name': 'AdministrativeAct'}, +            'act_object': ('django.db.models.fields.TextField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'act_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.ActType']"}), +            'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'administrative_act'", 'null': 'True', 'to': "orm['archaeological_files.File']"}), +            'departments_label': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_operations_administrativeact'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'adminact_operation_in_charge'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'index': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'operation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'administrative_act'", 'null': 'True', 'to': "orm['archaeological_operations.Operation']"}), +            'operator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'adminact_operator'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'ref_sra': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), +            'scientist': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'adminact_scientist'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'signatory': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'signatory'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'signature_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'towns_label': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_operations.archaeologicalsite': { +            'Meta': {'object_name': 'ArchaeologicalSite'}, +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_operations_archaeologicalsite'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'periods': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_operations.Period']", 'null': 'True', 'blank': 'True'}), +            'reference': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}), +            'remains': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_operations.RemainType']", 'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_operations.operation': { +            'Meta': {'ordering': "('cached_label',)", 'object_name': 'Operation'}, +            'abstract': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'archaeological_sites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_operations.ArchaeologicalSite']", 'null': 'True', 'blank': 'True'}), +            'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operations'", 'null': 'True', 'to': "orm['archaeological_files.File']"}), +            'cached_label': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), +            'cira_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'cira_rapporteur': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'cira_rapporteur'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'code_dracar': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'code_patriarche': ('django.db.models.fields.IntegerField', [], {'unique': 'True', 'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'common_name': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'creation_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}), +            'eas_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), +            'effective_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'excavation_end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'fnap_cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'fnap_financing': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), +            'geoarchaeological_context_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_operations_operation'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operation_responsability'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'large_area_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'negative_result': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), +            'operation_code': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'operation_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['ishtar_common.OperationType']"}), +            'operator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operator'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'operator_reference': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), +            'optional_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'periods': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_operations.Period']", 'null': 'True', 'blank': 'True'}), +            'record_quality': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}), +            'remains': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['archaeological_operations.RemainType']", 'null': 'True', 'blank': 'True'}), +            'report_delivery_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'report_processing': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.ReportState']", 'null': 'True', 'blank': 'True'}), +            'scheduled_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'scientist': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operation_scientist_responsability'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), +            'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'towns': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.Town']", 'symmetrical': 'False'}), +            'virtual_operation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'zoning_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_operations.parcel': { +            'Meta': {'ordering': "('year', 'section', 'parcel_number')", 'object_name': 'Parcel'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parcels'", 'null': 'True', 'to': "orm['archaeological_files.File']"}), +            'external_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_operations_parcel'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            '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', 'null': 'True', 'blank': 'True'}), +            '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.period': { +            'Meta': {'ordering': "('order',)", 'object_name': 'Period'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'end_date': ('django.db.models.fields.IntegerField', [], {}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Period']", 'null': 'True', 'blank': 'True'}), +            'start_date': ('django.db.models.fields.IntegerField', [], {}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_operations.remaintype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'RemainType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_operations.reportstate': { +            'Meta': {'ordering': "('order',)", 'object_name': 'ReportState'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'archaeological_warehouse.container': { +            'Meta': {'object_name': 'Container'}, +            'comment': ('django.db.models.fields.TextField', [], {}), +            'container_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_warehouse.ContainerType']"}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_warehouse_container'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'location': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_warehouse.Warehouse']"}), +            'reference': ('django.db.models.fields.CharField', [], {'max_length': '40'}) +        }, +        'archaeological_warehouse.containertype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'ContainerType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'length': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'reference': ('django.db.models.fields.CharField', [], {'max_length': '30'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), +            'volume': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'archaeological_warehouse.warehouse': { +            'Meta': {'object_name': 'Warehouse'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'email': ('django.db.models.fields.EmailField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_archaeological_warehouse_warehouse'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}), +            'person_in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'warehouse_in_charge'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Person']"}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), +            'warehouse_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_warehouse.WarehouseType']"}) +        }, +        'archaeological_warehouse.warehousetype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'WarehouseType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'auth.group': { +            'Meta': {'object_name': 'Group'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), +            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) +        }, +        'auth.permission': { +            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, +            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) +        }, +        'auth.user': { +            'Meta': {'object_name': 'User'}, +            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), +            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), +            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), +            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), +            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), +            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'contenttypes.contenttype': { +            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, +            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) +        }, +        'ishtar_common.arrondissement': { +            'Meta': {'object_name': 'Arrondissement'}, +            'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) +        }, +        'ishtar_common.author': { +            'Meta': {'object_name': 'Author'}, +            'author_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.AuthorType']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'to': "orm['ishtar_common.Person']"}) +        }, +        'ishtar_common.authortype': { +            'Meta': {'object_name': 'AuthorType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.canton': { +            'Meta': {'object_name': 'Canton'}, +            'arrondissement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Arrondissement']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) +        }, +        'ishtar_common.department': { +            'Meta': {'ordering': "['number']", 'object_name': 'Department'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '30'}), +            'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'}), +            'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.State']", 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.documenttemplate': { +            'Meta': {'ordering': "['associated_object_name', 'name']", 'object_name': 'DocumentTemplate'}, +            'associated_object_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'template': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) +        }, +        'ishtar_common.format': { +            'Meta': {'object_name': 'Format'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.import': { +            'Meta': {'object_name': 'Import'}, +            'conservative_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), +            'encoding': ('django.db.models.fields.CharField', [], {'default': "'utf-8'", 'max_length': '15'}), +            'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), +            'error_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imported_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), +            'imported_images': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'importer_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.ImporterType']"}), +            'match_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'result_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'seconds_remaining': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), +            'skip_lines': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'state': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '2'}), +            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.IshtarUser']"}) +        }, +        'ishtar_common.importertype': { +            'Meta': {'object_name': 'ImporterType'}, +            'associated_models': ('django.db.models.fields.CharField', [], {'max_length': '200'}), +            'description': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'is_template': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'unique': 'True', 'null': 'True', 'blank': 'True'}), +            'unicity_keys': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), +            'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ishtar_common.IshtarUser']", 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.ishtaruser': { +            'Meta': {'object_name': 'IshtarUser', '_ormbases': ['auth.User']}, +            'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ishtaruser'", 'unique': 'True', 'to': "orm['ishtar_common.Person']"}), +            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) +        }, +        'ishtar_common.operationtype': { +            'Meta': {'ordering': "['-preventive', 'order', 'label']", 'object_name': 'OperationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), +            'preventive': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.organization': { +            'Meta': {'object_name': 'Organization'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'email': ('django.db.models.fields.EmailField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'exclude_from_merge': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_ishtar_common_organization'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'merge_candidate': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_candidate_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Organization']"}), +            'merge_exclusion': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_exclusion_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Organization']"}), +            'merge_key': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}), +            'organization_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.OrganizationType']"}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.organizationtype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'OrganizationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.person': { +            'Meta': {'object_name': 'Person'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), +            'attached_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'members'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'contact_type': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'email': ('django.db.models.fields.EmailField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'exclude_from_merge': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}), +            'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_ishtar_common_person'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), +            'merge_candidate': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_candidate_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}), +            'merge_exclusion': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_exclusion_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}), +            'merge_key': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), +            'person_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.PersonType']", 'symmetrical': 'False'}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'raw_name': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), +            'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'surname': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), +            'title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.persontype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'PersonType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.sourcetype': { +            'Meta': {'object_name': 'SourceType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.state': { +            'Meta': {'ordering': "['number']", 'object_name': 'State'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '30'}), +            'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'}) +        }, +        'ishtar_common.supporttype': { +            'Meta': {'object_name': 'SupportType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) +        }, +        'ishtar_common.town': { +            'Meta': {'ordering': "['numero_insee']", 'object_name': 'Town'}, +            'canton': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Canton']", 'null': 'True', 'blank': 'True'}), +            'center': ('django.contrib.gis.db.models.fields.PointField', [], {'srid': '27572', 'null': 'True', 'blank': 'True'}), +            'departement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'numero_insee': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '6'}), +            'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        } +    } + +    complete_apps = ['archaeological_finds']
\ No newline at end of file diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py index b52aabbf2..417dd3929 100644 --- a/archaeological_finds/models.py +++ b/archaeological_finds/models.py @@ -27,7 +27,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext  from ishtar_common.models import GeneralType, ImageModel, BaseHistorizedItem, \      ShortMenuItem, LightHistorizedItem, HistoricalRecords, OwnPerms, Source, \ -    Person +    Person, Basket  from archaeological_operations.models import AdministrativeAct  from archaeological_context_records.models import ContextRecord, Dating @@ -240,6 +240,11 @@ CHECK_CHOICES = (('NC', _(u"Not checked")),                   ) +class FindBasket(Basket): +    items = models.ManyToManyField('Find', blank=True, null=True, +                                   related_name='basket') + +  class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem):      CHECK_DICT = dict(CHECK_CHOICES)      SHOW_URL = 'show-find' @@ -329,6 +334,7 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem):      check_date = models.DateField(_(u"Check date"),                                    default=datetime.date.today)      history = HistoricalRecords() +    BASKET_MODEL = FindBasket      def __init__(self, *args, **kwargs):          super(Find, self).__init__(*args, **kwargs) @@ -372,6 +378,18 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem):          return u" - ".join([base_find.name                              for base_find in self.base_finds.all()]) +    @property +    def full_label(self): +        lbl = u" - ".join([ +            getattr(self, attr) +            for attr in ('label', 'administrative_index') +            if getattr(self, attr)]) +        base = u" - ".join([base_find.complete_id() +                            for base_find in self.base_finds.all()]) +        if base: +            lbl += u' ({})'.format(base) +        return lbl +      def get_first_base_find(self):          q = self.base_finds          if not q.count(): diff --git a/archaeological_finds/templates/ishtar/sheet_findbasket.html b/archaeological_finds/templates/ishtar/sheet_findbasket.html new file mode 100644 index 000000000..00b52ab7b --- /dev/null +++ b/archaeological_finds/templates/ishtar/sheet_findbasket.html @@ -0,0 +1,16 @@ +{% extends "ishtar/sheet.html" %} +{% load i18n window_tables from_dict %} + +{% block head_sheet %} +{{block.super}} +<h1>{% trans "Find"%}</h1> +{% endblock %} + +{% block content %} + +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-findbasket item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-findbasket item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<div class='tool modify'><a href='{% url select_itemsinbasket item.pk %}'>{% trans "Modify" %}</a></div> + +{% dynamic_table_document_large finds 'finds_for_ope' 'basket' item.pk 'TABLE_COLS_FOR_OPE' output %} + +{% endblock %} diff --git a/archaeological_finds/templates/ishtar/sheet_findbasket_pdf.html b/archaeological_finds/templates/ishtar/sheet_findbasket_pdf.html new file mode 100644 index 000000000..37eecf81b --- /dev/null +++ b/archaeological_finds/templates/ishtar/sheet_findbasket_pdf.html @@ -0,0 +1,18 @@ +{% extends "ishtar/sheet_findbasket.html" %} +{% block header %} +<link rel="stylesheet" href="{{STATIC_URL}}/media/style_basic.css" /> +{% endblock %} +{% block main_head %} +{{ block.super }} +<div id="pdfheader"> +Ishtar – {{APP_NAME}} – {{item}} +</div> +{% endblock %} +{%block head_sheet%}{%endblock%} +{%block main_foot%} +<div id="pdffooter"> +– <pdf:pagenumber/> – +</div> +</body> +</html> +{%endblock%} diff --git a/archaeological_finds/templates/ishtar/sheet_findbasket_window.html b/archaeological_finds/templates/ishtar/sheet_findbasket_window.html new file mode 100644 index 000000000..5bc46d5c7 --- /dev/null +++ b/archaeological_finds/templates/ishtar/sheet_findbasket_window.html @@ -0,0 +1,3 @@ +{% extends "ishtar/sheet_findbasket.html" %} +{% block main_head %}{%endblock%} +{% block main_foot %}{%endblock%} diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py index acf9c46a6..e66743bf4 100644 --- a/archaeological_finds/urls.py +++ b/archaeological_finds/urls.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 É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 @@ -55,6 +55,33 @@ urlpatterns = patterns(          check_rights(['change_find', 'change_own_find'])(              views.find_source_deletion_wizard),          name='find_source_deletion'), +    url(r'^find_basket_creation/$', +        check_rights(['change_find', 'change_own_find'])( +            views.NewFindBasketView.as_view()), name='new_findbasket'), +    url(r'^find_basket_modification_add/$', +        check_rights(['change_find', 'change_own_find'])( +            views.SelectBasketForManagement.as_view()), +        name='select_findbasketforadd'), +    url(r'^find_basket_modification_add/(?P<pk>[0-9]+)?/$', +        check_rights(['change_find', 'change_own_find'])( +            views.SelectItemsInBasket.as_view()), +        name='select_itemsinbasket'), +    url(r'^find_basket_modification_add_item/$', +        check_rights(['change_find', 'change_own_find'])( +            views.FindBasketAddItemView.as_view()), +        name='add_iteminbasket'), +    url(r'^find_basket_modification_delete_item/(?P<basket>[0-9]+)?' +        r'/(?P<find_pk>[0-9]+)?/$', +        check_rights(['change_find', 'change_own_find'])( +            views.FindBasketDeleteItemView.as_view()), +        name='delete_iteminbasket'), +    url(r'^find_basket_list/(?P<pk>[0-9]+)?/$', +        check_rights(['change_find', 'change_own_find'])( +            views.FindBasketListView.as_view()), +        name='list_iteminbasket'), +    url(r'^find_basket_deletion/$', +        check_rights(['change_find', 'change_own_find'])( +            views.DeleteFindBasketView.as_view()), name='delete_findbasket'),  )  urlpatterns += patterns( @@ -81,8 +108,13 @@ urlpatterns += patterns(          name='get-find-full', kwargs={'full': True}),      url(r'get-findsource/(?P<type>.+)?$',          'get_findsource', name='get-findsource'), +    url(r'get-findsource-full/(?P<type>.+)?$', +        'get_findsource', name='get-findsource-full', +        kwargs={'full': True}),      url(r'show-findsource(?:/(?P<pk>.+))?/(?P<type>.+)?$', 'show_findsource',          name=models.FindSource.SHOW_URL), +    url(r'show-find/basket-(?P<pk>.+)/(?P<type>.+)?$', 'show_findbasket', +        name='show-findbasket'),      url(r'show-find(?:/(?P<pk>.+))?/(?P<type>.+)?$', 'show_find',          name=models.Find.SHOW_URL),      url(r'show-historized-find/(?P<pk>.+)?/(?P<date>.+)?$', diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py index afe6715a8..7bcca32c8 100644 --- a/archaeological_finds/views.py +++ b/archaeological_finds/views.py @@ -17,17 +17,23 @@  # See the file COPYING for details. +from django.core.exceptions import PermissionDenied  from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect  from django.shortcuts import redirect  from django.utils.translation import ugettext_lazy as _ +from django.views.generic import TemplateView +from django.views.generic.edit import CreateView, FormView  from ishtar_common.forms import FinalForm  from ishtar_common.forms_common import SourceForm, AuthorFormset, \      SourceDeletionForm -from archaeological_context_records.forms import RecordFormSelection +from ishtar_common.models import IshtarUser +from archaeological_context_records.forms \ +    import RecordFormSelection as RecordFormSelectionTable  from ishtar_common.views import get_item, show_item, revert_item, \ -    get_autocomplete_generic +    get_autocomplete_generic, IshtarMixin, LoginRequiredMixin  from ishtar_common.wizards import SearchWizard  from wizards import * @@ -57,6 +63,7 @@ find_extra_keys = {      'base_finds__find__description':          'base_finds__find__description__icontains',      'base_finds__batch': 'base_finds__batch', +    'basket': 'basket',      'image': 'image__isnull'}  get_find = get_item( @@ -90,8 +97,10 @@ get_findsource = get_item(  show_find = show_item(models.Find, 'find')  revert_find = revert_item(models.Find) +show_findbasket = show_item(models.FindBasket, 'findbasket') +  find_creation_wizard = FindWizard.as_view([ -    ('selecrecord-find_creation', RecordFormSelection), +    ('selecrecord-find_creation', RecordFormSelectionTable),      ('find-find_creation', FindForm),      ('dating-find_creation', DatingFormSet),      ('final-find_creation', FinalForm)], @@ -105,6 +114,7 @@ find_search_wizard = SearchWizard.as_view([  find_modification_wizard = FindModificationWizard.as_view([      ('selec-find_modification', FindFormSelection), +    ('selecrecord-find_modification', RecordFormSelection),      ('find-find_modification', FindForm),      ('dating-find_modification', DatingFormSet),      ('final-find_modification', FinalForm)], @@ -155,6 +165,149 @@ autocomplete_preservationtype = get_autocomplete_generic(      models.PreservationType)  autocomplete_integritytype = get_autocomplete_generic(models.IntegrityType) + +class NewFindBasketView(IshtarMixin, LoginRequiredMixin, CreateView): +    template_name = 'ishtar/form.html' +    model = models.FindBasket +    form_class = NewFindBasketForm +    page_name = _(u"New basket") + +    def get_form_kwargs(self): +        kwargs = super(NewFindBasketView, self).get_form_kwargs() +        kwargs['user'] = IshtarUser.objects.get(pk=self.request.user.pk) +        return kwargs + +    def get_success_url(self): +        return reverse('select_itemsinbasket', +                       kwargs={'pk': self.object.pk}) + +    def form_valid(self, form): +        self.object = form.save() +        return HttpResponseRedirect(self.get_success_url()) + + +class SelectBasketForManagement(IshtarMixin, LoginRequiredMixin, FormView): +    template_name = 'ishtar/form.html' +    form_class = SelectFindBasketForm +    page_name = _(u"Manage items in basket") + +    def get_form_kwargs(self): +        kwargs = super(SelectBasketForManagement, self).get_form_kwargs() +        kwargs['user'] = IshtarUser.objects.get(pk=self.request.user.pk) +        if 'pk' in self.kwargs: +            kwargs['initial'].update({'basket': self.kwargs['pk']}) +        return kwargs + +    def get_success_url(self, basket): +        return reverse('select_itemsinbasket', +                       kwargs={'pk': basket}) + +    def form_valid(self, form): +        return HttpResponseRedirect(self.get_success_url( +            form.cleaned_data['basket'])) + + +class SelectItemsInBasket(IshtarMixin, LoginRequiredMixin, TemplateView): +    template_name = 'ishtar/manage_basket.html' +    page_name = _(u"Manage basket") + +    def get_context_data(self, *args, **kwargs): +        context = super(SelectItemsInBasket, self).get_context_data( +            *args, **kwargs) +        self.user = IshtarUser.objects.get(pk=self.request.user.pk) +        try: +            self.basket = models.FindBasket.objects.get( +                pk=self.kwargs['pk'], user=self.user) +        except models.FindBasket.DoesNotExist: +            raise PermissionDenied +        context['basket'] = self.basket +        context['form'] = MultipleFindFormSelection() +        context['add_url'] = reverse('add_iteminbasket') +        context['list_url'] = reverse('list_iteminbasket', +                                      kwargs={'pk': self.basket.pk}) +        return context + +    def form_valid(self, form): +        return HttpResponseRedirect(self.get_success_url()) + + +class FindBasketAddItemView(IshtarMixin, LoginRequiredMixin, FormView): +    template_name = 'ishtar/simple_form.html' +    form_class = FindBasketAddItemForm + +    def get_success_url(self, basket): +        return reverse('list_iteminbasket', kwargs={'pk': basket.pk}) + +    def form_valid(self, form): +        user = IshtarUser.objects.get(pk=self.request.user.pk) +        # rights are checked on the form +        basket = form.save(user) +        return HttpResponseRedirect(self.get_success_url(basket)) + + +class FindBasketListView(IshtarMixin, LoginRequiredMixin, TemplateView): +    template_name = 'ishtar/basket_list.html' + +    def get_context_data(self, *args, **kwargs): +        context = super(FindBasketListView, self).get_context_data( +            *args, **kwargs) +        self.user = IshtarUser.objects.get(pk=self.request.user.pk) +        try: +            self.basket = models.FindBasket.objects.get( +                pk=self.kwargs['pk'], user=self.user) +        except models.FindBasket.DoesNotExist: +            raise PermissionDenied +        context['basket'] = self.basket +        context['item_url'] = '/'.join( +            reverse(models.Find.SHOW_URL, args=[1]).split('/')[:-1]) +        context['delete_url'] = '/'.join( +            reverse('delete_iteminbasket', args=[1, 1]).split('/')[:-3]) +        return context + + +class FindBasketDeleteItemView(IshtarMixin, LoginRequiredMixin, TemplateView): +    template_name = 'ishtar/simple_form.html' + +    def get_success_url(self, basket): +        return reverse('list_iteminbasket', kwargs={'pk': basket.pk}) + +    def get(self, *args, **kwargs): +        user = self.request.user +        ishtaruser = IshtarUser.objects.get(pk=self.request.user.pk) +        try: +            find = models.Find.objects.get( +                pk=self.kwargs['find_pk']) +        except models.Find.DoesNotExist: +            raise PermissionDenied +        try: +            basket = models.FindBasket.objects.get( +                pk=self.kwargs['basket'], user=ishtaruser) +        except models.FindBasket.DoesNotExist: +            raise PermissionDenied +        if not user.is_superuser and \ +                not ishtaruser.has_right('change_find') and \ +                not (ishtaruser.has_right('change_own_find') +                     and find.is_own(user)): +            raise PermissionDenied +        basket.items.remove(find) +        return HttpResponseRedirect(self.get_success_url(basket)) + + +class DeleteFindBasketView(IshtarMixin, LoginRequiredMixin, FormView): +    template_name = 'ishtar/form_delete.html' +    form_class = DeleteFindBasketForm +    success_url = '/' +    page_name = _(u"Delete basket") + +    def get_form_kwargs(self): +        kwargs = super(DeleteFindBasketView, self).get_form_kwargs() +        kwargs['user'] = IshtarUser.objects.get(pk=self.request.user.pk) +        return kwargs + +    def form_valid(self, form): +        form.save() +        return HttpResponseRedirect(self.get_success_url()) +  """  treatment_creation_wizard = TreatmentWizard.as_view([      ('basetreatment-treatment_creation', BaseTreatmentForm), diff --git a/archaeological_finds/wizards.py b/archaeological_finds/wizards.py index 61636aa25..fabe1039a 100644 --- a/archaeological_finds/wizards.py +++ b/archaeological_finds/wizards.py @@ -58,7 +58,7 @@ class FindWizard(Wizard):          if not current_cr or self.steps.current.startswith('select-'):              return context          context['reminders'] = ( -            (_("Operation"), unicode(current_cr.operation)), +            (_(u"Operation"), unicode(current_cr.operation)),              (_(u"Context record"), unicode(current_cr)))          return context diff --git a/archaeological_operations/admin.py b/archaeological_operations/admin.py index 9f886bc62..d976aac77 100644 --- a/archaeological_operations/admin.py +++ b/archaeological_operations/admin.py @@ -31,7 +31,7 @@ class AdministrativeActAdmin(HistorizedObjectAdmin):      list_filter = ('act_type',)      search_fields = ('year', 'index')      readonly_fields = ('in_charge', 'operator', 'scientist', 'signatory', -                       'operation', 'associated_file', 'imports', +                       'associated_file', 'imports',                         'departments_label', 'towns_label',                         'history_modifier', 'history_creator')      model = models.AdministrativeAct diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 49824e24a..b61285177 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -1136,7 +1136,8 @@ class OperationSourceSelect(SourceSelect):  OperationSourceFormSelection = get_form_selection(      'OperationSourceFormSelection', _(u"Documentation search"), 'pk',      models.OperationSource, OperationSourceSelect, 'get-operationsource', -    _(u"You should select a document.")) +    _(u"You should select a document."), +    get_full_url='get-operationsource-full')  ################################################  # Administrative act management for operations # diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 253ea7635..e3453f0cf 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -251,7 +251,7 @@ class Operation(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem,          owns = super(Operation, cls).get_owns(user)          # owns = owns.annotate(null_count=Count('operation_code'))          # return owns.order_by("common_name", "-year", "operation_code") -        return sorted(owns.all(), key=lambda x: x.cached_label) +        return sorted(owns, key=lambda x: x.cached_label)      def __unicode__(self):          if self.cached_label: diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 76723deab..ef7d14dd6 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -130,6 +130,9 @@ urlpatterns += patterns(          'show_operationsource', name=models.OperationSource.SHOW_URL),      url(r'get-operationsource/(?P<type>.+)?$',          'get_operationsource', name='get-operationsource'), +    url(r'get-operationsource-full/(?P<type>.+)?$', +        'get_operationsource', name='get-operationsource-full', +        kwargs={'full': True}),      url(r'dashboard_operation/$', 'dashboard_operation',          name='dashboard-operation'),      url(r'autocomplete-archaeologicalsite/$', diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index c90b6fa8a..c51b88d0b 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -361,6 +361,7 @@ class OperationAdministrativeActWizard(OperationWizard):          step = self.steps.current          if step.startswith('final-'):              general_form_key = 'administrativeact-' + self.url_name +            act_type = None              try:                  act_type = models.ActType.objects.get(                      pk=self.session_get_value(general_form_key, "act_type")) diff --git a/archaeological_warehouse/admin.py b/archaeological_warehouse/admin.py index b76c48308..cf71dbab6 100644 --- a/archaeological_warehouse/admin.py +++ b/archaeological_warehouse/admin.py @@ -17,13 +17,13 @@  # See the file COPYING for details. -from django.conf import settings  from django.contrib import admin  from ishtar_common.admin import HistorizedObjectAdmin, GeneralTypeAdmin  import models +  class WarehouseAdmin(HistorizedObjectAdmin):      list_display = ('name', 'warehouse_type', 'town')      list_filter = ('warehouse_type',) @@ -32,6 +32,7 @@ class WarehouseAdmin(HistorizedObjectAdmin):  admin.site.register(models.Warehouse, WarehouseAdmin) +  class ContainerTypeAdmin(admin.ModelAdmin):      list_display = ('label', 'reference', 'length', 'width', 'height',                      'volume') @@ -39,6 +40,7 @@ class ContainerTypeAdmin(admin.ModelAdmin):  admin.site.register(models.ContainerType, ContainerTypeAdmin) +  class ContainerAdmin(admin.ModelAdmin):      list_display = ('reference', 'location', 'container_type',)      list_filter = ("container_type",) diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py index ff869c5fb..f045fac1e 100644 --- a/archaeological_warehouse/forms.py +++ b/archaeological_warehouse/forms.py @@ -17,8 +17,6 @@  # See the file COPYING for details. -import datetime -  from django import forms  from django.conf import settings  from django.utils.translation import ugettext_lazy as _ @@ -31,6 +29,7 @@ from ishtar_common.forms import name_validator, reverse_lazy, \      get_form_selection, TableSelect  from archaeological_finds.forms import FindMultipleFormSelection +  def get_warehouse_field(label=_(u"Warehouse"), required=True):      # !FIXME hard_link, reverse_lazy doen't seem to work with formsets      url = "/" + settings.URL_PATH + 'autocomplete-warehouse' @@ -38,16 +37,19 @@ def get_warehouse_field(label=_(u"Warehouse"), required=True):      return forms.IntegerField(widget=widget, label=label, required=required,                                validators=[valid_id(models.Warehouse)]) +  class WarehouseForm(forms.Form):      name = forms.CharField(label=_(u"Name"), max_length=40, -                              validators=[name_validator]) +                           validators=[name_validator])      warehouse_type = forms.ChoiceField(label=_(u"Warehouse type"),                                         choices=[]) -    person_in_charge = forms.IntegerField(label=_(u"Person in charge"), -         widget=widgets.JQueryAutoComplete( -           reverse_lazy('autocomplete-person'), associated_model=models.Person), -           validators=[valid_id(models.Person)], -           required=False) +    person_in_charge = forms.IntegerField( +        label=_(u"Person in charge"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person'), +            associated_model=models.Person), +        validators=[valid_id(models.Person)], +        required=False)      comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,                                required=False)      address = forms.CharField(label=_(u"Address"), widget=forms.Textarea, @@ -66,50 +68,54 @@ class WarehouseForm(forms.Form):      def __init__(self, *args, **kwargs):          super(WarehouseForm, self).__init__(*args, **kwargs)          self.fields['warehouse_type'].choices = \ -                                          models.WarehouseType.get_types() +            models.WarehouseType.get_types()          self.fields['warehouse_type'].help_text = \ -                                          models.WarehouseType.get_help() +            models.WarehouseType.get_help()      def save(self, user):          dct = self.cleaned_data          dct['history_modifier'] = user          dct['warehouse_type'] = models.WarehouseType.objects.get( -                                                     pk=dct['warehouse_type']) +            pk=dct['warehouse_type'])          if 'person_in_charge' in dct and dct['person_in_charge']:              dct['person_in_charge'] = models.Person.objects.get( -                                                     pk=dct['person_in_charge']) +                pk=dct['person_in_charge'])          new_item = models.Warehouse(**dct)          new_item.save()          return new_item +  class ContainerForm(forms.Form):      form_label = _(u"Container")      reference = forms.CharField(label=_(u"Ref."))      container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) -    location = forms.IntegerField(label=_(u"Warehouse"), -         widget=widgets.JQueryAutoComplete( -     reverse_lazy('autocomplete-warehouse'), associated_model=models.Warehouse, -     new=True), -     validators=[valid_id(models.Warehouse)]) +    location = forms.IntegerField( +        label=_(u"Warehouse"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-warehouse'), +            associated_model=models.Warehouse, new=True), +        validators=[valid_id(models.Warehouse)])      comment = forms.CharField(label=_(u"Comment"),                                widget=forms.Textarea, required=False)      def __init__(self, *args, **kwargs):          super(ContainerForm, self).__init__(*args, **kwargs) -        self.fields['container_type'].choices = models.ContainerType.get_types() +        self.fields['container_type'].choices = \ +            models.ContainerType.get_types()          self.fields['container_type'].help_text = \ -                                                models.ContainerType.get_help() +            models.ContainerType.get_help()      def save(self, user):          dct = self.cleaned_data          dct['history_modifier'] = user          dct['container_type'] = models.ContainerType.objects.get( -                                                    pk=dct['container_type']) +            pk=dct['container_type'])          dct['location'] = models.Warehouse.objects.get(pk=dct['location'])          new_item = models.Container(**dct)          new_item.save()          return new_item +  class ContainerSelect(TableSelect):      location = get_warehouse_field()      container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) @@ -118,9 +124,9 @@ class ContainerSelect(TableSelect):      def __init__(self, *args, **kwargs):          super(ContainerSelect, self).__init__(*args, **kwargs)          self.fields['container_type'].choices = \ -                                            models.ContainerType.get_types() +            models.ContainerType.get_types()          self.fields['container_type'].help_text = \ -                                            models.ContainerType.get_help() +            models.ContainerType.get_help()  ContainerFormSelection = get_form_selection(      'ContainerFormSelection', _(u"Container search"), 'container', @@ -128,23 +134,27 @@ ContainerFormSelection = get_form_selection(      _(u"You should select a container."), new=True,      new_message=_(u"Add a new container")) +  class BasePackagingForm(forms.Form):      form_label = _(u"Packaging") -    associated_models = {'treatment_type':TreatmentType, -                         'person':Person, -                         'location':models.Warehouse} +    associated_models = {'treatment_type': TreatmentType, +                         'person': Person, +                         'location': models.Warehouse}      treatment_type = forms.IntegerField(label="", widget=forms.HiddenInput) -    person = forms.IntegerField(label=_(u"Packager"), -         widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), -                                      associated_model=Person, new=True), -           validators=[valid_id(Person)]) -    start_date = forms.DateField(label=_(u"Date"), required=False, -                               widget=widgets.JQueryDate) +    person = forms.IntegerField( +        label=_(u"Packager"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person'), +            associated_model=Person, new=True), +        validators=[valid_id(Person)]) +    start_date = forms.DateField( +        label=_(u"Date"), required=False, widget=widgets.JQueryDate)      def __init__(self, *args, **kwargs):          super(BasePackagingForm, self).__init__(*args, **kwargs)          self.fields['treatment_type'].initial = \ -                TreatmentType.objects.get(txt_idx='packaging').pk +            TreatmentType.objects.get(txt_idx='packaging').pk +  class FindPackagingFormSelection(FindMultipleFormSelection):      form_label = _(u"Packaged finds") diff --git a/archaeological_warehouse/ishtar_menu.py b/archaeological_warehouse/ishtar_menu.py index 2da50e7ce..f9f0daf33 100644 --- a/archaeological_warehouse/ishtar_menu.py +++ b/archaeological_warehouse/ishtar_menu.py @@ -27,13 +27,13 @@ from archaeological_finds.models import Treatment  MENU_SECTIONS = [ -    #    (60, SectionItem('find_management', _(u"Find"), -    #     profile_restriction='warehouse', -    #     childs=[ -    #        MenuItem('warehouse_packaging', _(u"Packaging"), -    #                 model=Treatment, -    #                 access_controls=['add_treatment', 'add_own_treatment']), -    #    ])), +    (60, SectionItem('find_management', _(u"Find"), +     profile_restriction='warehouse', +     childs=[ +        MenuItem('warehouse_packaging', _(u"Packaging"), +                 model=Treatment, +                 access_controls=['add_treatment', 'add_own_treatment']), +    ])),  ]  """      (60, SectionItem('warehouse', _(u"Warehouse"), diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 86e430a7e..3591f554a 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -17,12 +17,11 @@  # See the file COPYING for details. -from django.conf import settings  from django.contrib.gis.db import models  from django.utils.translation import ugettext_lazy as _, ugettext -from ishtar_common.models import GeneralType, BaseHistorizedItem, \ -                          LightHistorizedItem, OwnPerms, Address, Person +from ishtar_common.models import GeneralType, \ +    LightHistorizedItem, OwnPerms, Address, Person  class WarehouseType(GeneralType): @@ -31,13 +30,14 @@ class WarehouseType(GeneralType):          verbose_name_plural = _(u"Warehouse types")          ordering = ('label',) +  class Warehouse(Address, OwnPerms):      name = models.CharField(_(u"Name"), max_length=40)      warehouse_type = models.ForeignKey(WarehouseType,                                         verbose_name=_(u"Warehouse type")) -    person_in_charge = models.ForeignKey(Person, on_delete=models.SET_NULL, -                     related_name='warehouse_in_charge', -                     verbose_name=_(u"Person in charge"), null=True, blank=True) +    person_in_charge = models.ForeignKey( +        Person, on_delete=models.SET_NULL, related_name='warehouse_in_charge', +        verbose_name=_(u"Person in charge"), null=True, blank=True)      comment = models.TextField(_(u"Comment"), null=True, blank=True)      class Meta: @@ -54,6 +54,7 @@ class Warehouse(Address, OwnPerms):      def __unicode__(self):          return u"%s (%s)" % (self.name, unicode(self.warehouse_type)) +  class ContainerType(GeneralType):      length = models.IntegerField(_(u"Length (mm)"), blank=True, null=True)      width = models.IntegerField(_(u"Width (mm)"), blank=True, null=True) @@ -66,8 +67,9 @@ class ContainerType(GeneralType):          verbose_name_plural = _(u"Container types")          ordering = ('label',) +  class Container(LightHistorizedItem): -    TABLE_COLS = ['reference', 'container_type', 'location',] +    TABLE_COLS = ['reference', 'container_type', 'location']      location = models.ForeignKey(Warehouse, verbose_name=_(u"Warehouse"))      container_type = models.ForeignKey(ContainerType,                                         verbose_name=_("Container type")) @@ -82,4 +84,3 @@ class Container(LightHistorizedItem):          lbl = u" - ".join((self.reference, unicode(self.container_type),                             unicode(self.location)))          return lbl - diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 22eed80e3..aab18ed40 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -21,7 +21,6 @@ import json  from django.db.models import Q  from django.http import HttpResponse -from django.shortcuts import render_to_response  from django.utils.translation import ugettext_lazy as _  from ishtar_common.views import get_item, new_item @@ -30,13 +29,14 @@ from wizards import *  from ishtar_common.forms import FinalForm  from forms import * -get_container = get_item(models.Container, -        'get_container', 'container', -        extra_request_keys={ -                'location':'location__pk', -                'container_type':'container_type__pk', -                'reference':'reference__icontains', -        }) +get_container = get_item( +    models.Container, +    'get_container', 'container', +    extra_request_keys={ +        'location': 'location__pk', +        'container_type': 'container_type__pk', +        'reference': 'reference__icontains', +    })  new_warehouse = new_item(models.Warehouse, WarehouseForm)  new_container = new_item(models.Container, ContainerForm) @@ -54,12 +54,12 @@ def autocomplete_warehouse(request):      query = Q()      for q in q.split(' '):          extra = Q(name__icontains=q) | \ -                Q(warehouse_type__label__icontains=q) +            Q(warehouse_type__label__icontains=q)          query = query & extra      limit = 15      warehouses = models.Warehouse.objects.filter(query)[:limit] -    data = json.dumps([{'id':warehouse.pk, 'value':unicode(warehouse)} -                                          for warehouse in warehouses]) +    data = json.dumps([{'id': warehouse.pk, 'value': unicode(warehouse)} +                       for warehouse in warehouses])      return HttpResponse(data, mimetype='text/plain') @@ -75,15 +75,15 @@ def autocomplete_container(request):      query = Q()      for q in q.split(' '):          extra = Q(container_type__label__icontains=q) | \ -                Q(container_type__reference__icontains=q) | \ -                Q(reference__icontains=q) | \ -                Q(location__name=q) | \ -                Q(location__town=q) +            Q(container_type__reference__icontains=q) | \ +            Q(reference__icontains=q) | \ +            Q(location__name=q) | \ +            Q(location__town=q)          query = query & extra      limit = 15      containers = models.Container.objects.filter(query)[:limit] -    data = json.dumps([{'id':container.pk, 'value':unicode(container)} -                                          for container in containers]) +    data = json.dumps([{'id': container.pk, 'value': unicode(container)} +                       for container in containers])      return HttpResponse(data, mimetype='text/plain')  warehouse_packaging_wizard = PackagingWizard.as_view([ diff --git a/archaeological_warehouse/wizards.py b/archaeological_warehouse/wizards.py index c40894c25..833c1c697 100644 --- a/archaeological_warehouse/wizards.py +++ b/archaeological_warehouse/wizards.py @@ -19,7 +19,6 @@  from django.shortcuts import render_to_response  from django.template import RequestContext -from django.utils.translation import ugettext_lazy as _  from archaeological_finds.wizards import TreatmentWizard  from archaeological_finds.models import Treatment diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index 03ba9bc36..76f58bf8e 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -77,10 +77,13 @@ def get_base_context(request):          current = model_name in request.session and request.session[model_name]          items = []          for item in model.get_owns(request.user): -            selected = unicode(item.pk) == current +            pk = unicode(item.pk) +            if item.IS_BASKET: +                pk = "basket-" + pk +            selected = pk == current              if selected:                  cls = item.get_short_menu_class() -            items.append((item.pk, shortify(unicode(item), 60), +            items.append((pk, shortify(unicode(item), 60),                            selected, item.get_short_menu_class()))          if items:              dct['current_menu'].append((lbl, model_name, cls, items)) diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index a5abdddcd..5e0d14eb8 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -128,7 +128,7 @@ class ClosingDateFormSelection(forms.Form):  def get_form_selection(          class_name, label, key, model, base_form, get_url,          not_selected_error=_(u"You should select an item."), new=False, -        new_message=_(u"Add a new item")): +        new_message=_(u"Add a new item"), get_full_url=None):      """      Generate a class selection form          class_name -- name of the class @@ -145,11 +145,14 @@ def get_form_selection(               'form_label': label,               'associated_models': {key: model},               'currents': {key: model}} +    widget_kwargs = {"new": new, "new_message": new_message} +    if get_full_url: +        widget_kwargs['source_full'] = reverse_lazy(get_full_url)      attrs[key] = forms.IntegerField(          label="", required=False,          validators=[models.valid_id(model)],          widget=widgets.JQueryJqGrid(reverse_lazy(get_url), base_form, model, -                                    new=new, new_message=new_message)) +                                    **widget_kwargs))      def clean(self):          cleaned_data = self.cleaned_data diff --git a/ishtar_common/menu_base.py b/ishtar_common/menu_base.py index d8ee0775c..7c309d376 100644 --- a/ishtar_common/menu_base.py +++ b/ishtar_common/menu_base.py @@ -89,9 +89,9 @@ class MenuItem:          for access_control in self.access_controls:              access_control = prefix + access_control              if hasattr(user, 'ishtaruser') and \ -                user.ishtaruser.has_perm(access_control, self.model, -                                         session=session) or \ +                user.ishtaruser.has_perm(access_control, self.model) or\                 access_control in user.get_group_permissions(): +                #                         session=session) or \                  return True          # manage by person type          if hasattr(user, 'ishtaruser'): @@ -107,8 +107,8 @@ class MenuItem:          prefix = (self.model._meta.app_label + '.') if self.model else ''          for access_control in self.access_controls:              access_control = prefix + access_control -            if user.has_perm(access_control, self.model, obj=obj, -                             session=session): +            if user.has_perm(access_control, self.model, obj=obj): +                #              session=session):                  return True          # manage by person type          if hasattr(user, 'ishtaruser'): diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 9509b36a6..f3974d04d 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -243,10 +243,15 @@ class OwnPerms:              user = IshtarUser.objects.get(user_ptr=user)          if user.is_anonymous():              return cls.objects.filter(pk__isnull=True) +        items = [] +        if hasattr(cls, 'BASKET_MODEL'): +            items = list(cls.BASKET_MODEL.objects.filter(user=user).all())          query = cls.get_query_owns(user)          if not query:              return cls.objects.filter(pk__isnull=True) -        return cls.objects.filter(query).order_by(*cls._meta.ordering) +        items += list( +            cls.objects.filter(query).order_by(*cls._meta.ordering).all()) +        return items  class Cached(object): @@ -475,6 +480,33 @@ class GeneralType(models.Model, Cached):              item.generate_key() +class Basket(models.Model): +    """ +    Abstract class for a basket +    Subclass must be defined with an "items" ManyToManyField +    """ +    IS_BASKET = True +    label = models.CharField(_(u"Label"), max_length=1000) +    comment = models.TextField(_(u"Comment"), blank=True, null=True) +    user = models.ForeignKey('IshtarUser', blank=True, null=True) +    available = models.BooleanField(_(u"Available"), default=True) + +    class Meta: +        abstract = True +        unique_together = (('label', 'user'),) + +    def __unicode__(self): +        return self.label + +    def get_short_menu_class(self): +        return 'basket' + +    @property +    def associated_filename(self): +        return "{}-{}".format(datetime.date.today().strftime( +            "%Y-%m-%d"), slugify(self.label)) + +  class ItemKey(models.Model):      key = models.CharField(_(u"Key"), max_length=100)      content_type = models.ForeignKey(ContentType) @@ -551,6 +583,7 @@ class HistoryError(Exception):  class BaseHistorizedItem(Imported): +    IS_BASKET = False      history_modifier = models.ForeignKey(          User, related_name='+', on_delete=models.SET_NULL,          verbose_name=_(u"Last editor"), blank=True, null=True) diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 9af5cf2b0..f469fc546 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -23,6 +23,15 @@ beforeSend: function(xhr, settings) {      }  }}); +function manage_async_link(event){ +    event.preventDefault(); +    var url = $(this).attr('href'); +    var target = $(this).attr('data-target'); +    $.get(url, function(data) { +        $(target).html(data); +    }); +} +  /* default function to prevent undefined */  function get_next_table_id(){}  function get_previous_table_id(){} @@ -63,7 +72,8 @@ $(document).ready(function(){      }      $('#current_items select').change(function(){          $(this).attr('class', $(this).children("option:selected").attr('class')); -    }) +    }); +    $("a.async-link").click(manage_async_link);  });  $(document).on("click", '#to_bottom_arrow', function(){ diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index 1590c1738..1d47bcbd9 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -45,6 +45,12 @@ a.add-button,      color:#000;  } +#context_menu .basket{ +    color:#000; +    font-weight: bold; +    font-style: italic; +} +  /* borders */  a.add-button, a.remove,  #progress-content, diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index 578b3edcc..1bab3d647 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -74,7 +74,7 @@                  <td>                    <select class='{{main_cls}}' id='current_{{model_name}}'>                      <option class='normal' value=''>--</option> -                    {% for val, label, selected, cls in items %}<option class='{{cls}}' value='{{val}}'{%if selected%} selected="selected"{%endif%}>{{label}}</option> +                    {% for val, label, selected, cls in items %}<option class='{{cls}}' value='{{val}}'{% if selected %} selected="selected"{%endif%}>{{label}}</option>                    {% endfor %}</select>                  </td>{% with 'show-'|add:model_name as model_url%}                  <td><a href='#' onclick='load_current_window("{% url model_url 0 %}", "{{model_name}}");' class='display_details'>{% trans "Details" %}</a></td> @@ -87,7 +87,7 @@          {% endif %}{% endblock %}      </div>{% endif %}  {% if reminders %}<fieldset id='reminder'><legend>{% trans "Current items" %}</legend> -{% for lbl, value in reminders%} +{% for lbl, value in reminders %}  <p><strong class='lbl'>{{lbl}}{% trans ":"%}</strong> <span class='value'>{{value}}</span></p>  {% endfor %}  </fieldset>{%endif%} diff --git a/ishtar_common/templates/blocks/JQueryJqGrid.html b/ishtar_common/templates/blocks/JQueryJqGrid.html index 063a3c1da..c6a15243a 100644 --- a/ishtar_common/templates/blocks/JQueryJqGrid.html +++ b/ishtar_common/templates/blocks/JQueryJqGrid.html @@ -90,6 +90,7 @@ jQuery(document).ready(function(){      width: null,      shrinkToFit: false,      rowNum:20, +    {% if multiple_select %}multiselect: true,{% endif %}      jsonReader : {repeatitems: false},      loadError: function (jqXHR, textStatus, errorThrown) {          alert("{% trans "An error as occured during search. Check your query fields." %}"); diff --git a/ishtar_common/templates/ishtar/basket_list.html b/ishtar_common/templates/ishtar/basket_list.html new file mode 100644 index 000000000..a0a0e5d73 --- /dev/null +++ b/ishtar_common/templates/ishtar/basket_list.html @@ -0,0 +1,10 @@ +{% load i18n %} +<table> +<tr>{% for item in basket.items.all %} +    <td><a class="display_details" href="#" onclick="load_window('{{item_url}}/{{item.pk}}/');">{% trans 'Details' %}</a></td> +    <td>{{item.full_label}}</td> +    <td><a class='async-link' data-target='#basket-content' href='{{delete_url}}/{{basket.pk}}/{{item.pk}}/'>{% trans "remove" %}</a></td></tr>{% endfor %} +</table> +<script type='text/javascript'> +    $("a.async-link").click(manage_async_link); +</script> diff --git a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html index 7239b64fc..8850bd34a 100644 --- a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html +++ b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html @@ -42,6 +42,7 @@ setTimeout(              alert("{% trans "An error as occured during search. Check your query fields." %}");          }        }); +      {% if large %}jQuery("#grid_{{name}}").jqGrid('setGridHeight', 400);{% endif %}  }, 200);  </script> diff --git a/ishtar_common/templates/ishtar/form_delete.html b/ishtar_common/templates/ishtar/form_delete.html new file mode 100644 index 000000000..6243e9423 --- /dev/null +++ b/ishtar_common/templates/ishtar/form_delete.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n inline_formset %} +{% block content %} +<h2>{{page_name}}</h2> +<div class='form'> +<form enctype="multipart/form-data" action="." method="post" +    onsubmit="return confirm('Do you really want to delete this item?');">{% csrf_token %} +<table> +{{form}} +</table> +<input type="submit" value="{% trans "Delete" %}"/> +</form> +</div> +{% endblock %} diff --git a/ishtar_common/templates/ishtar/manage_basket.html b/ishtar_common/templates/ishtar/manage_basket.html new file mode 100644 index 000000000..6332b326e --- /dev/null +++ b/ishtar_common/templates/ishtar/manage_basket.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} +{% load i18n inline_formset %} +{% block content %} +<h2>{{page_name}}{% trans ":"%} {{basket}}</h2> +<form enctype="multipart/form-data" action="." method="post">{% csrf_token %} +<div class='form'> +<p class='alert'>{% trans 'Checking "Select all" only select the current page.' %}</p> +{{form}} +<button id='add_to' onclick='return false'>{% trans "Add" %}</button> +<h3>{% trans "Basket content" %}</h3> +<div id='basket-content' style='text-align:left'> +</div> +</div> +</form> +<script type='text/javascript' language='javascript'> + +function load_list(data){ +    $('#basket-content').html(data); +} + +$('#add_to').click(function(){ +    var selected_items = jQuery("#grid_pk").getGridParam('selarrrow'); +    if(!selected_items) return false; +    for (i = 0, n = selected_items.length; i < n; i++) { +        var selected_item = selected_items[i]; +        $.ajax({ +            type: "POST", +            url: '{{add_url}}', +            data: { +                basket_id: {{basket.pk}}, +                item_id: selected_item +            }, +            success: load_list +        }); +    } +    return false; +}); +jQuery(document).ready(function(){ +    $.get('{{list_url}}', load_list); +}); +</script> +{% endblock %} diff --git a/ishtar_common/templates/ishtar/simple_form.html b/ishtar_common/templates/ishtar/simple_form.html new file mode 100644 index 000000000..e3a464459 --- /dev/null +++ b/ishtar_common/templates/ishtar/simple_form.html @@ -0,0 +1,11 @@ +{% load i18n  %} +<html> +<body> +<div class='form'> +<form enctype="multipart/form-data" action="." method="post">{% csrf_token %} +{{form}} +<input type="submit" value="{% trans "Validate" %}"/> +</form> +</div> +</body> +</html> diff --git a/ishtar_common/templatetags/window_tables.py b/ishtar_common/templatetags/window_tables.py index cdd681b52..6710672e1 100644 --- a/ishtar_common/templatetags/window_tables.py +++ b/ishtar_common/templatetags/window_tables.py @@ -27,25 +27,28 @@ def table_document(caption, data):  ASSOCIATED_MODELS = {}  ASSOCIATED_MODELS['files'] = (File, 'get-file', '') -ASSOCIATED_MODELS['operation_docs'] = (OperationSource, -                                       'get-operationsource', '') +ASSOCIATED_MODELS['operation_docs'] = ( +    OperationSource, 'get-operationsource', 'get-operationsource-full')  ASSOCIATED_MODELS['operations'] = (Operation, 'get-operation', '')  ASSOCIATED_MODELS['context_records'] = (ContextRecord, 'get-contextrecord',                                          'get-contextrecord-full')  ASSOCIATED_MODELS['context_records_for_ope'] = (      ContextRecord,      'get-contextrecord-for-ope', 'get-contextrecord-full') -ASSOCIATED_MODELS['context_records_docs'] = (ContextRecordSource, -                                             'get-contextrecordsource', '') +ASSOCIATED_MODELS['context_records_docs'] = ( +    ContextRecordSource, +    'get-contextrecordsource', 'get-contextrecordsource-full')  ASSOCIATED_MODELS['finds'] = (Find, 'get-find', 'get-find-full')  ASSOCIATED_MODELS['finds_for_ope'] = (      Find, 'get-find-for-ope', 'get-find-full') -ASSOCIATED_MODELS['finds_docs'] = (FindSource, 'get-findsource', '') +ASSOCIATED_MODELS['finds_docs'] = ( +    FindSource, 'get-findsource', 'get-findsource-full')  @register.simple_tag(takes_context=True) -def dynamic_table_document(context, caption, associated_model, key, value, -                           table_cols='TABLE_COLS', output='html'): +def dynamic_table_document( +        context, caption, associated_model, key, value, +        table_cols='TABLE_COLS', output='html', large=False):      if not table_cols:          table_cols = 'TABLE_COLS'      model, url, url_full = ASSOCIATED_MODELS[associated_model] @@ -68,6 +71,7 @@ def dynamic_table_document(context, caption, associated_model, key, value,              'no_result': unicode(_("No results")),              'loading': unicode(_("Loading...")),              'encoding': settings.ENCODING or 'utf-8', +            'large': large          })          return t.render(context)      else: @@ -103,3 +107,12 @@ def dynamic_table_document(context, caption, associated_model, key, value,              'data': data          })          return t.render(context) + + +@register.simple_tag(takes_context=True) +def dynamic_table_document_large( +        context, caption, associated_model, key, +        value, table_cols='TABLE_COLS', output='html'): +    return dynamic_table_document( +        context, caption, associated_model, key, +        value, table_cols, output, large=True) diff --git a/ishtar_common/views.py b/ishtar_common/views.py index f4a8d02e2..59cfe6321 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016  É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 @@ -350,7 +350,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  if specific_perms and perm not in specific_perms:                      continue                  cperm = model._meta.app_label + '.' + perm -                if cperm in request.user.get_all_permissions() \ +                if request.user.has_perm(cperm)\ +                        or cperm in request.user.get_all_permissions() \                          or (request.user.is_authenticated()                              and request.user.ishtaruser.has_right(                                  perm, session=request.session)): @@ -416,7 +417,12 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          if 'submited' not in request_items:              if default_name in request.session and \                 request.session[default_name]: -                dct = {"pk": request.session[default_name]} +                value = request.session[default_name] +                if 'basket-' in value: +                    dct = {"basket__pk": +                           request.session[default_name].split('-')[-1]} +                else: +                    dct = {"pk": request.session[default_name]}              elif not dct:                  for name in relative_session_names.keys():                      if name in request.session and request.session[name]: diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index b8b104a61..6d9600d0c 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -513,13 +513,15 @@ class JQueryJqGrid(forms.RadioSelect):      def __init__(self, source, form, associated_model, attrs={},                   table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], -                 new=False, new_message="", source_full=None): +                 new=False, new_message="", source_full=None, +                 multiple_select=False):          self.source = source          self.form = form          self.attrs = attrs          self.associated_model = associated_model          self.table_cols = table_cols          self.multiple = multiple +        self.multiple_select = multiple_select          self.multiple_cols = multiple_cols          self.new, self.new_message = new, new_message          self.source_full = source_full @@ -604,6 +606,7 @@ class JQueryJqGrid(forms.RadioSelect):                      'remove': unicode(_(u"Remove")),                      'sname': name.replace('-', ''),                      'multiple': self.multiple, +                    'multiple_select': self.multiple_select,                      'multi_cols': ",".join((u'"%d"' % col                                             for col in self.multiple_cols))})          t = loader.get_template('blocks/JQueryJqGrid.html') diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index e974942b7..49abe606f 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -510,7 +510,7 @@ class Wizard(NamedUrlWizardView):              adds = {}              # manage attributes relations              if hasattr(self.model, 'ATTRS_EQUIV'): -                for k in other_objs: +                for k in other_objs.keys():                      if k in self.model.ATTRS_EQUIV:                          new_k = self.model.ATTRS_EQUIV[k]                          if new_k in other_objs:  | 
