diff options
author | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-20 21:52:43 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-20 21:52:43 +0200 |
commit | 5b8c7201eefa8b404afb0cb89b389fd3e8f92899 (patch) | |
tree | 1f1887c1153c40cd4323c482856e5f281ec1dc97 | |
parent | 111fb54c79daf2a1bcfe624f103f02da650e8741 (diff) | |
download | Ishtar-5b8c7201eefa8b404afb0cb89b389fd3e8f92899.tar.bz2 Ishtar-5b8c7201eefa8b404afb0cb89b389fd3e8f92899.zip |
Djangoization - Major refactoring (step 6)
Work on wizard, views and forms to dispatch logic in a more
relevant way.
25 files changed, 1269 insertions, 1923 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 816782bd8..983dbb869 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-2011 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -31,86 +31,16 @@ from django.utils.translation import ugettext_lazy as _ from ishtar import settings +from ishtar_common.models import valid_id +from archaeological_operations.models import Period, Parcel, Operation import models import widgets -from forms import Wizard, FinalForm, FormSet, SearchWizard, DeletionWizard, \ +from forms import FinalForm, FormSet, \ formset_factory, get_now, reverse_lazy, get_form_selection -from forms_common import get_town_field, SourceForm, SourceWizard, \ +from forms_common import get_town_field, SourceForm, \ SourceSelect, AuthorFormset from forms_operations import OperationSelect -class RecordWizard(Wizard): - model = models.ContextRecord - edit = False - - def get_current_operation(self, request, storage): - step = storage.get_current_step() - if not step: - return - if step.endswith('_creation'): # an operation has been selected - main_form_key = 'selec-' + self.url_name - try: - idx = int(self.session_get_value(request, storage, - main_form_key, 'operation_id')) - current_ope = models.Operation.objects.get(pk=idx) - return current_ope - except(TypeError, ValueError, ObjectDoesNotExist): - pass - current_cr = self.get_current_object(request, storage) - if current_cr: - return current_cr.parcel.operation - - def get_template_context(self, request, storage, form=None): - """ - Get the operation "reminder" on top of wizard forms - """ - context = super(RecordWizard, self).get_template_context(request, - storage, form) - operation = self.get_current_operation(request, storage) - if not operation: - return context - items = [] - if hasattr(operation, 'code_patriarche') and operation.code_patriarche: - items.append(unicode(operation.code_patriarche)) - items.append("-".join((unicode(operation.year), - unicode(operation.operation_code)))) - context['reminder'] = _("Current operation: ") + " - ".join(items) - return context - - def get_form(self, request, storage, step=None, data=None, files=None): - """ - Get associated operation - """ - if data: - data = data.copy() - else: - data = {} - if not step: - step = self.determine_step(request, storage) - form = self.get_form_list(request, storage)[step] - - general_form_key = 'general-' + self.url_name - if step.startswith('general-'): - if step.endswith('_creation'): # an operation has been selected - main_form_key = 'selec-' + self.url_name - try: - idx = int(self.session_get_value(request, storage, - main_form_key, 'operation_id')) - current_obj = models.Operation.objects.get(pk=idx) - data['operation'] = current_obj - except(TypeError, ValueError, ObjectDoesNotExist): - pass - else: - current_object = self.get_current_object(request, storage) - data['context_record'] = current_object - form = super(RecordWizard, self).get_form(request, storage, step, data, - files) - return form - -class RecordModifWizard(RecordWizard): - modification = True - model = models.ContextRecord - class RecordSelect(forms.Form): parcel__town = get_town_field() operation__year = forms.IntegerField(label=_(u"Year")) @@ -118,10 +48,8 @@ class RecordSelect(forms.Form): unit = forms.ChoiceField(label=_(u"Unit type"), choices=[]) def __init__(self, *args, **kwargs): super(RecordSelect, self).__init__(*args, **kwargs) - self.fields['datings__period'].choices = \ - models.Period.get_types() - self.fields['datings__period'].help_text = \ - models.Period.get_help() + self.fields['datings__period'].choices = Period.get_types() + self.fields['datings__period'].help_text = Period.get_help() self.fields['unit'].choices = models.Unit.get_types() self.fields['unit'].help_text = models.Unit.get_help() @@ -133,7 +61,7 @@ class RecordFormSelection(forms.Form): widget=widgets.JQueryJqGrid(reverse_lazy('get-contextrecord'), RecordSelect(), models.ContextRecord, source_full=reverse_lazy('get-contextrecord-full')), - validators=[models.valid_id(models.ContextRecord)]) + validators=[valid_id(models.ContextRecord)]) def clean(self): cleaned_data = self.cleaned_data @@ -145,7 +73,7 @@ class RecordFormSelection(forms.Form): class RecordFormGeneral(forms.Form): form_label = _("General") - associated_models = {'parcel':models.Parcel, 'unit':models.Unit} + associated_models = {'parcel':Parcel, 'unit':models.Unit} pk = forms.IntegerField(required=False, widget=forms.HiddenInput) operation_id = forms.IntegerField(widget=forms.HiddenInput) parcel = forms.ChoiceField(label=_("Parcel"), choices=[]) @@ -210,8 +138,7 @@ class DatingForm(forms.Form): associated_models = {'dating_type':models.DatingType, 'quality':models.DatingQuality, 'period':models.Period} - period = forms.ChoiceField(label=_("Period"), - choices=models.Period.get_types()) + period = forms.ChoiceField(label=_("Period"), choices=Period.get_types()) start_date = forms.IntegerField(label=_(u"Start date"), required=False) end_date = forms.IntegerField(label=_(u"End date"), required=False) quality = forms.ChoiceField(label=_("Quality"), required=False, @@ -259,67 +186,25 @@ class RecordFormInterpretation(forms.Form): self.fields['identification'].help_text = \ models.IdentificationType.get_help() -record_search_wizard = SearchWizard([ - ('general-record_search', RecordFormSelection)], - url_name='record_search',) - OperationRecordFormSelection = get_form_selection( 'OperationRecordFormSelection', _(u"Operation search"), 'operation_id', - models.Operation, OperationSelect, 'get-operation', + Operation, OperationSelect, 'get-operation', _(u"You should select an operation.")) -record_creation_wizard = RecordWizard([ - ('selec-record_creation', OperationRecordFormSelection), - ('general-record_creation', RecordFormGeneral), - ('datings-record_creation', DatingFormSet), - ('interpretation-record_creation', RecordFormInterpretation), - ('final-record_creation', FinalForm)], - url_name='record_creation',) - -record_modification_wizard = RecordModifWizard([ - ('selec-record_modification', RecordFormSelection), - ('general-record_modification', RecordFormGeneral), - ('datings-record_modification', DatingFormSet), - ('interpretation-record_modification', RecordFormInterpretation), - ('final-record_modification', FinalForm)], - url_name='record_modification',) - -class RecordDeletionWizard(DeletionWizard): - model = models.ContextRecord - fields = ['label', 'parcel', 'description', 'length', 'width', 'thickness', - 'depth', 'location', 'datings', 'units', 'has_furniture', - 'filling', 'interpretation', 'taq', 'taq_estimated', 'tpq', - 'tpq_estimated'] - class RecordDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this context record?") -record_deletion_wizard = RecordDeletionWizard([ - ('selec-record_deletion', RecordFormSelection), - ('final-record_deletion', RecordDeletionForm)], - url_name='record_deletion',) - ######################################### # Source management for context records # ######################################### -class RecordSourceWizard(SourceWizard): - model = models.ContextRecordSource - SourceRecordFormSelection = get_form_selection( 'SourceRecordFormSelection', _(u"Context record search"), 'context_record', models.ContextRecord, RecordSelect, 'get-contextrecord', _(u"You should select a context record.")) -record_source_creation_wizard = RecordSourceWizard([ - ('selec-record_source_creation', SourceRecordFormSelection), - ('source-record_source_creation', SourceForm), - ('authors-record_source_creation', AuthorFormset), - ('final-record_source_creation', FinalForm)], - url_name='record_source_creation',) - class RecordSourceSelect(SourceSelect): context_record__parcel__town = get_town_field( label=_(u"Town of the operation")) @@ -333,9 +218,9 @@ class RecordSourceSelect(SourceSelect): def __init__(self, *args, **kwargs): super(RecordSourceSelect, self).__init__(*args, **kwargs) self.fields['context_record__datings__period'].choices = \ - models.Period.get_types() + Period.get_types() self.fields['context_record__datings__period'].help_text = \ - models.Period.get_help() + Period.get_help() self.fields['context_record__unit'].choices = models.Unit.get_types() self.fields['context_record__unit'].help_text = models.Unit.get_help() @@ -345,18 +230,3 @@ RecordSourceFormSelection = get_form_selection( models.ContextRecordSource, RecordSourceSelect, 'get-contextrecordsource', _(u"You should select a document.")) -record_source_modification_wizard = RecordSourceWizard([ - ('selec-record_source_modification', RecordSourceFormSelection), - ('source-record_source_modification', SourceForm), - ('authors-record_source_modification', AuthorFormset), - ('final-record_source_modification', FinalForm)], - url_name='record_source_modification',) - -class RecordSourceDeletionWizard(DeletionWizard): - model = models.ContextRecordSource - fields = ['context_record', 'title', 'source_type', 'authors',] - -record_source_deletion_wizard = RecordSourceDeletionWizard([ - ('selec-record_source_deletion', RecordSourceFormSelection), - ('final-record_source_deletion', RecordDeletionForm)], - url_name='record_source_deletion',) diff --git a/archaeological_context_records/urls.py b/archaeological_context_records/urls.py index c42ae2b02..1cbf03f12 100644 --- a/archaeological_context_records/urls.py +++ b/archaeological_context_records/urls.py @@ -19,27 +19,27 @@ from django.conf.urls.defaults import * """ -import forms +import views # forms urlpatterns = patterns('', # Context records url(r'record_search/(?P<step>.+)$', - forms.record_search_wizard, name='record_search'), + views.record_search_wizard, name='record_search'), url(r'record_creation/(?P<step>.+)$', - forms.record_creation_wizard, name='record_creation'), + views.record_creation_wizard, name='record_creation'), url(r'record_modification/(?P<step>.+)$', - forms.record_modification_wizard, name='record_modification'), + views.record_modification_wizard, name='record_modification'), url(r'record_deletion/(?P<step>.+)$', - forms.record_deletion_wizard, name='record_deletion'), + views.record_deletion_wizard, name='record_deletion'), url(r'record_source_creation/(?P<step>.+)$', - forms.record_source_creation_wizard, + views.record_source_creation_wizard, name='record_source_creation'), url(r'record_source_modification/(?P<step>.+)$', - forms.record_source_modification_wizard, + views.record_source_modification_wizard, name='record_source_modification'), url(r'record_source_deletion/(?P<step>.+)$', - forms.record_source_deletion_wizard, + views.record_source_deletion_wizard, name='record_source_deletion'), ) diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index 89a45482b..b1f8ca772 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -18,6 +18,9 @@ # See the file COPYING for details. from ishtar_common.views import get_item, show_item, revert_item +from ishtar_common.wizards import SearchWizard +from wizards import * +from forms import * import models show_contextrecord = show_item(models.ContextRecord, 'contextrecord') @@ -34,3 +37,48 @@ get_contextrecordsource = get_item(models.ContextRecordSource, 'context_record__datings__period':'context_record__datings__period__pk', 'context_record__unit':'context_record__unit__pk', }) + +record_search_wizard = SearchWizard.as_view([ + ('general-record_search', RecordFormSelection)], + url_name='record_search',) + +record_creation_wizard = RecordWizard.as_view([ + ('selec-record_creation', OperationRecordFormSelection), + ('general-record_creation', RecordFormGeneral), + ('datings-record_creation', DatingFormSet), + ('interpretation-record_creation', RecordFormInterpretation), + ('final-record_creation', FinalForm)], + url_name='record_creation',) + +record_modification_wizard = RecordModifWizard.as_view([ + ('selec-record_modification', RecordFormSelection), + ('general-record_modification', RecordFormGeneral), + ('datings-record_modification', DatingFormSet), + ('interpretation-record_modification', RecordFormInterpretation), + ('final-record_modification', FinalForm)], + url_name='record_modification',) + +record_deletion_wizard = RecordDeletionWizard.as_view([ + ('selec-record_deletion', RecordFormSelection), + ('final-record_deletion', RecordDeletionForm)], + url_name='record_deletion',) + +record_source_creation_wizard = RecordSourceWizard.as_view([ + ('selec-record_source_creation', SourceRecordFormSelection), + ('source-record_source_creation', SourceForm), + ('authors-record_source_creation', AuthorFormset), + ('final-record_source_creation', FinalForm)], + url_name='record_source_creation',) + +record_source_modification_wizard = RecordSourceWizard.as_view([ + ('selec-record_source_modification', RecordSourceFormSelection), + ('source-record_source_modification', SourceForm), + ('authors-record_source_modification', AuthorFormset), + ('final-record_source_modification', FinalForm)], + url_name='record_source_modification',) + +record_source_deletion_wizard = RecordSourceDeletionWizard.as_view([ + ('selec-record_source_deletion', RecordSourceFormSelection), + ('final-record_source_deletion', RecordDeletionForm)], + url_name='record_source_deletion',) + diff --git a/archaeological_context_records/wizards.py b/archaeological_context_records/wizards.py new file mode 100644 index 000000000..b14272e16 --- /dev/null +++ b/archaeological_context_records/wizards.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.utils.translation import ugettext_lazy as _ + +from ishtar_common.wizards import Wizard, DeletionWizard, SourceWizard +import models + +class RecordWizard(Wizard): + model = models.ContextRecord + edit = False + + def get_current_operation(self, request, storage): + step = storage.get_current_step() + if not step: + return + if step.endswith('_creation'): # an operation has been selected + main_form_key = 'selec-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'operation_id')) + current_ope = models.Operation.objects.get(pk=idx) + return current_ope + except(TypeError, ValueError, ObjectDoesNotExist): + pass + current_cr = self.get_current_object(request, storage) + if current_cr: + return current_cr.parcel.operation + + def get_template_context(self, request, storage, form=None): + """ + Get the operation "reminder" on top of wizard forms + """ + context = super(RecordWizard, self).get_template_context(request, + storage, form) + operation = self.get_current_operation(request, storage) + if not operation: + return context + items = [] + if hasattr(operation, 'code_patriarche') and operation.code_patriarche: + items.append(unicode(operation.code_patriarche)) + items.append("-".join((unicode(operation.year), + unicode(operation.operation_code)))) + context['reminder'] = _("Current operation: ") + " - ".join(items) + return context + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Get associated operation + """ + if data: + data = data.copy() + else: + data = {} + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + + general_form_key = 'general-' + self.url_name + if step.startswith('general-'): + if step.endswith('_creation'): # an operation has been selected + main_form_key = 'selec-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'operation_id')) + current_obj = models.Operation.objects.get(pk=idx) + data['operation'] = current_obj + except(TypeError, ValueError, ObjectDoesNotExist): + pass + else: + current_object = self.get_current_object(request, storage) + data['context_record'] = current_object + form = super(RecordWizard, self).get_form(request, storage, step, data, + files) + return form + +class RecordModifWizard(RecordWizard): + modification = True + model = models.ContextRecord + +class RecordDeletionWizard(DeletionWizard): + model = models.ContextRecord + fields = ['label', 'parcel', 'description', 'length', 'width', 'thickness', + 'depth', 'location', 'datings', 'units', 'has_furniture', + 'filling', 'interpretation', 'taq', 'taq_estimated', 'tpq', + 'tpq_estimated'] + +class RecordSourceWizard(SourceWizard): + model = models.ContextRecordSource + +class RecordSourceDeletionWizard(DeletionWizard): + model = models.ContextRecordSource + fields = ['context_record', 'title', 'source_type', 'authors',] + diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 368c57843..564d0c6fc 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -31,104 +31,17 @@ from django.shortcuts import render_to_response from django.template import RequestContext from django.utils.translation import ugettext_lazy as _ -from ishtar_common.models import Town +from ishtar_common.models import Person, PersonType, Town, Organization, \ + OrganizationType, valid_id, is_unique +from archaeological_operations.models import ActType, AdministrativeAct import models -from ishtar_common.views import Wizard -from ishtar_common.forms import FinalForm, FormSet, ClosingWizard, \ - ClosingDateFormSelection, SearchWizard, formset_factory, get_now, \ - reverse_lazy -from ishtar_common.forms_common import TownFormset, ParcelFormSet, \ - get_town_field, get_person_field -from archaeological_operations.forms import OperationAdministrativeActWizard, \ - AdministrativeActOpeForm, AdministrativeActOpeFormSelection, \ - AdministrativeActDeletionWizard, FinalAdministrativeActDeleteForm, \ - is_preventive +from ishtar_common.forms import FinalForm, FormSet, ClosingDateFormSelection, \ + formset_factory, get_now, reverse_lazy +from ishtar_common.forms_common import get_town_field, get_person_field +from archaeological_operations.forms import AdministrativeActOpeForm, \ + AdministrativeActOpeFormSelection, FinalAdministrativeActDeleteForm from ishtar_common import widgets -class FileWizard(Wizard): - model = models.File - object_parcel_type = 'associated_file' - - def get_form(self, request, storage, step=None, data=None, files=None): - """ - Manage towns - """ - if data: - data = data.copy() - else: - data = {} - # manage the dynamic choice of towns - if not step: - step = self.determine_step(request, storage) - form = self.get_form_list(request, storage)[step] - town_form_key = 'towns-' + self.url_name - if step.startswith('parcels-') and hasattr(form, 'management_form') \ - and self.session_has_key(request, storage, town_form_key): - towns = [] - qdict = request.session[storage.prefix]['step_data'][town_form_key] - for k in qdict.keys(): - if k.endswith("town") and qdict[k]: - try: - town = Town.objects.get(pk=int(qdict[k])) - towns.append((town.pk, unicode(town))) - except (ObjectDoesNotExist, ValueError): - pass - data['TOWNS'] = sorted(towns, key=lambda x:x[1]) - form = super(FileWizard, self).get_form(request, storage, step, data, - files) - return form - - def get_extra_model(self, dct, request, storage, form_list): - dct = super(FileWizard, self).get_extra_model(dct, request, storage, - form_list) - if not dct['numeric_reference']: - current_ref = models.File.objects.filter(year=dct['year'] - ).aggregate(Max('numeric_reference'))["numeric_reference__max"] - dct['numeric_reference'] = current_ref and current_ref + 1 or 1 - return dct - - def done(self, request, storage, form_list, **kwargs): - ''' - Save parcels - ''' - r = super(FileWizard, self).done(request, storage, form_list, - return_object=True, **kwargs) - if type(r) not in (list, tuple) or len(r) != 2: - return r - obj, res = r - obj.parcels.clear() - for form in form_list: - if not hasattr(form, 'prefix') \ - or not form.prefix.startswith('parcels-') \ - or not hasattr(form, 'forms'): - continue - for frm in form.forms: - if not frm.is_valid(): - continue - dct = frm.cleaned_data.copy() - if 'parcel' in dct: - try: - parcel = models.Parcel.objects.get(pk=dct['parcel']) - setattr(parcel, self.object_parcel_type, obj) - parcel.save() - except (ValueError, ObjectDoesNotExist): - continue - continue - try: - dct['town'] = models.Town.objects.get(pk=int(dct['town'])) - except (ValueError, ObjectDoesNotExist): - continue - dct['associated_file'], dct['operation'] = None, None - dct[self.object_parcel_type] = obj - if 'DELETE' in dct: - dct.pop('DELETE') - parcel = models.Parcel.objects.filter(**dct).count() - if not parcel: - dct['history_modifier'] = request.user - parcel = models.Parcel(**dct) - parcel.save() - return res - class FileSelect(forms.Form): towns = get_town_field() in_charge = get_person_field(label=_(u"Person in charge"), @@ -150,7 +63,7 @@ class FileFormSelection(forms.Form): pk = forms.IntegerField(label="", required=False, widget=widgets.JQueryJqGrid(reverse_lazy('get-file'), FileSelect(), models.File, source_full=reverse_lazy('get-file-full')), - validators=[models.valid_id(models.File)]) + validators=[valid_id(models.File)]) def clean(self): cleaned_data = self.cleaned_data @@ -160,14 +73,14 @@ class FileFormSelection(forms.Form): class FileFormGeneral(forms.Form): form_label = _("General") - associated_models = {'in_charge':models.Person, + associated_models = {'in_charge':Person, 'related_file':models.File, 'file_type':models.FileType} in_charge = forms.IntegerField(label=_("Person in charge"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', - args=[models.PersonType.objects.get(txt_idx='sra_agent').pk]), - associated_model=models.Person, new=True), - validators=[models.valid_id(models.Person)]) + args=[PersonType.objects.get(txt_idx='sra_agent').pk]), + associated_model=Person, new=True), + validators=[valid_id(Person)]) year = forms.IntegerField(label=_("Year"), initial=lambda:datetime.datetime.now().year, validators=[validators.MinValueValidator(1900), @@ -176,7 +89,7 @@ class FileFormGeneral(forms.Form): widget=forms.HiddenInput, required=False) internal_reference = forms.CharField(label=_(u"Internal reference"), max_length=60, - validators=[models.is_unique(models.File, 'internal_reference')]) + validators=[is_unique(models.File, 'internal_reference')]) creation_date = forms.DateField(label=_(u"Creation date"), initial=get_now, widget=widgets.JQueryDate) file_type = forms.ChoiceField(label=_("File type"), @@ -184,7 +97,7 @@ class FileFormGeneral(forms.Form): related_file = forms.IntegerField(label=_("Related file"), required=False, widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), associated_model=models.File), - validators=[models.valid_id(models.File)]) + validators=[valid_id(models.File)]) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) @@ -198,7 +111,7 @@ class FileFormGeneralRO(FileFormGeneral): class FileFormAddress(forms.Form): form_label = _(u"Address") - associated_models = {'town':models.Town} + associated_models = {'town':Town} total_surface = forms.IntegerField(required=False, widget=widgets.AreaWidget, label=_(u"Total surface (m²)"), @@ -212,23 +125,23 @@ class FileFormAddress(forms.Form): class FileFormPreventive(forms.Form): form_label = _(u"Preventive informations") - associated_models = {'general_contractor':models.Person, + associated_models = {'general_contractor':Person, 'saisine_type':models.SaisineType, 'permit_type':models.PermitType, - 'town_planning_service':models.Organization} + 'town_planning_service':Organization} general_contractor = forms.IntegerField(label=_(u"General contractor"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', - args=[models.PersonType.objects.get(txt_idx='general_contractor').pk]), - associated_model=models.Person, new=True), - validators=[models.valid_id(models.Person)]) + args=[PersonType.objects.get(txt_idx='general_contractor').pk]), + associated_model=Person, new=True), + validators=[valid_id(Person)]) town_planning_service = forms.IntegerField(required=False, label=_(u"Town planning service"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization', - args=[models.OrganizationType.objects.get(txt_idx='planning_service').pk]), - associated_model=models.Organization, new=True), - validators=[models.valid_id(models.Organization)]) + args=[OrganizationType.objects.get(txt_idx='planning_service').pk]), + associated_model=Organization, new=True), + validators=[valid_id(Organization)]) permit_type = forms.ChoiceField(label=_(u"Permit type"), required=False, choices=models.PermitType.get_types()) permit_reference = forms.CharField(label=_(u"Permit reference"), @@ -247,143 +160,40 @@ class FileFormPreventive(forms.Form): self.fields['saisine_type'].choices = models.SaisineType.get_types() self.fields['saisine_type'].help_text = models.SaisineType.get_help() -file_search_wizard = SearchWizard([('general-file_search', FileFormSelection)], - url_name='file_search',) - -file_creation_wizard = FileWizard([ - ('general-file_creation', FileFormGeneral), - ('address-file_creation', FileFormAddress), - ('towns-file_creation', TownFormset), - ('parcels-file_creation', ParcelFormSet), - ('preventive-file_creation', FileFormPreventive), - ('final-file_creation', FinalForm)], - condition_list={ -'preventive-file_creation':is_preventive('general-file_creation', - models.FileType, type_key='file_type') - }, - url_name='file_creation',) - -class FileModificationWizard(FileWizard): - modification = True - -file_modification_wizard = FileModificationWizard([ - ('selec-file_modification', FileFormSelection), - ('general-file_modification', FileFormGeneralRO), - ('adress-file_modification', FileFormAddress), - ('towns-file_modification', TownFormset), - ('parcels-file_modification', ParcelFormSet), - ('preventive-file_modification', FileFormPreventive), - ('final-file_modification', FinalForm)], - condition_list={ -'preventive-file_modification':is_preventive('general-file_modification', - models.FileType, type_key='file_type') - }, - url_name='file_modification',) - -class FileClosingWizard(ClosingWizard): - model = models.File - fields = ['year', 'numeric_reference', 'internal_reference', - 'file_type', 'in_charge', 'general_contractor', 'creation_date', - 'reception_date', 'total_surface', 'total_developed_surface', - 'address', 'address_complement', 'postal_code', 'comment'] - if settings.COUNTRY == 'fr': - fields += ['saisine_type', 'reference_number'] - fields += ['towns'] class FinalFileClosingForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to close this archaeological file?") -file_closing_wizard = FileClosingWizard([ - ('selec-file_closing', FileFormSelection), - ('date-file_closing', ClosingDateFormSelection), - ('final-file_closing', FinalFileClosingForm)], - url_name='file_closing',) - -class FileDeletionWizard(FileClosingWizard): - def get_formated_datas(self, forms): - datas = super(FileDeletionWizard, self).get_formated_datas(forms) - datas.append((_("Associated operations"), [])) - for operation in models.Operation.objects.filter( - associated_file=self.current_obj).all(): - if operation.end_date: - datas[-1][1].append(('', unicode(operation))) - return datas - - def done(self, request, storage, form_list, **kwargs): - obj = self.get_current_object(request, storage) - for operation in models.Operation.objects.filter( - associated_file=obj).all(): - operation.delete() - obj.delete() - return render_to_response('wizard_done.html', {}, - context_instance=RequestContext(request)) - class FinalFileDeleteForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this archaelogical file ?") -file_deletion_wizard = FileDeletionWizard([ - ('selec-file_deletion', FileFormSelection), - ('final-file_deletion', FinalFileDeleteForm)], - url_name='file_deletion',) - -class FileAdministrativeActWizard(OperationAdministrativeActWizard): - model = models.File - -class FileEditAdministrativeActWizard(FileAdministrativeActWizard): - model = models.AdministrativeAct - edit = True - def get_associated_item(self, request, storage, dct): - return self.get_current_object(request, storage).associated_file - class AdministrativeActFileSelect(forms.Form): associated_file__towns = get_town_field() act_type = forms.ChoiceField(label=_("Act type"), choices=[]) def __init__(self, *args, **kwargs): super(AdministrativeActFileSelect, self).__init__(*args, **kwargs) - self.fields['act_type'].choices = models.ActType.get_types( + self.fields['act_type'].choices = ActType.get_types( dct={'intented_to':'F'}) - self.fields['act_type'].help_text = models.ActType.get_help( + self.fields['act_type'].help_text = ActType.get_help( dct={'intented_to':'F'}) class AdministrativeActFileFormSelection(AdministrativeActOpeFormSelection): pk = forms.IntegerField(label="", required=False, widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactfile'), - AdministrativeActFileSelect(), models.AdministrativeAct, + AdministrativeActFileSelect(), AdministrativeAct, table_cols='TABLE_COLS_FILE'), - validators=[models.valid_id(models.AdministrativeAct)]) + validators=[valid_id(AdministrativeAct)]) class AdministrativeActFileForm(AdministrativeActOpeForm): act_type = forms.ChoiceField(label=_(u"Act type"), choices=[]) def __init__(self, *args, **kwargs): super(AdministrativeActFileForm, self).__init__(*args, **kwargs) - self.fields['act_type'].choices = models.ActType.get_types( + self.fields['act_type'].choices = ActType.get_types( dct={'intented_to':'F'}) - self.fields['act_type'].help_text = models.ActType.get_help( + self.fields['act_type'].help_text = ActType.get_help( dct={'intented_to':'F'}) - -file_administrativeactfile_wizard = FileAdministrativeActWizard([ - ('selec-file_administrativeactfile', FileFormSelection), - ('administrativeact-file_administrativeactfile', AdministrativeActFileForm), - ('final-file_administrativeactfile', FinalForm)], - url_name='file_administrativeactfile',) - -file_administrativeactfile_modification_wizard = FileEditAdministrativeActWizard([ - ('selec-file_administrativeactfile_modification', - AdministrativeActFileFormSelection), - ('administrativeact-file_administrativeactfile_modification', - AdministrativeActFileForm), - ('final-file_administrativeactfile_modification', FinalForm)], - url_name='file_administrativeactfile_modification',) - -file_administrativeactfile_deletion_wizard = AdministrativeActDeletionWizard([ - ('selec-file_administrativeactfile_deletion', - AdministrativeActFileFormSelection), - ('final-file_administrativeactfile_deletion', - FinalAdministrativeActDeleteForm)], - url_name='file_administrativeactfile_deletion',) - diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py index e32ab8294..a64a8b2b1 100644 --- a/archaeological_files/urls.py +++ b/archaeological_files/urls.py @@ -19,29 +19,28 @@ from django.conf.urls.defaults import * -""" -import forms +import views -# forms +# forms: urlpatterns = patterns('', - url(r'file_search/(?P<step>.+)$', - forms.file_search_wizard, name='file_search'), - url(r'file_creation/(?P<step>.+)$', - forms.file_creation_wizard, name='file_creation'), - url(r'file_modification/(?P<step>.+)$', - forms.file_modification_wizard, name='file_modification'), - url(r'file_closing/(?P<step>.+)$', - forms.file_closing_wizard, name='file_closing'), - url(r'file_deletion/(?P<step>.+)$', - forms.file_deletion_wizard, name='file_deletion'), - url(r'file_administrativeactfile/(?P<step>.+)$', - forms.file_administrativeactfile_wizard, + url(r'file_search/(?P<step>.+)?$', + views.file_search_wizard, name='file_search'), + url(r'file_creation/(?P<step>.+)?$', + views.file_creation_wizard, name='file_creation'), + url(r'file_modification/(?P<step>.+)?$', + views.file_modification_wizard, name='file_modification'), + url(r'file_closing/(?P<step>.+)?$', + views.file_closing_wizard, name='file_closing'), + url(r'file_deletion/(?P<step>.+)?$', + views.file_deletion_wizard, name='file_deletion'), + url(r'file_administrativeactfile/(?P<step>.+)?$', + views.file_administrativeactfile_wizard, name='file_administrativeactfile'), - url(r'file_administrativeactfile_modification/(?P<step>.+)$', - forms.file_administrativeactfile_modification_wizard, + url(r'file_administrativeactfile_modification/(?P<step>.+)?$', + views.file_administrativeactfile_modification_wizard, name='file_administrativeactfile_modification'), - url(r'file_administrativeactfile_deletion/(?P<step>.+)$', - forms.file_administrativeactfile_deletion_wizard, + url(r'file_administrativeactfile_deletion/(?P<step>.+)?$', + views.file_administrativeactfile_deletion_wizard, name='file_administrativeactfile_deletion'), ) @@ -61,4 +60,3 @@ urlpatterns += patterns('archaeological_files.views', url(r'revert-file/(?P<pk>.+)/(?P<date>.+)$', 'revert_file', name='revert-file'), ) -""" diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 02332b629..0f71b24d8 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -24,7 +24,14 @@ from django.http import HttpResponse from django.shortcuts import render_to_response from ishtar_common.views import get_item, show_item, revert_item +from archaeological_operations.models import AdministrativeAct import models +from ishtar_common.wizards import SearchWizard +from archaeological_operations.wizards import is_preventive +from wizards import * +from ishtar_common.forms_common import TownFormset +from archaeological_operations.forms import ParcelFormSet +from forms import * def autocomplete_file(request): person_types = request.user.ishtaruser.person.person_type @@ -56,6 +63,12 @@ get_file = get_item(models.File, 'get_file', 'file') show_file = show_item(models.File, 'file') revert_file = revert_item(models.File) +get_administrativeactfile = get_item(AdministrativeAct, + 'get_administrativeactfile', 'administrativeactfile', + extra_request_keys={'associated_file__towns':'associated_file__towns__pk', + 'operation__towns':'operation__towns__pk', + 'act_type__intented_to':'act_type__intented_to'}) + def dashboard_file(request, dct, obj_id=None, *args, **kwargs): """ Main dashboard @@ -64,3 +77,69 @@ def dashboard_file(request, dct, obj_id=None, *args, **kwargs): return render_to_response('dashboard_file.html', dct, context_instance=RequestContext(request)) +file_search_wizard = SearchWizard.as_view( + [('general-file_search', FileFormSelection)], + url_name='file_search',) +file_creation_wizard = FileWizard.as_view([ + ('general-file_creation', FileFormGeneral), + ('address-file_creation', FileFormAddress), + ('towns-file_creation', TownFormset), + ('parcels-file_creation', ParcelFormSet), + ('preventive-file_creation', FileFormPreventive), + ('final-file_creation', FinalForm)], + condition_dict={'preventive-file_creation':is_preventive( + 'general-file_creation', + models.FileType, type_key='file_type') + }, + url_name='file_creation',) + +file_modification_wizard = FileModificationWizard.as_view([ + ('selec-file_modification', FileFormSelection), + ('general-file_modification', FileFormGeneralRO), + ('adress-file_modification', FileFormAddress), + ('towns-file_modification', TownFormset), + ('parcels-file_modification', ParcelFormSet), + ('preventive-file_modification', FileFormPreventive), + ('final-file_modification', FinalForm)], + condition_dict={'preventive-file_modification':is_preventive( + 'general-file_modification', + models.FileType, type_key='file_type') + }, + url_name='file_modification',) + +file_closing_wizard = FileClosingWizard.as_view([ + ('selec-file_closing', FileFormSelection), + ('date-file_closing', ClosingDateFormSelection), + ('final-file_closing', FinalFileClosingForm)], + url_name='file_closing',) + + +file_deletion_wizard = FileDeletionWizard.as_view([ + ('selec-file_deletion', FileFormSelection), + ('final-file_deletion', FinalFileDeleteForm)], + url_name='file_deletion',) + +file_administrativeactfile_wizard = FileAdministrativeActWizard.as_view([ + ('selec-file_administrativeactfile', FileFormSelection), + ('administrativeact-file_administrativeactfile', + AdministrativeActFileForm), + ('final-file_administrativeactfile', FinalForm)], + url_name='file_administrativeactfile',) + +file_administrativeactfile_modification_wizard = \ + FileEditAdministrativeActWizard.as_view([ + ('selec-file_administrativeactfile_modification', + AdministrativeActFileFormSelection), + ('administrativeact-file_administrativeactfile_modification', + AdministrativeActFileForm), + ('final-file_administrativeactfile_modification', FinalForm)], + url_name='file_administrativeactfile_modification',) + +file_administrativeactfile_deletion_wizard = \ + AdministrativeActDeletionWizard.as_view([ + ('selec-file_administrativeactfile_deletion', + AdministrativeActFileFormSelection), + ('final-file_administrativeactfile_deletion', + FinalAdministrativeActDeleteForm)], + url_name='file_administrativeactfile_deletion',) + diff --git a/archaeological_files/wizards.py b/archaeological_files/wizards.py new file mode 100644 index 000000000..b161deae0 --- /dev/null +++ b/archaeological_files/wizards.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.utils.translation import ugettext_lazy as _ + +from ishtar_common.wizards import Wizard, ClosingWizard +from archaeological_operations.wizards import OperationAdministrativeActWizard,\ + AdministrativeActDeletionWizard +from archaeological_operations.models import AdministrativeAct +import models + +class FileWizard(Wizard): + model = models.File + object_parcel_type = 'associated_file' + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Manage towns + """ + if data: + data = data.copy() + else: + data = {} + # manage the dynamic choice of towns + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + town_form_key = 'towns-' + self.url_name + if step.startswith('parcels-') and hasattr(form, 'management_form') \ + and self.session_has_key(request, storage, town_form_key): + towns = [] + qdict = request.session[storage.prefix]['step_data'][town_form_key] + for k in qdict.keys(): + if k.endswith("town") and qdict[k]: + try: + town = Town.objects.get(pk=int(qdict[k])) + towns.append((town.pk, unicode(town))) + except (ObjectDoesNotExist, ValueError): + pass + data['TOWNS'] = sorted(towns, key=lambda x:x[1]) + form = super(FileWizard, self).get_form(request, storage, step, data, + files) + return form + + def get_extra_model(self, dct, request, storage, form_list): + dct = super(FileWizard, self).get_extra_model(dct, request, storage, + form_list) + if not dct['numeric_reference']: + current_ref = models.File.objects.filter(year=dct['year'] + ).aggregate(Max('numeric_reference'))["numeric_reference__max"] + dct['numeric_reference'] = current_ref and current_ref + 1 or 1 + return dct + + def done(self, request, storage, form_list, **kwargs): + ''' + Save parcels + ''' + r = super(FileWizard, self).done(request, storage, form_list, + return_object=True, **kwargs) + if type(r) not in (list, tuple) or len(r) != 2: + return r + obj, res = r + obj.parcels.clear() + for form in form_list: + if not hasattr(form, 'prefix') \ + or not form.prefix.startswith('parcels-') \ + or not hasattr(form, 'forms'): + continue + for frm in form.forms: + if not frm.is_valid(): + continue + dct = frm.cleaned_data.copy() + if 'parcel' in dct: + try: + parcel = models.Parcel.objects.get(pk=dct['parcel']) + setattr(parcel, self.object_parcel_type, obj) + parcel.save() + except (ValueError, ObjectDoesNotExist): + continue + continue + try: + dct['town'] = models.Town.objects.get(pk=int(dct['town'])) + except (ValueError, ObjectDoesNotExist): + continue + dct['associated_file'], dct['operation'] = None, None + dct[self.object_parcel_type] = obj + if 'DELETE' in dct: + dct.pop('DELETE') + parcel = models.Parcel.objects.filter(**dct).count() + if not parcel: + dct['history_modifier'] = request.user + parcel = models.Parcel(**dct) + parcel.save() + return res + +class FileModificationWizard(FileWizard): + modification = True + +class FileClosingWizard(ClosingWizard): + model = models.File + fields = ['year', 'numeric_reference', 'internal_reference', + 'file_type', 'in_charge', 'general_contractor', 'creation_date', + 'reception_date', 'total_surface', 'total_developed_surface', + 'address', 'address_complement', 'postal_code', 'comment'] + if settings.COUNTRY == 'fr': + fields += ['saisine_type', 'reference_number'] + fields += ['towns'] +class FileDeletionWizard(FileClosingWizard): + def get_formated_datas(self, forms): + datas = super(FileDeletionWizard, self).get_formated_datas(forms) + datas.append((_("Associated operations"), [])) + for operation in models.Operation.objects.filter( + associated_file=self.current_obj).all(): + if operation.end_date: + datas[-1][1].append(('', unicode(operation))) + return datas + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + for operation in models.Operation.objects.filter( + associated_file=obj).all(): + operation.delete() + obj.delete() + return render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + + +class FileAdministrativeActWizard(OperationAdministrativeActWizard): + model = models.File + +class FileEditAdministrativeActWizard(FileAdministrativeActWizard): + model = AdministrativeAct + edit = True + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage).associated_file diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 7d64214f5..21593a450 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2010-2011 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -18,7 +18,7 @@ # See the file COPYING for details. """ -Items forms definitions +Finds forms definitions """ import datetime @@ -33,67 +33,20 @@ from django.utils.translation import ugettext_lazy as _ from ishtar import settings +from ishtar_common.models import Person, valid_id +from archaeological_operations.models import Period, OperationType +from archaeological_context_records.models import DatingType, DatingQuality +from archaeological_warehouse.models import Warehouse, ContainerType, Container import models import widgets -from forms import Wizard, FinalForm, FormSet, SearchWizard, DeletionWizard,\ +from forms import FinalForm, FormSet,\ FloatField, formset_factory, get_now, get_form_selection, reverse_lazy from forms_common import get_town_field, get_warehouse_field, SourceForm, \ - SourceWizard, SourceSelect, SourceDeletionForm, AuthorFormset + SourceSelect, SourceDeletionForm, AuthorFormset from forms_context_records import RecordFormSelection -class ItemWizard(Wizard): - model = models.Item - - def get_current_contextrecord(self, request, storage): - step = storage.get_current_step() - if not step: - return - if step.endswith('_creation'): # a context record has been selected - main_form_key = 'selecrecord-' + self.url_name - try: - idx = int(self.session_get_value(request, storage, - main_form_key, 'pk')) - current_cr = models.ContextRecord.objects.get(pk=idx) - return current_cr - except(TypeError, ValueError, ObjectDoesNotExist): - pass - current_item = self.get_current_object(request, storage) - if current_item: - base_finds = current_item.base_finds.all() - if base_finds: - return base_finds[0].context_record - - def get_template_context(self, request, storage, form=None): - """ - Get the operation and context record "reminder" on top of wizard forms - """ - context = super(ItemWizard, self).get_template_context(request, - storage, form) - current_cr = self.get_current_contextrecord(request, storage) - if not current_cr: - return context - operation = current_cr.operation - items = [] - if hasattr(operation, 'code_patriarche') and operation.code_patriarche: - items.append(unicode(operation.code_patriarche)) - items.append("-".join((unicode(operation.year), - unicode(operation.operation_code)))) - reminder = unicode(_("Current operation: ")) + u" - ".join(items) - reminder += u"<br/>" + unicode(_("Current context record: "))\ - + unicode(current_cr.label) - context['reminder'] = mark_safe(reminder) - return context - - def get_extra_model(self, dct, request, storage, form_list): - dct = super(ItemWizard, self).get_extra_model(dct, request, storage, - form_list) - dct['order'] = 1 - if 'pk' in dct and type(dct['pk']) == models.ContextRecord: - dct['base_finds__context_record'] = dct.pop('pk') - return dct - -class ItemForm(forms.Form): - form_label = _("Item") +class FindForm(forms.Form): + form_label = _("Find") base_model = 'base_finds' associated_models = {'material_type':models.MaterialType,} label = forms.CharField(label=_(u"ID"), @@ -106,37 +59,30 @@ class ItemForm(forms.Form): choices=models.MaterialType.get_types()) volume = FloatField(label=_(u"Volume (l)"), required=False) weight = FloatField(label=_(u"Weight (g)"), required=False) - item_number = forms.IntegerField(label=_(u"Item number"), required=False) + find_number = forms.IntegerField(label=_(u"Find number"), required=False) class DateForm(forms.Form): form_label = _("Dating") base_model = 'dating' - associated_models = {'dating__dating_type':models.DatingType, - 'dating__quality':models.DatingQuality, - 'dating__period':models.Period} + associated_models = {'dating__dating_type':DatingType, + 'dating__quality':DatingQuality, + 'dating__period':Period} dating__period = forms.ChoiceField(label=_("Period"), - choices=models.Period.get_types()) + choices=Period.get_types()) dating__start_date = forms.IntegerField(label=_(u"Start date"), required=False) dating__end_date = forms.IntegerField(label=_(u"End date"), required=False) dating__quality = forms.ChoiceField(label=_("Quality"), required=False, - choices=models.DatingQuality.get_types()) + choices=DatingQuality.get_types()) dating__dating_type = forms.ChoiceField(label=_("Dating type"), required=False, choices=[]) def __init__(self, *args, **kwargs): super(DateForm, self).__init__(*args, **kwargs) - self.fields['dating__dating_type'].choices = models.DatingType.get_types() - self.fields['dating__dating_type'].help_text = models.DatingType.get_help() + self.fields['dating__dating_type'].choices = DatingType.get_types() + self.fields['dating__dating_type'].help_text = DatingType.get_help() -item_creation_wizard = ItemWizard([ - ('selecrecord-item_creation', RecordFormSelection), - ('item-item_creation', ItemForm), - ('dating-item_creation', DateForm), - ('final-item_creation', FinalForm)], - url_name='item_creation',) - -class ItemSelect(forms.Form): +class FindSelect(forms.Form): base_finds__context_record__parcel__town = get_town_field() base_finds__context_record__operation__year = forms.IntegerField( label=_(u"Year")) @@ -145,61 +91,42 @@ class ItemSelect(forms.Form): dating__period = forms.ChoiceField(label=_(u"Period"), choices=[]) # TODO search by warehouse material_type = forms.ChoiceField(label=_(u"Material type"), choices=[]) - base_finds__item__description = forms.CharField(label=_(u"Description")) + base_finds__find__description = forms.CharField(label=_(u"Description")) base_finds__is_isolated = forms.NullBooleanField(label=_(u"Is isolated?")) def __init__(self, *args, **kwargs): - super(ItemSelect, self).__init__(*args, **kwargs) - self.fields['dating__period'].choices = \ - models.Period.get_types() - self.fields['dating__period'].help_text = \ - models.Period.get_help() + super(FindSelect, self).__init__(*args, **kwargs) + self.fields['dating__period'].choices = Period.get_types() + self.fields['dating__period'].help_text = Period.get_help() self.fields['material_type'].choices = \ models.MaterialType.get_types() self.fields['material_type'].help_text = \ models.MaterialType.get_help() -class ItemFormSelection(forms.Form): - form_label = _("Item search") - associated_models = {'pk':models.Item} - currents = {'pk':models.Item} +class FindFormSelection(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-item'), - ItemSelect(), models.Item, source_full=reverse_lazy('get-item-full')), - validators=[models.valid_id(models.Item)]) - -item_search_wizard = SearchWizard([ - ('general-item_search', ItemFormSelection)], - url_name='item_search',) - -class ItemModificationWizard(ItemWizard): - modification = True - -item_modification_wizard = ItemModificationWizard([ - ('selec-item_modification', ItemFormSelection), - ('item-item_modification', ItemForm), - ('dating-item_modification', DateForm), - ('final-item_modification', FinalForm)], - url_name='item_modification',) - -class TreatmentWizard(Wizard): - model = models.Treatment + widget=widgets.JQueryJqGrid(reverse_lazy('get-find'), + FindSelect(), models.Find, 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, - 'person':models.Person, - 'location':models.Warehouse} + 'person':Person, + 'location':Warehouse} treatment_type = forms.ChoiceField(label=_(u"Treatment type"), choices=[]) person = forms.IntegerField(label=_(u"Person"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), - associated_model=models.Person, new=True), - validators=[models.valid_id(models.Person)]) + associated_model=Person, new=True), + validators=[valid_id(Person)]) location = forms.IntegerField(label=_(u"Location"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-warehouse'), associated_model=models.Warehouse, + reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, new=True), - validators=[models.valid_id(models.Warehouse)]) + validators=[valid_id(Warehouse)]) description = forms.CharField(label=_(u"Description"), widget=forms.Textarea, required=False) start_date = forms.DateField(label=_(u"Start date"), required=False, @@ -214,19 +141,19 @@ class BaseTreatmentForm(forms.Form): self.fields['treatment_type'].help_text = models.TreatmentType.get_help( exclude=['packaging']) -class ItemMultipleFormSelection(forms.Form): - form_label = _(u"Upstream items") - associated_models = {'items':models.Item} - associated_labels = {'items':_(u"Items")} - items = forms.CharField(label="", required=False, - widget=widgets.JQueryJqGrid(reverse_lazy('get-item'), - ItemSelect(), models.Item, multiple=True, multiple_cols=[2, 3, 4]), - validators=[models.valid_ids(models.Item)]) +class FindMultipleFormSelection(forms.Form): + form_label = _(u"Upstream finds") + associated_models = {'finds':models.Find} + associated_labels = {'finds':_(u"Finds")} + finds = forms.CharField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-find'), + FindSelect(), models.Find, multiple=True, multiple_cols=[2, 3, 4]), + validators=[valid_ids(models.Find)]) def clean(self): - if not 'items' in self.cleaned_data or not self.cleaned_data['items']: + if not 'finds' in self.cleaned_data or not self.cleaned_data['finds']: raise forms.ValidationError(_(u"You should at least select one " - u"archaeological item.")) + u"archaeological find.")) return self.cleaned_data class ContainerForm(forms.Form): @@ -235,26 +162,24 @@ class ContainerForm(forms.Form): 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, + reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, new=True), - validators=[models.valid_id(models.Warehouse)]) + validators=[valid_id(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'].help_text = \ - models.ContainerType.get_help() + self.fields['container_type'].choices = ContainerType.get_types() + self.fields['container_type'].help_text = ContainerType.get_help() def save(self, user): dct = self.cleaned_data dct['history_modifier'] = user - dct['container_type'] = models.ContainerType.objects.get( + dct['container_type'] = ContainerType.objects.get( pk=dct['container_type']) - dct['location'] = models.Warehouse.objects.get(pk=dct['location']) - new_item = models.Container(**dct) + dct['location'] = Warehouse.objects.get(pk=dct['location']) + new_item = Container(**dct) new_item.save() return new_item @@ -279,8 +204,8 @@ def check_treatment(form_name, type_key, type_list=[], not_type_list=[]): return False return func -class ResultItemForm(forms.Form): - form_label = _(u"Resulting item") +class ResultFindForm(forms.Form): + form_label = _(u"Resulting find") associated_models = {'material_type':models.MaterialType} label = forms.CharField(label=_(u"ID"), validators=[validators.MaxLengthValidator(60)]) @@ -290,204 +215,60 @@ class ResultItemForm(forms.Form): choices=models.MaterialType.get_types()) volume = forms.IntegerField(label=_(u"Volume (l)")) weight = forms.IntegerField(label=_(u"Weight (g)")) - item_number = forms.IntegerField(label=_(u"Item number")) + find_number = forms.IntegerField(label=_(u"Find number")) -ResultItemFormSet = formset_factory(ResultItemForm, can_delete=True, +ResultFindFormSet = formset_factory(ResultFindForm, can_delete=True, formset=FormSet) -ResultItemFormSet.form_label = _(u"Resulting items") - -class UpstreamItemFormSelection(ItemFormSelection): - form_label = _(u"Upstream item") - -treatment_creation_wizard = TreatmentWizard([ - ('basetreatment-treatment_creation', BaseTreatmentForm), - ('selecitem-treatment_creation', UpstreamItemFormSelection), - ('multiselecitems-treatment_creation', ItemMultipleFormSelection), - ('container-treatment_creation', ContainerForm), - ('resultitem-treatment_creation', ResultItemForm), - ('resultitems-treatment_creation', ResultItemFormSet), - ('final-treatment_creation', FinalForm)], - condition_list={ -'selecitem-treatment_creation': - check_treatment('basetreatment-treatment_creation', 'treatment_type', - not_type_list=['physical_grouping', 'packaging']), -'multiselecitems-treatment_creation': - check_treatment('basetreatment-treatment_creation', 'treatment_type', - ['physical_grouping', 'packaging']), -'resultitems-treatment_creation': - check_treatment('basetreatment-treatment_creation', 'treatment_type', - ['split']), -'resultitem-treatment_creation': - check_treatment('basetreatment-treatment_creation', 'treatment_type', - not_type_list=['split']), -'container-treatment_creation': - check_treatment('basetreatment-treatment_creation', 'treatment_type', - ['packaging']), - }, - url_name='treatment_creation',) - -############# -# Packaging # -############# - -class PackagingWizard(TreatmentWizard): - def save_model(self, dct, m2m, whole_associated_models, request, storage, - form_list, return_object): - dct = self.get_extra_model(dct, request, storage, form_list) - obj = self.get_current_saved_object(request, storage) - dct['location'] = dct['container'].location - items = dct.pop('items') - treatment = models.Treatment(**dct) - treatment.save() - if not hasattr(items, '__iter__'): - items = [items] - for item in items: - new = item.duplicate(request.user) - item.downstream_treatment = treatment - item.save() - new.upstream_treatment = treatment - new.container = dct['container'] - new.save() - res = render_to_response('wizard_done.html', {}, - context_instance=RequestContext(request)) - return return_object and (obj, res) or res - -class ContainerSelect(forms.Form): - location = get_warehouse_field() - container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) - reference = forms.CharField(label=_(u"Reference")) - - def __init__(self, *args, **kwargs): - super(ContainerSelect, self).__init__(*args, **kwargs) - self.fields['container_type'].choices = \ - models.ContainerType.get_types() - self.fields['container_type'].help_text = \ - models.ContainerType.get_help() - -ContainerFormSelection = get_form_selection( - 'ContainerFormSelection', _(u"Container search"), 'container', - models.Container, ContainerSelect, 'get-container', - _(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':models.TreatmentType, - 'person':models.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=models.Person, new=True), - validators=[models.valid_id(models.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 = \ - models.TreatmentType.objects.get(txt_idx='packaging').pk - -class ItemPackagingFormSelection(ItemMultipleFormSelection): - form_label = _(u"Packaged items") +ResultFindFormSet.form_label = _(u"Resulting finds") -warehouse_packaging_wizard = PackagingWizard([ - ('seleccontainer-packaging', ContainerFormSelection), - ('base-packaging', BasePackagingForm), - ('multiselecitems-packaging', ItemPackagingFormSelection), - ('final-packaging', FinalForm)], - url_name='warehouse_packaging',) +class UpstreamFindFormSelection(FindFormSelection): + form_label = _(u"Upstream find") -""" -warehouse_packaging_wizard = ItemSourceWizard([ - ('selec-warehouse_packaging', ItemsSelection), - ('final-warehouse_packaging', FinalForm)], - url_name='warehouse_packaging',) -""" ############################################# -# Source management for archaelogical items # +# Source management for archaelogical finds # ############################################# -class ItemSourceWizard(SourceWizard): - model = models.ItemSource +SourceFindFormSelection = get_form_selection( + 'SourceFindFormSelection', _(u"Archaelogical find search"), 'find', + models.Find, FindSelect, 'get-find', + _(u"You should select an archaelogical find.")) -SourceItemFormSelection = get_form_selection( - 'SourceItemFormSelection', _(u"Archaelogical item search"), 'item', - models.Item, ItemSelect, 'get-item', - _(u"You should select an archaelogical item.")) - -item_source_creation_wizard = ItemSourceWizard([ - ('selec-item_source_creation', SourceItemFormSelection), - ('source-item_source_creation', SourceForm), - ('authors-item_source_creation', AuthorFormset), - ('final-item_source_creation', FinalForm)], - url_name='item_source_creation',) - -class ItemSourceSelect(SourceSelect): - item__base_finds__context_record__operation__year = forms.IntegerField( +class FindSourceSelect(SourceSelect): + find__base_finds__context_record__operation__year = forms.IntegerField( label=_(u"Year of the operation")) - item__dating__period = forms.ChoiceField( - label=_(u"Period of the archaelogical item"), + find__dating__period = forms.ChoiceField( + label=_(u"Period of the archaelogical find"), choices=[]) - item__material_type = forms.ChoiceField( - label=_("Material type of the archaelogical item"), + find__material_type = forms.ChoiceField( + label=_("Material type of the archaelogical find"), choices=models.MaterialType.get_types()) - item__description = forms.CharField( - label=_(u"Description of the archaelogical item")) + find__description = forms.CharField( + label=_(u"Description of the archaelogical find")) def __init__(self, *args, **kwargs): - super(ItemSourceSelect, self).__init__(*args, **kwargs) - self.fields['item__dating__period'].choices = \ - models.Period.get_types() - self.fields['item__dating__period'].help_text = \ - models.Period.get_help() - self.fields['item__material_type'].choices = \ + super(FindSourceSelect, self).__init__(*args, **kwargs) + self.fields['find__dating__period'].choices = Period.get_types() + self.fields['find__dating__period'].help_text = Period.get_help() + self.fields['find__material_type'].choices = \ models.MaterialType.get_types() - self.fields['item__material_type'].help_text = \ + self.fields['find__material_type'].help_text = \ models.MaterialType.get_help() -ItemSourceFormSelection = get_form_selection( - 'ItemSourceFormSelection', _(u"Documentation search"), 'pk', - models.ItemSource, ItemSourceSelect, 'get-itemsource', +FindSourceFormSelection = get_form_selection( + 'FindSourceFormSelection', _(u"Documentation search"), 'pk', + models.FindSource, FindSourceSelect, 'get-findsource', _(u"You should select a document.")) -item_source_modification_wizard = ItemSourceWizard([ - ('selec-item_source_modification', ItemSourceFormSelection), - ('source-item_source_modification', SourceForm), - ('authors-item_source_modification', AuthorFormset), - ('final-item_source_modification', FinalForm)], - url_name='item_source_modification',) - -class ItemSourceDeletionWizard(DeletionWizard): - model = models.ItemSource - fields = ['item', 'title', 'source_type', 'authors',] - -item_source_deletion_wizard = ItemSourceDeletionWizard([ - ('selec-item_source_deletion', ItemSourceFormSelection), - ('final-item_source_deletion', SourceDeletionForm)], - url_name='item_source_deletion',) - -""" #################################### # Source management for treatments # #################################### -class TreatmentSourceWizard(SourceWizard): - model = models.TreamentSource - SourceTreatementFormSelection = get_form_selection( 'SourceTreatmentFormSelection', _(u"Treatment search"), 'operation', models.Treatment, TreatmentSelect, 'get-treatment', _(u"You should select a treatment.")) -treatment_source_creation_wizard = TreatmentSourceWizard([ - ('selec-treatment_source_creation', SourceTreatmentFormSelection), - ('source-treatment_source_creation', SourceForm), - ('authors-treatment_source_creation', AuthorFormset), - ('final-treatment_source_creation', FinalForm)], - url_name='treatment_source_creation',) - class TreatmentSourceSelect(SourceSelect): operation__towns = get_town_field(label=_(u"Operation's town")) treatment__treatment_type = forms.ChoiceField(label=_(u"Operation type"), @@ -497,11 +278,12 @@ class TreatmentSourceSelect(SourceSelect): def __init__(self, *args, **kwargs): super(OperationSourceSelect, self).__init__(*args, **kwargs) self.fields['operation__operation_type'].choices = \ - models.OperationType.get_types() + OperationType.get_types() self.fields['operation__operation_type'].help_text = \ - models.OperationType.get_help() + OperationType.get_help() +""" OperationSourceFormSelection = get_form_selection( 'OperationSourceFormSelection', _(u"Documentation search"), 'pk', models.OperationSource, OperationSourceSelect, 'get-operationsource', diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py index 4c733436d..fbf359813 100644 --- a/archaeological_finds/urls.py +++ b/archaeological_finds/urls.py @@ -20,24 +20,24 @@ from django.conf.urls.defaults import * """ -import forms +import views # forms urlpatterns = patterns('', url(r'item_search/(?P<step>.+)$', - forms.item_search_wizard, name='item_search'), + views.item_search_wizard, name='item_search'), url(r'item_creation/(?P<step>.+)$', - forms.item_creation_wizard, name='item_creation'), + views.item_creation_wizard, name='item_creation'), url(r'item_modification/(?P<step>.+)$', - forms.item_modification_wizard, name='item_modification'), + views.item_modification_wizard, name='item_modification'), url(r'item_source_creation/(?P<step>.+)$', - forms.item_source_creation_wizard, + views.item_source_creation_wizard, name='item_source_creation'), url(r'item_source_modification/(?P<step>.+)$', - forms.item_source_modification_wizard, + views.item_source_modification_wizard, name='item_source_modification'), url(r'item_source_deletion/(?P<step>.+)$', - forms.item_source_deletion_wizard, + views.item_source_deletion_wizard, name='item_source_deletion'), ) diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py index af428d59e..cde192ef3 100644 --- a/archaeological_finds/views.py +++ b/archaeological_finds/views.py @@ -18,6 +18,9 @@ # See the file COPYING for details. from ishtar_common.views import get_item, show_item, revert_item +from ishtar_common.wizards import SearchWizard +from wizards import * +from forms import * import models get_find = get_item(models.Find, @@ -41,3 +44,76 @@ get_findsource = get_item(models.FindSource, 'find__dating__period':'find__dating__period__pk', 'find__description':'find__description__icontains', }) + +find_creation_wizard = FindWizard.as_view([ + ('selecrecord-find_creation', RecordFormSelection), + ('find-find_creation', FindForm), + ('dating-find_creation', DateForm), + ('final-find_creation', FinalForm)], + url_name='find_creation',) + +find_search_wizard = SearchWizard.as_view([ + ('general-find_search', FindFormSelection)], + url_name='find_search',) + +find_modification_wizard = FindModificationWizard.as_view([ + ('selec-find_modification', FindFormSelection), + ('find-find_modification', FindForm), + ('dating-find_modification', DateForm), + ('final-find_modification', FinalForm)], + url_name='find_modification',) + +treatment_creation_wizard = TreatmentWizard.as_view([ + ('basetreatment-treatment_creation', BaseTreatmentForm), + ('selecfind-treatment_creation', UpstreamFindFormSelection), + ('multiselecfinds-treatment_creation', FindMultipleFormSelection), + ('container-treatment_creation', ContainerForm), + ('resultfind-treatment_creation', ResultFindForm), + ('resultfinds-treatment_creation', ResultFindFormSet), + ('final-treatment_creation', FinalForm)], + condition_dict={ +'selecfind-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + not_type_list=['physical_grouping', 'packaging']), +'multiselecfinds-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['physical_grouping', 'packaging']), +'resultfinds-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['split']), +'resultfind-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + not_type_list=['split']), +'container-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['packaging']), + }, + url_name='treatment_creation',) + +find_source_creation_wizard = FindSourceWizard.as_view([ + ('selec-find_source_creation', SourceFindFormSelection), + ('source-find_source_creation', SourceForm), + ('authors-find_source_creation', AuthorFormset), + ('final-find_source_creation', FinalForm)], + url_name='find_source_creation',) + +find_source_modification_wizard = FindSourceWizard.as_view([ + ('selec-find_source_modification', FindSourceFormSelection), + ('source-find_source_modification', SourceForm), + ('authors-find_source_modification', AuthorFormset), + ('final-find_source_modification', FinalForm)], + url_name='find_source_modification',) + +find_source_deletion_wizard = FindSourceDeletionWizard.as_view([ + ('selec-find_source_deletion', FindSourceFormSelection), + ('final-find_source_deletion', SourceDeletionForm)], + url_name='find_source_deletion',) + +treatment_source_creation_wizard = TreatmentSourceWizard.as_view([ + ('selec-treatment_source_creation', SourceTreatmentFormSelection), + ('source-treatment_source_creation', SourceForm), + ('authors-treatment_source_creation', AuthorFormset), + ('final-treatment_source_creation', FinalForm)], + url_name='treatment_source_creation',) + + diff --git a/archaeological_finds/wizards.py b/archaeological_finds/wizards.py new file mode 100644 index 000000000..2352863eb --- /dev/null +++ b/archaeological_finds/wizards.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.utils.translation import ugettext_lazy as _ + +from ishtar_common.wizards import Wizard, DeletionWizard, SourceWizard +import models + +class ItemWizard(Wizard): + model = models.Item + + def get_current_contextrecord(self, request, storage): + step = storage.get_current_step() + if not step: + return + if step.endswith('_creation'): # a context record has been selected + main_form_key = 'selecrecord-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'pk')) + current_cr = models.ContextRecord.objects.get(pk=idx) + return current_cr + except(TypeError, ValueError, ObjectDoesNotExist): + pass + current_item = self.get_current_object(request, storage) + if current_item: + base_finds = current_item.base_finds.all() + if base_finds: + return base_finds[0].context_record + + def get_template_context(self, request, storage, form=None): + """ + Get the operation and context record "reminder" on top of wizard forms + """ + context = super(ItemWizard, self).get_template_context(request, + storage, form) + current_cr = self.get_current_contextrecord(request, storage) + if not current_cr: + return context + operation = current_cr.operation + items = [] + if hasattr(operation, 'code_patriarche') and operation.code_patriarche: + items.append(unicode(operation.code_patriarche)) + items.append("-".join((unicode(operation.year), + unicode(operation.operation_code)))) + reminder = unicode(_("Current operation: ")) + u" - ".join(items) + reminder += u"<br/>" + unicode(_("Current context record: "))\ + + unicode(current_cr.label) + context['reminder'] = mark_safe(reminder) + return context + + def get_extra_model(self, dct, request, storage, form_list): + dct = super(ItemWizard, self).get_extra_model(dct, request, storage, + form_list) + dct['order'] = 1 + if 'pk' in dct and type(dct['pk']) == models.ContextRecord: + dct['base_finds__context_record'] = dct.pop('pk') + return dct + +class ItemModificationWizard(ItemWizard): + modification = True + +class TreatmentWizard(Wizard): + model = models.Treatment + +class ItemSourceWizard(SourceWizard): + model = models.ItemSource + +class ItemSourceDeletionWizard(DeletionWizard): + model = models.ItemSource + fields = ['item', 'title', 'source_type', 'authors',] + +class TreatmentSourceWizard(SourceWizard): + model = models.TreamentSource + + diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index d4152d4fa..d87e72423 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -31,37 +31,23 @@ from django.core.exceptions import ObjectDoesNotExist from django.db.models import Max from django.utils.translation import ugettext_lazy as _ +from ishtar_common.models import valid_id, PersonType, Person, Town +from archaeological_files.models import File import models -import widgets -from ishtar_common.forms import Wizard, FinalForm, FormSet, SearchWizard, \ - ClosingWizard, ClosingDateFormSelection, DeletionWizard, formset_factory, \ +from ishtar_common import widgets +from ishtar_common.forms import FinalForm, FormSet, \ + ClosingDateFormSelection, formset_factory, \ get_now, reverse_lazy, get_form_selection from ishtar_common.forms_common import TownForm, TownFormSet, TownFormset, \ - AuthorFormset, SourceForm, SourceWizard, SourceSelect, \ + AuthorFormset, SourceForm, SourceSelect, \ SourceDeletionForm, get_town_field -def is_preventive(form_name, model, type_key='operation_type', key=''): - def func(self, request, storage): - if storage.prefix not in request.session or \ - 'step_data' not in request.session[storage.prefix] or \ - form_name not in request.session[storage.prefix]['step_data'] or\ - form_name + '-' + type_key not in \ - request.session[storage.prefix]['step_data'][form_name]: - return False - try: - typ = int(request.session[storage.prefix]['step_data']\ - [form_name][form_name+'-'+type_key]) - return model.is_preventive(typ, key) - except ValueError: - return False - return func - class ParcelForm(forms.Form): form_label = _("Parcels") base_model = 'parcel' associated_models = {'parcel':models.Parcel, 'town':models.Town} town = forms.ChoiceField(label=_("Town"), choices=(), required=False, - validators=[models.valid_id(models.Town)]) + validators=[valid_id(models.Town)]) section = forms.CharField(label=_(u"Section"), required=False, validators=[validators.MaxLengthValidator(4)]) parcel_number = forms.CharField(label=_(u"Parcel number"), required=False, @@ -107,109 +93,6 @@ ParcelFormSet = formset_factory(ParcelForm, can_delete=True, formset=ParcelFormSet) ParcelFormSet.form_label = _(u"Parcels") -class OperationWizard(Wizard): - model = models.Operation - object_parcel_type = 'operation' - - def get_template(self, request, storage): - templates = super(OperationWizard, self).get_template(request, storage) - current_step = storage.get_current_step() or self.get_first_step( - request, storage) - if current_step.startswith('towns-'): - templates = ['towns_wizard.html'] + templates - return templates - - def get_extra_context(self, request, storage): - """ - Return extra context for templates - """ - context = super(OperationWizard, self).get_extra_context(request, - storage) - step = self.determine_step(request, storage) - if not step.startswith('towns-'): - return context - context['TOWNS'] = self.get_towns(request, storage) - return context - - def get_towns(self, request, storage): - """ - Obtention des villes disponibles - """ - general_form_key = 'general-' + self.url_name - towns = [] - file_id = self.session_get_value(request, storage, general_form_key, - "associated_file") - if file_id: - try: - for town in models.File.objects.get(pk=int(file_id) - ).towns.all(): - towns.append((town.pk, unicode(town))) - except (ValueError, ObjectDoesNotExist): - pass - return sorted(towns, key=lambda x:x[1]) - else: - return -1 - - def get_form(self, request, storage, step=None, data=None, files=None): - """ - Manage specifics fields - """ - if data: - data = data.copy() - else: - data = {} - if not step: - step = self.determine_step(request, storage) - form = self.get_form_list(request, storage)[step] - general_form_key = 'general-' + self.url_name - # manage the dynamic choice of towns - if step.startswith('towns-') and hasattr(form, 'management_form'): - data['TOWNS'] = self.get_towns(request, storage) - elif step.startswith('parcels') and hasattr(form, 'management_form'): - file_id = self.session_get_value(request, storage, general_form_key, - "associated_file") - if file_id: - parcels = [] - try: - for parcel in models.File.objects.get(pk=int(file_id) - ).parcels.all(): - parcels.append((parcel.pk, parcel.short_label())) - except (ValueError, ObjectDoesNotExist): - pass - data['PARCELS'] = sorted(parcels, key=lambda x:x[1]) - else: - town_form_key = step.startswith('parcelsgeneral') \ - and 'townsgeneral-' or 'towns-' - town_form_key += self.url_name - town_ids = self.session_get_value(request, storage, - town_form_key, 'town', multi=True) or [] - towns = [] - for town_id in town_ids: - try: - town = models.Town.objects.get(pk=int(town_id)) - towns.append((town.pk, unicode(town))) - except (ValueError, ObjectDoesNotExist): - pass - data['TOWNS'] = sorted(towns, key=lambda x:x[1]) - data = data or None - form = super(OperationWizard, self).get_form(request, storage, step, - data, files) - return form - - def get_formated_datas(self, forms): - """ - Show a specific warning if no archaelogical file is provided - """ - datas = super(OperationWizard, self).get_formated_datas(forms) - # if the general town form is used the advertissement is pertinent - has_no_af = [form.prefix for form in forms - if form.prefix == 'townsgeneral-operation'] and True - if has_no_af: - datas = [[_(u"Warning: No Archaelogical File is provided. " - u"If you have forget it return to the first step."), []]]\ - + datas - return datas - class OperationSelect(forms.Form): common_name = forms.CharField(label=_(u"Name"), max_length=30) towns = get_town_field() @@ -233,7 +116,7 @@ class OperationFormSelection(forms.Form): widget=widgets.JQueryJqGrid(reverse_lazy('get-operation'), OperationSelect(), models.Operation, source_full=reverse_lazy('get-operation-full')), - validators=[models.valid_id(models.Operation)]) + validators=[valid_id(models.Operation)]) def clean(self): cleaned_data = self.cleaned_data @@ -267,22 +150,22 @@ class OperationCodeInput(forms.TextInput): class OperationFormGeneral(forms.Form): form_label = _(u"General") - associated_models = {'in_charge':models.Person, - 'associated_file':models.File, + associated_models = {'in_charge':Person, + 'associated_file':File, 'operation_type':models.OperationType} - currents = {'associated_file':models.File} + currents = {'associated_file':File} pk = forms.IntegerField(required=False, widget=forms.HiddenInput) in_charge = forms.IntegerField(label=_("Person in charge of the operation"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', args=["_".join( - [unicode(models.PersonType.objects.get(txt_idx='head_scientist').pk), - unicode(models.PersonType.objects.get(txt_idx='sra_agent').pk)])]), - associated_model=models.Person, new=True), - validators=[models.valid_id(models.Person)], required=False) + [unicode(PersonType.objects.get(txt_idx='head_scientist').pk), + unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])]), + associated_model=Person, new=True), + validators=[valid_id(Person)], required=False) associated_file = forms.IntegerField(label=_(u"Archaelogical file"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), - associated_model=models.File), - validators=[models.valid_id(models.File)], required=False) + associated_model=File), + validators=[valid_id(File)], required=False) operation_type = forms.ChoiceField(label=_(u"Operation type"), choices=[]) start_date = forms.DateField(label=_(u"Start date"), required=False, @@ -369,9 +252,9 @@ class OperationFormPreventiveDiag(forms.Form): class SelectedTownForm(forms.Form): form_label = _("Towns") - associated_models = {'town':models.Town} + associated_models = {'town':Town} town = forms.ChoiceField(label=_("Town"), choices=(), - validators=[models.valid_id(models.Town)]) + validators=[valid_id(Town)]) def __init__(self, *args, **kwargs): towns = None if 'data' in kwargs and 'TOWNS' in kwargs['data']: @@ -395,7 +278,7 @@ class SelectedParcelForm(forms.Form): form_label = _("Parcels") associated_models = {'parcel':models.Parcel} parcel = forms.ChoiceField(label=_("Parcel"), choices=(), - validators=[models.valid_id(models.Parcel)]) + validators=[valid_id(models.Parcel)]) def __init__(self, *args, **kwargs): parcels = None if 'data' in kwargs and 'PARCELS' in kwargs['data']: @@ -453,10 +336,6 @@ PeriodFormset = formset_factory(PeriodForm, can_delete=True, formset=PeriodFormSet) PeriodFormset.form_label = _("Periods") -operation_search_wizard = SearchWizard([ - ('general-operation_search', OperationFormSelection)], - url_name='operation_search',) - def has_associated_file(form_name, file_key='associated_file', negate=False): def func(self, request, storage): if storage.prefix not in request.session or \ @@ -472,126 +351,18 @@ def has_associated_file(form_name, file_key='associated_file', negate=False): except ValueError: return negate return func - -operation_creation_wizard = OperationWizard([ - ('general-operation_creation', OperationFormGeneral), - ('preventive-operation_creation', OperationFormPreventive), - ('preventivediag-operation_creation', OperationFormPreventiveDiag), - ('townsgeneral-operation_creation', TownFormset), - ('towns-operation_creation', SelectedTownFormset), - ('parcelsgeneral-operation_creation', SelectedParcelGeneralFormSet), - ('parcels-operation_creation', SelectedParcelFormSet), - ('remains-operation_creation', RemainFormset), - ('periods-operation_creation', PeriodFormset), - ('final-operation_creation', FinalForm)], - condition_list={ -'preventive-operation_creation':is_preventive('general-operation_creation', - models.OperationType, 'operation_type', 'prev_excavation'), -'preventivediag-operation_creation':is_preventive('general-operation_creation', - models.OperationType, 'operation_type', 'arch_diagnostic'), -'townsgeneral-operation_creation':has_associated_file( - 'general-operation_creation', negate=True), -'towns-operation_creation':has_associated_file('general-operation_creation'), -'parcelsgeneral-operation_creation':has_associated_file( - 'general-operation_creation', negate=True), -'parcels-operation_creation':has_associated_file('general-operation_creation'), - }, - url_name='operation_creation',) - -class OperationModificationWizard(OperationWizard): - modification = True - -operation_modification_wizard = OperationModificationWizard([ - ('selec-operation_modification', OperationFormSelection), - ('general-operation_modification', OperationFormGeneral), - ('preventive-operation_modification', OperationFormPreventive), - ('preventivediag-operation_modification', OperationFormPreventiveDiag), - ('towns-operation_modification', SelectedTownFormset), - ('townsgeneral-operation_modification', TownFormset), - ('parcels-operation_modification', SelectedParcelFormSet), - ('parcelsgeneral-operation_modification', SelectedParcelGeneralFormSet), - ('remains-operation_modification', RemainFormset), - ('periods-operation_modification', PeriodFormset), - ('final-operation_modification', FinalForm)], - condition_list={ -'preventive-operation_modification':is_preventive( - 'general-operation_modification', models.OperationType, - 'operation_type', 'prev_excavation'), -'preventivediag-operation_modification':is_preventive( - 'general-operation_modification', models.OperationType, - 'operation_type', 'arch_diagnostic'), -'townsgeneral-operation_modification':has_associated_file( - 'general-operation_modification', negate=True), -'towns-operation_modification':has_associated_file( - 'general-operation_modification'), -'parcelsgeneral-operation_modification':has_associated_file( - 'general-operation_modification', negate=True), -'parcels-operation_modification':has_associated_file( - 'general-operation_modification'), - }, - url_name='operation_modification',) - -class OperationClosingWizard(ClosingWizard): - model = models.Operation - fields = ['year', 'operation_code', 'operation_type', 'associated_file', -'in_charge', 'start_date', 'excavation_end_date', 'comment', 'towns', 'remains'] - class FinalOperationClosingForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to close this operation?") -operation_closing_wizard = OperationClosingWizard([ - ('selec-operation_closing', OperationFormSelection), - ('date-operation_closing', ClosingDateFormSelection), - ('final-operation_closing', FinalOperationClosingForm)], - url_name='operation_closing',) - -class OperationDeletionWizard(DeletionWizard): - model = models.Operation - fields = OperationClosingWizard.fields - class OperationDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this operation?") -operation_deletion_wizard = OperationDeletionWizard([ - ('selec-operation_deletion', OperationFormSelection), - ('final-operation_deletion', OperationDeletionForm)], - url_name='operation_deletion',) - #################################### # Source management for operations # #################################### -class OperationSourceWizard(SourceWizard): - model = models.OperationSource - def get_form_initial(self, request, storage, step): - initial = super(OperationSourceWizard, self).get_form_initial(request, - storage, step) - # put default index and operation_id field in the main source form - general_form_key = 'selec-' + self.url_name - if step.startswith('source-') \ - and self.session_has_key(request, storage, general_form_key): - gen_storage = request.session[storage.prefix]['step_data']\ - [general_form_key] - if general_form_key+"-operation" in gen_storage: - operation_id = int(gen_storage[general_form_key+"-operation"]) - elif general_form_key+"-pk" in gen_storage: - pk = int(gen_storage[general_form_key+"-pk"]) - try: - source = models.OperationSource.objects.get(pk=pk) - operation_id = source.operation.pk - except ObjectDoesNotExist: - pass - if operation_id: - initial['hidden_operation_id'] = operation_id - if 'index' not in initial: - max_val = models.OperationSource.objects.filter( - operation__pk=operation_id).aggregate( - Max('index'))["index__max"] - initial['index'] = max_val and (max_val + 1) or 1 - return initial - class OperationSourceForm(SourceForm): pk = forms.IntegerField(required=False, widget=forms.HiddenInput) index = forms.IntegerField(label=_(u"Index")) @@ -627,13 +398,6 @@ SourceOperationFormSelection = get_form_selection( models.Operation, OperationSelect, 'get-operation', _(u"You should select an operation.")) -operation_source_creation_wizard = OperationSourceWizard([ - ('selec-operation_source_creation', SourceOperationFormSelection), - ('source-operation_source_creation',OperationSourceForm), - ('authors-operation_source_creation', AuthorFormset), - ('final-operation_source_creation', FinalForm)], - url_name='operation_source_creation',) - class OperationSourceSelect(SourceSelect): operation__towns = get_town_field(label=_(u"Operation's town")) operation__operation_type = forms.ChoiceField(label=_(u"Operation type"), @@ -653,66 +417,10 @@ OperationSourceFormSelection = get_form_selection( models.OperationSource, OperationSourceSelect, 'get-operationsource', _(u"You should select a document.")) -operation_source_modification_wizard = OperationSourceWizard([ - ('selec-operation_source_modification', OperationSourceFormSelection), - ('source-operation_source_modification', OperationSourceForm), - ('authors-operation_source_modification', AuthorFormset), - ('final-operation_source_modification', FinalForm)], - url_name='operation_source_modification',) - -class OperationSourceDeletionWizard(DeletionWizard): - model = models.OperationSource - fields = ['operation', 'title', 'source_type', 'authors',] - -operation_source_deletion_wizard = OperationSourceDeletionWizard([ - ('selec-operation_source_deletion', OperationSourceFormSelection), - ('final-operation_source_deletion', SourceDeletionForm)], - url_name='operation_source_deletion',) - ################################################ # Administrative act management for operations # ################################################ -class OperationAdministrativeActWizard(OperationWizard): - edit = False - - def get_extra_model(self, dct, request, storage, form_list): - dct['history_modifier'] = request.user - return dct - - def get_associated_item(self, request, storage, dct): - return self.get_current_object(request, storage) - - def save_model(self, dct, m2m, whole_associated_models, request, storage, - form_list, return_object): - associated_item = self.get_associated_item(request, storage, dct) - if not associated_item: - return self.render(request, storage, form_list[-1]) - if isinstance(associated_item, models.File): - dct['associated_file'] = associated_item - elif isinstance(associated_item, models.Operation): - dct['operation'] = associated_item - dct['history_modifier'] = request.user - if 'pk' in dct: - dct.pop('pk') - if self.edit: - admact = self.get_current_object(request, storage) - for k in dct: - if hasattr(admact, k): - setattr(admact, k, dct[k]) - else: - admact = models.AdministrativeAct(**dct) - admact.save() - res = render_to_response('wizard_done.html', {}, - context_instance=RequestContext(request)) - return res - -class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard): - model = models.AdministrativeAct - edit = True - def get_associated_item(self, request, storage, dct): - return self.get_current_object(request, storage).operation - class AdministrativeActOpeSelect(forms.Form): operation__towns = get_town_field() act_type = forms.ChoiceField(label=_("Act type"), choices=[]) @@ -732,7 +440,7 @@ class AdministrativeActOpeFormSelection(forms.Form): widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactop'), AdministrativeActOpeSelect(), models.AdministrativeAct, table_cols='TABLE_COLS_OPE'), - validators=[models.valid_id(models.AdministrativeAct)]) + validators=[valid_id(models.AdministrativeAct)]) def clean(self): cleaned_data = self.cleaned_data @@ -744,12 +452,12 @@ class AdministrativeActOpeFormSelection(forms.Form): class AdministrativeActOpeForm(forms.Form): form_label = _("General") associated_models = {'act_type':models.ActType, - 'signatory':models.Person} + 'signatory':Person} act_type = forms.ChoiceField(label=_("Act type"), choices=[]) signatory = forms.IntegerField(label=_("Signatory"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), - associated_model=models.Person, new=True), - validators=[models.valid_id(models.Person)]) + associated_model=Person, new=True), + validators=[valid_id(Person)]) act_object = forms.CharField(label=_(u"Object"), max_length=200, widget=forms.Textarea) signature_date = forms.DateField(label=_(u"Signature date"), @@ -764,41 +472,7 @@ class AdministrativeActOpeForm(forms.Form): self.fields['act_type'].help_text = models.ActType.get_help( dct={'intented_to':'O'}) -class AdministrativeActDeletionWizard(ClosingWizard): - model = models.AdministrativeAct - fields = ['act_type', 'in_charge', 'operator', 'scientific', 'signatory', - 'operation', 'associated_file', 'signature_date', 'act_object',] - if settings.COUNTRY == 'fr': - fields += ['ref_sra'] - - def done(self, request, storage, form_list, **kwargs): - obj = self.get_current_object(request, storage) - obj.delete() - return render_to_response('wizard_done.html', {}, - context_instance=RequestContext(request)) - class FinalAdministrativeActDeleteForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this administrative act?") -operation_administrativeactop_wizard = OperationAdministrativeActWizard([ - ('selec-operation_administrativeactop', OperationFormSelection), - ('administrativeact-operation_administrativeactop', AdministrativeActOpeForm), - ('final-operation_administrativeactop', FinalForm)], - url_name='operation_administrativeactop',) - -operation_administrativeactop_modification_wizard = \ - OperationEditAdministrativeActWizard([ - ('selec-operation_administrativeactop_modification', - AdministrativeActOpeFormSelection), - ('administrativeact-operation_administrativeactop_modification', - AdministrativeActOpeForm), - ('final-operation_administrativeactop_modification', FinalForm)], - url_name='operation_administrativeactop_modification',) - -operation_administrativeactop_deletion_wizard = AdministrativeActDeletionWizard([ - ('selec-operation_administrativeactop_deletion', - AdministrativeActOpeFormSelection), - ('final-operation_administrativeactop_deletion', - FinalAdministrativeActDeleteForm)], - url_name='operation_administrativeactop_deletion',) diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index a761b4ccc..fb3278e31 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -20,38 +20,38 @@ from django.conf.urls.defaults import * """ -import forms +import views # forms urlpatterns = patterns('', url(r'operation_search/(?P<step>.+)$', - forms.operation_search_wizard, name='operation_search'), + views.operation_search_wizard, name='operation_search'), url(r'operation_creation/(?P<step>.+)$', - forms.operation_creation_wizard, name='operation_creation'), + views.operation_creation_wizard, name='operation_creation'), url(r'operation_modification/(?P<step>.+)$', - forms.operation_modification_wizard, + views.operation_modification_wizard, name='operation_modification'), url(r'operation_closing/(?P<step>.+)$', - forms.operation_closing_wizard, name='operation_closing'), + views.operation_closing_wizard, name='operation_closing'), url(r'operation_deletion/(?P<step>.+)$', - forms.operation_deletion_wizard, name='operation_deletion'), + views.operation_deletion_wizard, name='operation_deletion'), url(r'operation_administrativeactop/(?P<step>.+)$', - forms.operation_administrativeactop_wizard, + views.operation_administrativeactop_wizard, name='operation_administrativeactop'), url(r'operation_administrativeactop_modification/(?P<step>.+)$', - forms.operation_administrativeactop_modification_wizard, + views.operation_administrativeactop_modification_wizard, name='operation_administrativeactop_modification'), url(r'operation_administrativeactop_deletion/(?P<step>.+)$', - forms.operation_administrativeactop_deletion_wizard, + views.operation_administrativeactop_deletion_wizard, name='operation_administrativeactop_deletion'), url(r'operation_source_creation/(?P<step>.+)$', - forms.operation_source_creation_wizard, + views.operation_source_creation_wizard, name='operation_source_creation'), url(r'operation_source_modification/(?P<step>.+)$', - forms.operation_source_modification_wizard, + views.operation_source_modification_wizard, name='operation_source_modification'), url(r'operation_source_deletion/(?P<step>.+)$', - forms.operation_source_deletion_wizard, + views.operation_source_deletion_wizard, name='operation_source_deletion'), ) diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 27ebd60e9..7866e2c66 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -24,6 +24,9 @@ from django.http import HttpResponse from django.shortcuts import render_to_response from ishtar_common.views import get_item, show_item, revert_item +from ishtar_common.wizards import SearchWizard +from wizards import * +from forms import * import models def autocomplete_operation(request, non_closed=True): @@ -76,11 +79,6 @@ get_operationsource = get_item(models.OperationSource, 'operation__operation_type':'operation__operation_type__pk', 'operation__year':'operation__year'}) -get_administrativeactfile = get_item(models.AdministrativeAct, - 'get_administrativeactfile', 'administrativeactfile', - extra_request_keys={'associated_file__towns':'associated_file__towns__pk', - 'operation__towns':'operation__towns__pk', - 'act_type__intented_to':'act_type__intented_to'}) get_administrativeactop = get_item(models.AdministrativeAct, 'get_administrativeactop', 'administrativeactop', extra_request_keys={'associated_file__towns':'associated_file__towns__pk', @@ -95,3 +93,117 @@ def dashboard_operation(request, dct, obj_id=None, *args, **kwargs): dct = {'dashboard': models.OperationDashboard()} return render_to_response('dashboard_operation.html', dct, context_instance=RequestContext(request)) + +operation_search_wizard = SearchWizard.as_view([ + ('general-operation_search', OperationFormSelection)], + url_name='operation_search',) + +operation_creation_wizard = OperationWizard.as_view([ + ('general-operation_creation', OperationFormGeneral), + ('preventive-operation_creation', OperationFormPreventive), + ('preventivediag-operation_creation', OperationFormPreventiveDiag), + ('townsgeneral-operation_creation', TownFormset), + ('towns-operation_creation', SelectedTownFormset), + ('parcelsgeneral-operation_creation', SelectedParcelGeneralFormSet), + ('parcels-operation_creation', SelectedParcelFormSet), + ('remains-operation_creation', RemainFormset), + ('periods-operation_creation', PeriodFormset), + ('final-operation_creation', FinalForm)], + condition_dict={ +'preventive-operation_creation':is_preventive('general-operation_creation', + models.OperationType, 'operation_type', 'prev_excavation'), +'preventivediag-operation_creation':is_preventive('general-operation_creation', + models.OperationType, 'operation_type', 'arch_diagnostic'), +'townsgeneral-operation_creation':has_associated_file( + 'general-operation_creation', negate=True), +'towns-operation_creation':has_associated_file('general-operation_creation'), +'parcelsgeneral-operation_creation':has_associated_file( + 'general-operation_creation', negate=True), +'parcels-operation_creation':has_associated_file('general-operation_creation'), + }, + url_name='operation_creation',) + +operation_modification_wizard = OperationModificationWizard.as_view([ + ('selec-operation_modification', OperationFormSelection), + ('general-operation_modification', OperationFormGeneral), + ('preventive-operation_modification', OperationFormPreventive), + ('preventivediag-operation_modification', OperationFormPreventiveDiag), + ('towns-operation_modification', SelectedTownFormset), + ('townsgeneral-operation_modification', TownFormset), + ('parcels-operation_modification', SelectedParcelFormSet), + ('parcelsgeneral-operation_modification', SelectedParcelGeneralFormSet), + ('remains-operation_modification', RemainFormset), + ('periods-operation_modification', PeriodFormset), + ('final-operation_modification', FinalForm)], + condition_dict={ +'preventive-operation_modification':is_preventive( + 'general-operation_modification', models.OperationType, + 'operation_type', 'prev_excavation'), +'preventivediag-operation_modification':is_preventive( + 'general-operation_modification', models.OperationType, + 'operation_type', 'arch_diagnostic'), +'townsgeneral-operation_modification':has_associated_file( + 'general-operation_modification', negate=True), +'towns-operation_modification':has_associated_file( + 'general-operation_modification'), +'parcelsgeneral-operation_modification':has_associated_file( + 'general-operation_modification', negate=True), +'parcels-operation_modification':has_associated_file( + 'general-operation_modification'), + }, + url_name='operation_modification',) + +operation_closing_wizard = OperationClosingWizard.as_view([ + ('selec-operation_closing', OperationFormSelection), + ('date-operation_closing', ClosingDateFormSelection), + ('final-operation_closing', FinalOperationClosingForm)], + url_name='operation_closing',) + +operation_deletion_wizard = OperationDeletionWizard.as_view([ + ('selec-operation_deletion', OperationFormSelection), + ('final-operation_deletion', OperationDeletionForm)], + url_name='operation_deletion',) + +operation_source_creation_wizard = OperationSourceWizard.as_view([ + ('selec-operation_source_creation', SourceOperationFormSelection), + ('source-operation_source_creation',OperationSourceForm), + ('authors-operation_source_creation', AuthorFormset), + ('final-operation_source_creation', FinalForm)], + url_name='operation_source_creation',) + +operation_source_modification_wizard = OperationSourceWizard.as_view([ + ('selec-operation_source_modification', OperationSourceFormSelection), + ('source-operation_source_modification', OperationSourceForm), + ('authors-operation_source_modification', AuthorFormset), + ('final-operation_source_modification', FinalForm)], + url_name='operation_source_modification',) + +operation_source_deletion_wizard = OperationSourceDeletionWizard.as_view([ + ('selec-operation_source_deletion', OperationSourceFormSelection), + ('final-operation_source_deletion', SourceDeletionForm)], + url_name='operation_source_deletion',) + +operation_administrativeactop_wizard = \ + OperationAdministrativeActWizard.as_view([ + ('selec-operation_administrativeactop', OperationFormSelection), + ('administrativeact-operation_administrativeactop', AdministrativeActOpeForm), + ('final-operation_administrativeactop', FinalForm)], + url_name='operation_administrativeactop',) + +operation_administrativeactop_modification_wizard = \ + OperationEditAdministrativeActWizard.as_view([ + ('selec-operation_administrativeactop_modification', + AdministrativeActOpeFormSelection), + ('administrativeact-operation_administrativeactop_modification', + AdministrativeActOpeForm), + ('final-operation_administrativeactop_modification', FinalForm)], + url_name='operation_administrativeactop_modification',) + +operation_administrativeactop_deletion_wizard = \ + AdministrativeActDeletionWizard.as_view([ + ('selec-operation_administrativeactop_deletion', + AdministrativeActOpeFormSelection), + ('final-operation_administrativeactop_deletion', + FinalAdministrativeActDeleteForm)], + url_name='operation_administrativeactop_deletion',) + diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py new file mode 100644 index 000000000..df785fe6e --- /dev/null +++ b/archaeological_operations/wizards.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.utils.translation import ugettext_lazy as _ + +from ishtar_common.wizards import Wizard, ClosingWizard, DeletionWizard, \ + SourceWizard +import models + +class OperationWizard(Wizard): + model = models.Operation + object_parcel_type = 'operation' + + def get_template(self, request, storage): + templates = super(OperationWizard, self).get_template(request, storage) + current_step = storage.get_current_step() or self.get_first_step( + request, storage) + if current_step.startswith('towns-'): + templates = ['towns_wizard.html'] + templates + return templates + + def get_extra_context(self, request, storage): + """ + Return extra context for templates + """ + context = super(OperationWizard, self).get_extra_context(request, + storage) + step = self.determine_step(request, storage) + if not step.startswith('towns-'): + return context + context['TOWNS'] = self.get_towns(request, storage) + return context + + def get_towns(self, request, storage): + """ + Obtention des villes disponibles + """ + general_form_key = 'general-' + self.url_name + towns = [] + file_id = self.session_get_value(request, storage, general_form_key, + "associated_file") + if file_id: + try: + for town in models.File.objects.get(pk=int(file_id) + ).towns.all(): + towns.append((town.pk, unicode(town))) + except (ValueError, ObjectDoesNotExist): + pass + return sorted(towns, key=lambda x:x[1]) + else: + return -1 + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Manage specifics fields + """ + if data: + data = data.copy() + else: + data = {} + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + general_form_key = 'general-' + self.url_name + # manage the dynamic choice of towns + if step.startswith('towns-') and hasattr(form, 'management_form'): + data['TOWNS'] = self.get_towns(request, storage) + elif step.startswith('parcels') and hasattr(form, 'management_form'): + file_id = self.session_get_value(request, storage, general_form_key, + "associated_file") + if file_id: + parcels = [] + try: + for parcel in models.File.objects.get(pk=int(file_id) + ).parcels.all(): + parcels.append((parcel.pk, parcel.short_label())) + except (ValueError, ObjectDoesNotExist): + pass + data['PARCELS'] = sorted(parcels, key=lambda x:x[1]) + else: + town_form_key = step.startswith('parcelsgeneral') \ + and 'townsgeneral-' or 'towns-' + town_form_key += self.url_name + town_ids = self.session_get_value(request, storage, + town_form_key, 'town', multi=True) or [] + towns = [] + for town_id in town_ids: + try: + town = models.Town.objects.get(pk=int(town_id)) + towns.append((town.pk, unicode(town))) + except (ValueError, ObjectDoesNotExist): + pass + data['TOWNS'] = sorted(towns, key=lambda x:x[1]) + data = data or None + form = super(OperationWizard, self).get_form(request, storage, step, + data, files) + return form + + def get_formated_datas(self, forms): + """ + Show a specific warning if no archaelogical file is provided + """ + datas = super(OperationWizard, self).get_formated_datas(forms) + # if the general town form is used the advertissement is pertinent + has_no_af = [form.prefix for form in forms + if form.prefix == 'townsgeneral-operation'] and True + if has_no_af: + datas = [[_(u"Warning: No Archaelogical File is provided. " + u"If you have forget it return to the first step."), []]]\ + + datas + return datas + +class OperationModificationWizard(OperationWizard): + modification = True + +class OperationClosingWizard(ClosingWizard): + model = models.Operation + fields = ['year', 'operation_code', 'operation_type', 'associated_file', +'in_charge', 'start_date', 'excavation_end_date', 'comment', 'towns', 'remains'] + +class OperationDeletionWizard(DeletionWizard): + model = models.Operation + fields = OperationClosingWizard.fields + +class OperationSourceWizard(SourceWizard): + model = models.OperationSource + def get_form_initial(self, request, storage, step): + initial = super(OperationSourceWizard, self).get_form_initial(request, + storage, step) + # put default index and operation_id field in the main source form + general_form_key = 'selec-' + self.url_name + if step.startswith('source-') \ + and self.session_has_key(request, storage, general_form_key): + gen_storage = request.session[storage.prefix]['step_data']\ + [general_form_key] + if general_form_key+"-operation" in gen_storage: + operation_id = int(gen_storage[general_form_key+"-operation"]) + elif general_form_key+"-pk" in gen_storage: + pk = int(gen_storage[general_form_key+"-pk"]) + try: + source = models.OperationSource.objects.get(pk=pk) + operation_id = source.operation.pk + except ObjectDoesNotExist: + pass + if operation_id: + initial['hidden_operation_id'] = operation_id + if 'index' not in initial: + max_val = models.OperationSource.objects.filter( + operation__pk=operation_id).aggregate( + Max('index'))["index__max"] + initial['index'] = max_val and (max_val + 1) or 1 + return initial + +class OperationSourceDeletionWizard(DeletionWizard): + model = models.OperationSource + fields = ['operation', 'title', 'source_type', 'authors',] + +class OperationAdministrativeActWizard(OperationWizard): + edit = False + + def get_extra_model(self, dct, request, storage, form_list): + dct['history_modifier'] = request.user + return dct + + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage) + + def save_model(self, dct, m2m, whole_associated_models, request, storage, + form_list, return_object): + associated_item = self.get_associated_item(request, storage, dct) + if not associated_item: + return self.render(request, storage, form_list[-1]) + if isinstance(associated_item, models.File): + dct['associated_file'] = associated_item + elif isinstance(associated_item, models.Operation): + dct['operation'] = associated_item + dct['history_modifier'] = request.user + if 'pk' in dct: + dct.pop('pk') + if self.edit: + admact = self.get_current_object(request, storage) + for k in dct: + if hasattr(admact, k): + setattr(admact, k, dct[k]) + else: + admact = models.AdministrativeAct(**dct) + admact.save() + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + return res + +class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard): + model = models.AdministrativeAct + edit = True + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage).operation + +class AdministrativeActDeletionWizard(ClosingWizard): + model = models.AdministrativeAct + fields = ['act_type', 'in_charge', 'operator', 'scientific', 'signatory', + 'operation', 'associated_file', 'signature_date', 'act_object',] + if settings.COUNTRY == 'fr': + fields += ['ref_sra'] + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + obj.delete() + return render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + +def is_preventive(form_name, model, type_key='operation_type', key=''): + def func(self, request, storage): + if storage.prefix not in request.session or \ + 'step_data' not in request.session[storage.prefix] or \ + form_name not in request.session[storage.prefix]['step_data'] or\ + form_name + '-' + type_key not in \ + request.session[storage.prefix]['step_data'][form_name]: + return False + try: + typ = int(request.session[storage.prefix]['step_data']\ + [form_name][form_name+'-'+type_key]) + return model.is_preventive(typ, key) + except ValueError: + return False + return func + diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py new file mode 100644 index 000000000..33b7ba116 --- /dev/null +++ b/archaeological_warehouse/forms.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +import datetime + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from ishtar_common.models import Person, valid_id +from archaeological_finds.models import TreatmentType +import models + +class ContainerSelect(forms.Form): + location = get_warehouse_field() + container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) + reference = forms.CharField(label=_(u"Reference")) + + def __init__(self, *args, **kwargs): + super(ContainerSelect, self).__init__(*args, **kwargs) + self.fields['container_type'].choices = \ + models.ContainerType.get_types() + self.fields['container_type'].help_text = \ + models.ContainerType.get_help() + +ContainerFormSelection = get_form_selection( + 'ContainerFormSelection', _(u"Container search"), 'container', + models.Container, ContainerSelect, 'get-container', + _(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} + 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) + + def __init__(self, *args, **kwargs): + super(BasePackagingForm, self).__init__(*args, **kwargs) + self.fields['treatment_type'].initial = \ + TreatmentType.objects.get(txt_idx='packaging').pk + +class ItemPackagingFormSelection(ItemMultipleFormSelection): + form_label = _(u"Packaged items") diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py index 914ee2533..903d77a59 100644 --- a/archaeological_warehouse/urls.py +++ b/archaeological_warehouse/urls.py @@ -20,14 +20,14 @@ from django.conf.urls.defaults import * """ -import forms +import views # forms urlpatterns = patterns('', url(r'treatment_creation/(?P<step>.+)$', - forms.treatment_creation_wizard, name='treatment_creation'), + views.treatment_creation_wizard, name='treatment_creation'), url(r'warehouse_packaging/(?P<step>.+)$', - forms.warehouse_packaging_wizard, name='warehouse_packaging'), + views.warehouse_packaging_wizard, name='warehouse_packaging'), ) urlpatterns += patterns('archaeological_warehouse.views', diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 16a8e19f5..78df71bc2 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -25,6 +25,8 @@ from django.shortcuts import render_to_response from ishtar_common.views import get_item, show_item, revert_item import models +from wizards import * +from forms import * get_container = get_item(models.Container, 'get_container', 'container', @@ -79,3 +81,17 @@ def autocomplete_container(request): 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([ + ('seleccontainer-packaging', ContainerFormSelection), + ('base-packaging', BasePackagingForm), + ('multiselecitems-packaging', ItemPackagingFormSelection), + ('final-packaging', FinalForm)], + url_name='warehouse_packaging',) + +""" +warehouse_packaging_wizard = ItemSourceWizard.as_view([ + ('selec-warehouse_packaging', ItemsSelection), + ('final-warehouse_packaging', FinalForm)], + url_name='warehouse_packaging',) +""" diff --git a/archaeological_warehouse/wizards.py b/archaeological_warehouse/wizards.py new file mode 100644 index 000000000..1e8455b94 --- /dev/null +++ b/archaeological_warehouse/wizards.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.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 + + +class PackagingWizard(TreatmentWizard): + def save_model(self, dct, m2m, whole_associated_models, request, storage, + form_list, return_object): + dct = self.get_extra_model(dct, request, storage, form_list) + obj = self.get_current_saved_object(request, storage) + dct['location'] = dct['container'].location + items = dct.pop('items') + treatment = Treatment(**dct) + treatment.save() + if not hasattr(items, '__iter__'): + items = [items] + for item in items: + new = item.duplicate(request.user) + item.downstream_treatment = treatment + item.save() + new.upstream_treatment = treatment + new.container = dct['container'] + new.save() + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + return return_object and (obj, res) or res diff --git a/example_project/urls.py b/example_project/urls.py index 02936e6df..e4247b922 100644 --- a/example_project/urls.py +++ b/example_project/urls.py @@ -10,18 +10,20 @@ admin.autodiscover() urlpatterns = patterns('', (r'^accounts/', include('registration.urls')), (r'^admin/', include(admin.site.urls)), - ('', include('ishtar_common.urls')), ) -""" -for app in ['archaeological_files', 'archaeological_operations', +APP_LIST = ['archaeological_files', 'archaeological_operations', 'archaeological_context_records', 'archaeological_warehouse', - 'archaeological_finds']: + 'archaeological_finds'] +APP_LIST = ['archaeological_files'] +for app in APP_LIST: if app in settings.INSTALLED_APPS: - urlpatterns = patterns('', + urlpatterns += patterns('', ('', include(app+'.urls')), ) -""" +urlpatterns += patterns('', + ('', include('ishtar_common.urls')), +) urlpatterns += patterns('ishtar_common.views', url(r'$', 'index', name='start'), diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 62f51fa08..d66d6d4cc 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -101,120 +101,16 @@ class FormSet(BaseFormSet): form.fields[DELETION_FIELD_NAME].label = '' form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget() -''' -class SearchWizard(NamedUrlSessionFormWizard): - model = None - - def get_wizard_name(self): - """ - As the class name can interfere when reused, use the url_name - """ - return self.url_name - - def get_template(self, request, storage): - templates = ['search.html'] - return templates - def get_now(): format = formats.get_format('DATE_INPUT_FORMATS')[0] value = datetime.datetime.now().strftime(format) return value -class DeletionWizard(Wizard): - def get_formated_datas(self, forms): - datas = super(DeletionWizard, self).get_formated_datas(forms) - self.current_obj = None - for form in forms: - if not hasattr(form, "cleaned_data"): - continue - for key in form.cleaned_data: - if key == 'pk': - model = form.associated_models['pk'] - self.current_obj = model.objects.get(pk=form.cleaned_data['pk']) - if not self.current_obj: - return datas - res = {} - for field in self.model._meta.fields + self.model._meta.many_to_many: - if field.name not in self.fields: - continue - value = getattr(self.current_obj, field.name) - if not value: - continue - if hasattr(value, 'all'): - value = ", ".join([unicode(item) for item in value.all()]) - if not value: - continue - else: - value = unicode(value) - res[field.name] = (field.verbose_name, value, '') - if not datas and self.fields: - datas = [['', []]] - for field in self.fields: - if field in res: - datas[0][1].append(res[field]) - return datas - - def done(self, request, storage, form_list, **kwargs): - obj = self.get_current_object(request, storage) - obj.delete() - return render_to_response('wizard_delete_done.html', {}, - context_instance=RequestContext(request)) - class ClosingDateFormSelection(forms.Form): form_label = _("Closing date") end_date = forms.DateField(label=_(u"Closing date"), widget=widgets.JQueryDate) -class ClosingWizard(Wizard): - # "close" an item - # to be define in the overloaded class - model = None - fields = [] - - def get_formated_datas(self, forms): - datas = super(ClosingWizard, self).get_formated_datas(forms) - self.current_obj = None - for form in forms: - if not hasattr(form, "cleaned_data"): - continue - for key in form.cleaned_data: - if key == 'pk': - model = form.associated_models['pk'] - self.current_obj = model.objects.get( - pk=form.cleaned_data['pk']) - if not self.current_obj: - return datas - res = {} - for field in self.model._meta.fields + self.model._meta.many_to_many: - if field.name not in self.fields: - continue - value = getattr(self.current_obj, field.name) - if not value: - continue - if hasattr(value, 'all'): - value = ", ".join([unicode(item) for item in value.all()]) - if not value: - continue - else: - value = unicode(value) - res[field.name] = (field.verbose_name, value, '') - if not datas and self.fields: - datas = [['', []]] - for field in self.fields: - if field in res: - datas[0][1].append(res[field]) - return datas - - def done(self, request, storage, form_list, **kwargs): - obj = self.get_current_object(request, storage) - for form in form_list: - if form.is_valid(): - if 'end_date' in form.cleaned_data and hasattr(obj, 'end_date'): - obj.end_date = form.cleaned_data['end_date'] - obj.save() - return render_to_response('wizard_closing_done.html', {}, - context_instance=RequestContext(request)) - 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")): @@ -246,4 +142,3 @@ def get_form_selection(class_name, label, key, model, base_form, get_url, return cleaned_data attrs['clean'] = clean return type(class_name, (forms.Form,), attrs) -''' diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index d3ae65d55..ccae0b6d2 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -268,16 +268,6 @@ TownFormset.form_label = _("Towns") ###################### # Sources management # ###################### -''' -class SourceWizard(Wizard): - model = None - def get_extra_model(self, dct, request, storage, form_list): - dct = super(SourceWizard, self).get_extra_model(dct, request, storage, - form_list) - if 'history_modifier' in dct: - dct.pop('history_modifier') - return dct -''' class SourceForm(forms.Form): form_label = _(u"Documentation informations") associated_models = {'source_type':models.SourceType} diff --git a/ishtar_common/menus.py b/ishtar_common/menus.py index 008220373..7804d73e4 100644 --- a/ishtar_common/menus.py +++ b/ishtar_common/menus.py @@ -38,18 +38,15 @@ for app in settings.INSTALLED_APPS: # sort __section_items = [menu for order, menu in sorted(_extra_menus, key=lambda x:x[0])] -print __section_items # regroup menus _section_items, __keys = [], [] for section_item in __section_items: - print section_item if section_item.idx not in __keys: __keys.append(section_item.idx) _section_items.append(section_item) continue _section_items[_section_items.index(section_item.idx)].childs.append( section_item.childs) -print _section_items """ SectionItem('dashboard', _(u"Dashboard"), childs=[ diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 69fa8b90b..4f010d866 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -33,7 +33,6 @@ import ho.pisa as pisa from django.conf import settings from django.contrib.auth import logout -from django.contrib.formtools.wizard.views import NamedUrlWizardView from django.core import serializers from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse, NoReverseMatch @@ -55,6 +54,7 @@ import forms_main as ishtar_forms from ishtar_common.forms import FinalForm from ishtar_common.forms_common import PersonForm, PersonFormSelection,\ AccountForm, FinalAccountForm +from ishtar_common.wizards import PersonWizard, PersonModifWizard, AccountWizard import models CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} @@ -74,657 +74,12 @@ def index(request): return render_to_response('index.html', dct, context_instance=RequestContext(request)) -class Wizard(NamedUrlWizardView): - model = None - label = '' - modification = None # True when the wizard modify an item - storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage' - - @staticmethod - def _check_right(step, condition=True): - '''Return a method to check the right for a specific step''' - """ - def check_right(self, request, storage): - cond = condition - if callable(condition): - cond = condition(self, request, storage) - if not cond: - return False - person_type = request.user.ishtaruser.person.person_type - if person_type.txt_idx == 'administrator': - return True - if person_type.rights.filter(url_name=step).count(): - return True""" - def check_right(self): - cond = condition - if callable(condition): - cond = condition(self) - if not cond: - return False - if not hasattr(self.request.user, 'ishtaruser'): - return False - person_type = self.request.user.ishtaruser.person.person_type - if person_type.txt_idx == 'administrator': - return True - if person_type.rights.filter(url_name=step).count(): - return True - return check_right - - def __init__(self, *args, **kwargs): - """Check right for each step of the wizard""" - print "2" - super(Wizard, self).__init__(*args, **kwargs) - for form_key in self.form_list.keys()[:-1]: - condition = True - if form_key in self.condition_dict: - condition = self.condition_dict.get(form_key, True) - cond = self._check_right(form_key, condition) - self.condition_dict[form_key] = cond - """ - for form_key in self.form_list.keys()[:-1]: - condition = True - if form_key in self.condition_list: - condition = self.condition_list.get(form_key, True) - cond = self._check_right(form_key, condition) - self.condition_list[form_key] = cond""" - - def get_prefix(self, *args, **kwargs): - """As the class name can interfere when reused prefix with the url_name - """ - print "3" - return self.url_name + super(Wizard, self).get_prefix(*args, - **kwargs) - - def get_wizard_name(self): - """As the class name can interfere when reused, use the url_name""" - print "4" - return self.url_name - - def get_template_names(self): - print "5" - templates = ['ishtar/wizard/default_wizard.html'] - current_step = self.steps.current - if current_step == self.steps.last: - templates = ['ishtar/wizard/confirm_wizard.html'] + templates - return templates - - def get_context_data(self, form, **kwargs): - """Add previous, next and current steps to manage the wizard path""" - print "6" - context = super(Wizard, self).get_context_data(form) - self.request.session['CURRENT_ACTION'] = self.get_wizard_name() - step = self.steps.first - current_step = self.steps.current - context.update({'current_step':self.form_list[current_step], - 'wizard_label':self.label}) - if step == current_step: - return context - previous_steps, next_steps, previous_step_counter = [], [], 0 - while step: - if step == current_step \ - or (previous_steps and - previous_steps[-1] == self.form_list[step]): - break - previous_steps.append(self.form_list[step]) - previous_step_counter += 1 - if previous_step_counter >= len(self.steps): - break - step = self.steps.all[previous_step_counter] - context.update({'previous_steps':previous_steps, - 'previous_step_counter':previous_step_counter}) - storage = self.storage - # if modification: show the next steps - if self.modification: - next_step = step - while next_step: - # check if the form is initialized otherwise initialize it - if not storage.get_step_data(next_step): - values = self.get_form_initial(next_step) - prefixed_values = {} - if not isinstance(values, list): - for key in values: - form_key = next_step + '-' + key - prefixed_values[form_key] = values[key] - else: - for formset_idx, v in enumerate(values): - prefix = u"-%d-" % formset_idx - for key in v: - form_key = next_step + prefix + key - prefixed_values[form_key] = v[key] - storage.set_step_data(next_step, prefixed_values) - if step != next_step: # if not current step - next_steps.append(self.form_list[next_step]) - next_step = self.get_next_step(next_step) - context.update({'next_steps':next_steps}) - # not last step: validation - if current_step != self.steps.last: - return context - final_form_list = [] - for form_key in self.get_form_list().keys(): - form_obj = self.get_form(step=form_key, - data=self.storage.get_step_data(form_key), - files=self.storage.get_step_files(form_key)) - form_obj.is_valid() - final_form_list.append(form_obj) - last_form = final_form_list[-1] - context.update({'datas':self.get_formated_datas(final_form_list)}) - if hasattr(last_form, 'confirm_msg'): - context.update({'confirm_msg':last_form.confirm_msg}) - if hasattr(last_form, 'confirm_end_msg'): - context.update({'confirm_end_msg':last_form.confirm_end_msg}) - return context - - def get_formated_datas(self, forms): - """Get the data to present in the last page""" - print "7" - datas = [] - for form in forms: - form_datas = [] - base_form = hasattr(form, 'forms') and form.forms[0] or form - associated_models = hasattr(base_form, 'associated_models') and \ - base_form.associated_models or {} - if not hasattr(form, 'cleaned_data') and hasattr(form, 'forms'): - cleaned_datas = [frm.cleaned_data for frm in form.forms - if frm.is_valid()] - if not cleaned_datas: - continue - elif not hasattr(form, 'cleaned_data'): - continue - else: - cleaned_datas = type(form.cleaned_data) == list and \ - form.cleaned_data \ - or [form.cleaned_data] - for cleaned_data in cleaned_datas: - if not cleaned_data: - continue - if form_datas: - form_datas.append(("", "", "spacer")) - items = hasattr(base_form, 'fields') and \ - base_form.fields.keyOrder or cleaned_data.keys() - for key in items: - lbl = None - if key.startswith('hidden_'): - continue - if hasattr(base_form, 'fields') and key in base_form.fields: - lbl = base_form.fields[key].label - if hasattr(base_form, 'associated_labels') \ - and key in base_form.associated_labels: - lbl = base_form.associated_labels[key] - if not lbl: - continue - value = cleaned_data[key] - if not value and value != False: - continue - if type(value) == bool: - if value == True: - value = _(u"Yes") - elif value == False: - value = _(u"No") - elif key in associated_models: - values = [] - if "," in unicode(value): - values = unicode(value).split(",") - else: - values = [value] - rendered_values = [] - for val in values: - item = associated_models[key].objects.get(pk=val) - if hasattr(item, 'short_label'): - value = item.short_label() - else: - value = unicode(item) - rendered_values.append(value) - value = u" ; ".join(rendered_values) - form_datas.append((lbl, value, '')) - if form_datas: - datas.append((form.form_label, form_datas)) - return datas - - def get_extra_model(self, dct, form_list): - print "8" - dct['history_modifier'] = self.request.user - return dct - - def done(self, form_list, return_object=False, **kwargs): - """Save to the model""" - print "9" - dct, m2m, whole_associated_models = {}, [], [] - for form in form_list: - if not form.is_valid(): - return self.render(form) - base_form = hasattr(form, 'forms') and form.forms[0] or form - associated_models = hasattr(base_form, 'associated_models') and \ - base_form.associated_models or {} - if hasattr(form, 'forms'): - multi = False - if form.forms: - frm = form.forms[0] - if hasattr(frm, 'base_model') and frm.base_model: - whole_associated_models.append(frm.base_model) - else: - whole_associated_models += associated_models.keys() - fields = frm.fields.copy() - if 'DELETE' in fields: - fields.pop('DELETE') - multi = len(fields) > 1 - if multi: - assert hasattr(frm, 'base_model'), \ - u"Must define a base_model for " + unicode(frm.__class__) - for frm in form.forms: - if not frm.is_valid(): - continue - vals = {} - if "DELETE" in frm.cleaned_data: - if frm.cleaned_data["DELETE"]: - continue - frm.cleaned_data.pop('DELETE') - for key in frm.cleaned_data: - value = frm.cleaned_data[key] - if not value and value != False: - continue - if key in associated_models: - value = associated_models[key].objects.get(pk=value) - if multi: - vals[key] = value - else: - m2m.append((key, value)) - if multi and vals: - m2m.append((frm.base_model, vals)) - elif type(form.cleaned_data) == dict: - for key in form.cleaned_data: - if key.startswith('hidden_'): - continue - value = form.cleaned_data[key] - if key in associated_models: - if value: - model = associated_models[key] - if isinstance(value, unicode) \ - or isinstance(value, str) and "," in value: - value = value.split(",") - if isinstance(value, list) \ - or isinstance(value, tuple): - value = [model.objects.get(pk=val) - for val in value if val] - if len(value) == 1: - value = value[0] - else: - value = model.objects.get(pk=value) - else: - value = None - dct[key] = value - return self.save_model(dct, m2m, whole_associated_models, form_list, - return_object) - - def get_saved_model(self): - """Permit a distinguo when saved model is not the base selected model""" - print "10" - return self.model - - def get_current_saved_object(self): - """Permit a distinguo when saved model is not the base selected model""" - print "11" - return self.get_current_object() - - def save_model(self, dct, m2m, whole_associated_models, form_list, - return_object): - print "12" - dct = self.get_extra_model(dct, form_list) - obj = self.get_current_saved_object() - # manage dependant items - other_objs = {} - for k in dct.keys(): - if '__' not in k: - continue - vals = k.split('__') - assert len(vals) == 2, "Only one level of dependant item is managed" - dependant_item, key = vals - if dependant_item not in other_objs: - other_objs[dependant_item] = {} - other_objs[dependant_item][key] = dct.pop(k) - if obj: - for k in dct: - if k.startswith('pk'): - continue - setattr(obj, k, dct[k]) - try: - obj.full_clean() - except forms.ValidationError, msg: - return self.render(form_list[-1]) - for dependant_item in other_objs: - c_item = getattr(obj, dependant_item) - # manage ManyToMany if only one associated - if hasattr(c_item, "all"): - c_items = c_item.all() - if len(c_items) != 1: - continue - c_item = c_items[0] - if c_item: - # to check # - for k in other_objs[dependant_item]: - setattr(c_item, k, other_objs[dependant_item][k]) - c_item.save() - else: - m = getattr(self.model, dependant_item) - if hasattr(m, 'related'): - c_item = m.related.model(**other_objs[dependant_item]) - setattr(obj, dependant_item, c_item) - obj.save() - obj.save() - else: - adds = {} - for dependant_item in other_objs: - m = getattr(self.model, dependant_item) - model = m.field.rel.to - c_dct = other_objs[dependant_item].copy() - if issubclass(model, models.BaseHistorizedItem): - c_dct['history_modifier'] = self.request.user - c_item = model(**c_dct) - c_item.save() - if hasattr(m, 'through'): - adds[dependant_item] = c_item - elif hasattr(m, 'field'): - dct[dependant_item] = c_item - if 'pk' in dct: - dct.pop('pk') - obj = self.get_saved_model()(**dct) - try: - obj.full_clean() - except forms.ValidationError, msg: - return self.render(form_list[-1]) - obj.save() - for k in adds: - getattr(obj, k).add(adds[k]) - # necessary to manage interaction between models like - # material_index management for baseitems - obj.save() - m2m_items = {} - for model in whole_associated_models: - getattr(obj, model+'s').clear() - for key, value in m2m: - if key not in m2m_items: - if type(key) == dict: - vals = [] - for item in getattr(obj, key+'s').all(): - v = {} - for k in value.keys(): - v[k] = getattr(item, k) - vals.append(v) - m2m_items[key] = vals - else: - m2m_items[key] = getattr(obj, key+'s').all() - if value not in m2m_items[key]: - if type(value) == dict: - model = getattr(obj, key+'s').model - if issubclass(model, models.BaseHistorizedItem): - value['history_modifier'] = self.request.user - value = model.objects.create(**value) - value.save() - getattr(obj, key+'s').add(value) - # necessary to manage interaction between models like - # material_index management for baseitems - obj.save() - res = render_to_response('wizard_done.html', {}, - context_instance=RequestContext(self.request)) - return return_object and (obj, res) or res - - def get_deleted(self, keys): - """Get the deleted and non-deleted items in formsets""" - print "13" - not_to_delete, to_delete = set(), set() - for key in keys: - items = key.split('-') - if len(items) < 2 or items[-2] in to_delete: - continue - idx = items[-2] - try: - int(idx) - except: - continue - if items[-1] == u'DELETE': - to_delete.add(idx) - if idx in not_to_delete: - not_to_delete.remove(idx) - elif idx not in not_to_delete: - not_to_delete.add(idx) - return (to_delete, not_to_delete) - - def get_form(self, step=None, data=None, files=None): - """Manage formset""" - print "14" - request = self.request - storage = self.storage - if data: - data = data.copy() - if not step: - step = self.steps.current - form = self.get_form_list()[step] - if hasattr(form, 'management_form'): - # manage deletion - to_delete, not_to_delete = self.get_deleted(data.keys()) - # raz deleted fields - for key in data.keys(): - items = key.split('-') - if len(items) < 2 or items[-2] not in to_delete: - continue - data.pop(key) - if to_delete: - # reorganize - for idx, number in enumerate(sorted(not_to_delete)): - idx = unicode(idx) - if idx == number: - continue - for key in data.keys(): - items = key.split('-') - if len(items) > 2 and number == items[-2]: - items[-2] = unicode(idx) - k = u'-'.join(items) - data[k] = data.pop(key)[0] - # get a form key - base_key = form.form.base_fields.keys()[0] - init = self.get_form_initial(request, storage, step) - total_field = len([key for key in data.keys() - if base_key in key.split('-') - and data[key]]) - if init and not to_delete: - total_field = max((total_field, len(init))) - data[step + u'-INITIAL_FORMS'] = unicode(total_field) - data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1) - data = data or None - form = super(Wizard, self).get_form(step, data, files) - return form - - def render_next_step(self, form, **kwargs): - """ - Manage: - - modify or delete button in formset: next step = current step - - validate and end: nextstep = last step - """ - print "15" - request = self.request - if request.POST.has_key('formset_modify') \ - and request.POST['formset_modify'] \ - or [key for key in request.POST.keys() - if key.endswith('DELETE') and request.POST[key]]: - return self.render(form) - elif request.POST.has_key('validate_and_end') \ - and request.POST['validate_and_end']: - last_step = self.steps.last - new_form = self.get_form(last_step, - data=self.storage.get_step_data(last_step), - files=self.storage.get_step_files(last_step)) - self.storage.current_step = last_step - return self.render(new_form) - return super(Wizard, self).render_next_step(form, **kwargs) - - def post(self, *args, **kwargs): - """Convert numerical step number to step name""" - print "16" - request = self.request - post_data = request.POST.copy() - if request.POST.has_key('form_prev_step'): - try: - step_number = int(request.POST['form_prev_step']) - post_data['wizard_goto_step'] = self.get_form_list().keys( - )[step_number] - except ValueError: - pass - request.POST = post_data - return super(Wizard, self).post(*args, **kwargs) - - @classmethod - def session_has_key(cls, request, storage, form_key, key=None, multi=None): - """Check if the session has value of a specific form and (if provided) - of a key - """ - print "17" - test = storage.prefix in request.session \ - and 'step_data' in request.session[storage.prefix] \ - and form_key in request.session[storage.prefix]['step_data'] - if not key or not test: - return test - key = key.startswith(form_key) and key or \ - not multi and form_key + '-' + key or \ - form_key + '-0-' + key #only check if the first field is available - return key in request.session[storage.prefix]['step_data'][form_key] - - @classmethod - def session_get_value(cls, request, storage, form_key, key, multi=False): - """Get the value of a specific form""" - print "18" - if not cls.session_has_key(request, storage, form_key, key, multi): - return - if not multi: - key = key.startswith(form_key) and key or form_key + '-' + key - return request.session[storage.prefix]['step_data'][form_key][key] - vals = [] - for k in request.session[storage.prefix]['step_data'][form_key]: - if k.startswith(form_key) and k.endswith(key) and \ - request.session[storage.prefix]['step_data'][form_key][k]: - vals.append(request.session[storage.prefix]['step_data']\ - [form_key][k]) - return vals - - def get_current_object(self): - """Get the current object for an instancied wizard""" - print "19" - current_obj = None - main_form_key = 'selec-' + self.url_name - try: - idx = self.session_get_value(self.request, self.storage, - main_form_key, 'pk') - if type(idx) in (tuple, list): - idx = idx[0] - idx = int(idx) - current_obj = self.model.objects.get(pk=idx) - except(TypeError, ValueError, ObjectDoesNotExist): - pass - return current_obj - - def get_form_initial(self, step): - print "20" - current_obj = self.get_current_object() - current_step = self.steps.current - request = self.request - if step.startswith('selec-') and step in self.form_list \ - and 'pk' in self.form_list[step].associated_models: - model_name = self.form_list[step].associated_models['pk' - ].__name__.lower() - if step == current_step: - #self.reset_wizard(request, storage) - self.storage.reset() - val = model_name in request.session and request.session[model_name] - if val: - return {'pk':val} - elif current_obj: - return self.get_instanced_init(current_obj, step) - current_form = self.form_list[current_step] - if hasattr(current_form, 'currents'): - initial = {} - for key in current_form.currents: - model_name = current_form.currents[key].__name__.lower() - val = model_name in request.session and \ - request.session[model_name] - if val: - initial[key] = val - if initial: - return initial - return super(Wizard, self).get_form_initial(step) - - def get_instanced_init(self, obj, step=None): - """Get initial data from an init""" - print "21" - current_step = step or self.steps.current - c_form = self.form_list[current_step] - # make the current object the default item for the session - obj_name = obj.__class__.__name__.lower() - # prefer a specialized name if available - prefixes = self.storage.prefix.split('_') - if len(prefixes) > 1 and prefixes[-2].startswith(obj_name): - obj_name = prefixes[-2] - self.request.session[obj_name] = unicode(obj.pk) - initial = {} - if self.request.POST or \ - (step in self.request.session[self.storage.prefix] and\ - self.request.session[self.storage.prefix]['step_data'][step]): - return {} - if hasattr(c_form, 'base_fields'): - for base_field in c_form.base_fields.keys(): - fields = base_field.split('__') - value = obj - for field in fields: - if not hasattr(value, field) or \ - getattr(value, field) == None: - value = obj - break - value = getattr(value, field) - if value == obj: - continue - if hasattr(value, 'pk'): - value = value.pk - if value in (True, False): - initial[base_field] = value - elif value != None: - initial[base_field] = unicode(value) - elif hasattr(c_form, 'management_form'): - initial = [] - if hasattr(c_form.form, 'base_model'): - key = c_form.form.base_model + 's' - else: - key = current_step.split('-')[0] - if not hasattr(obj, key): - return initial - keys = c_form.form.base_fields.keys() - for child_obj in getattr(obj, key).order_by('pk').all(): - if not keys: - break - vals = {} - if len(keys) == 1: - # only one field: must be the id of the object - vals[keys[0]] = unicode(child_obj.pk) - else: - for field in keys: - if hasattr(child_obj, field): - value = getattr(child_obj, field) - if hasattr(value, 'pk'): - value = value.pk - if value != None: - vals[field] = unicode(value) - if vals: - initial.append(vals) - return initial - -class PersonWizard(Wizard): - model = models.Person - person_creation_wizard = PersonWizard.as_view([ ('identity-person_creation', PersonForm), ('final-person_creation', FinalForm)], label=_(u"Person creation"), url_name='person_creation') -class PersonModifWizard(PersonWizard): - modification = True - person_modification_wizard = PersonModifWizard.as_view([ ('selec-person_modification', PersonFormSelection), ('identity-person_modification', PersonForm), @@ -732,89 +87,6 @@ person_modification_wizard = PersonModifWizard.as_view([ label=_(u"Person modification"), url_name='person_modification') -class AccountWizard(Wizard): - model = models.Person - def get_formated_datas(self, forms): - datas = super(AccountWizard, self).get_formated_datas(forms) - for form in forms: - if not hasattr(form, "cleaned_data"): - continue - for key in form.cleaned_data: - if key == 'hidden_password' and form.cleaned_data[key]: - datas[-1][1].append((_("New password"), "*"*8)) - return datas - - def done(self, form_list, **kwargs): - """ - Save the account - """ - dct = {} - for form in form_list: - if not form.is_valid(): - return self.render(form) - associated_models = hasattr(form, 'associated_models') and \ - form.associated_models or {} - if type(form.cleaned_data) == dict: - for key in form.cleaned_data: - if key == 'pk': - continue - value = form.cleaned_data[key] - if key in associated_models and value: - value = associated_models[key].objects.get(pk=value) - dct[key] = value - person = self.get_current_object() - if not person: - return self.render(form) - for key in dct.keys(): - if key.startswith('hidden_password'): - dct['password'] = dct.pop(key) - try: - account = models.IshtarUser.objects.get(person=person) - account.username = dct['username'] - account.email = dct['email'] - except ObjectDoesNotExist: - now = datetime.datetime.now() - account = models.IshtarUser(person=person, username=dct['username'], - email=dct['email'], first_name=person.surname, - last_name=person.name, is_staff=False, is_active=True, - is_superuser=False, last_login=now, date_joined=now) - if dct['password']: - account.set_password(dct['password']) - account.save() - - if 'send_password' in dct and dct['send_password'] and \ - settings.ADMINS: - site = Site.objects.get_current() - - app_name = site and ("Ishtar - " + site.name) \ - or "Ishtar" - context = Context({'login':dct['username'], - 'password':dct['password'], - 'app_name':app_name, - 'site': site and site.domain or "" - }) - t = loader.get_template('account_activation_email.txt') - msg = t.render(context) - subject = _(u"[%(app_name)s] Account creation/modification") % { - "app_name":app_name} - send_mail(subject, msg, settings.ADMINS[0][1], - [dct['email']], fail_silently=True) - res = render_to_response('wizard_done.html', {}, - context_instance=RequestContext(self.request)) - return res - - def get_form(self, step=None, data=None, files=None): - """ - Display the "Send email" field if necessary - """ - form = super(AccountWizard, self).get_form(step, data, files) - if not hasattr(form, 'is_hidden'): - return form - if self.session_get_value(self.request, self.storage, - 'account-account_management', 'hidden_password'): - form.is_hidden = False - return form - account_management_wizard = AccountWizard.as_view([ ('selec-account_management', PersonFormSelection), ('account-account_management', AccountForm), |