diff options
author | Étienne Loks <etienne.loks@peacefrogs.net> | 2011-01-14 01:17:05 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2011-01-14 01:17:05 +0100 |
commit | dc3dd6ffd4be05b613a4bbba56e907b7ca2dea02 (patch) | |
tree | b7fe8f621f6165f8b7a5cdb28fa2e1052d9e5e6b | |
parent | f6d282bd88ef69501b0a01791e7a1eee22cb1a5b (diff) | |
download | Ishtar-dc3dd6ffd4be05b613a4bbba56e907b7ca2dea02.tar.bz2 Ishtar-dc3dd6ffd4be05b613a4bbba56e907b7ca2dea02.zip |
Implementation of operation creation (refs #16)
-rw-r--r-- | ishtar/furnitures/admin.py | 6 | ||||
-rw-r--r-- | ishtar/furnitures/forms.py | 195 | ||||
-rw-r--r-- | ishtar/furnitures/menus.py | 9 | ||||
-rw-r--r-- | ishtar/furnitures/models.py | 34 | ||||
-rw-r--r-- | ishtar/furnitures/urls.py | 5 | ||||
-rw-r--r-- | ishtar/furnitures/views.py | 6 |
6 files changed, 228 insertions, 27 deletions
diff --git a/ishtar/furnitures/admin.py b/ishtar/furnitures/admin.py index b7821fb43..980349520 100644 --- a/ishtar/furnitures/admin.py +++ b/ishtar/furnitures/admin.py @@ -69,9 +69,9 @@ class FileAdmin(HistorizedObjectAdmin): admin.site.register(models.File, FileAdmin) class OperationAdmin(HistorizedObjectAdmin): - list_display = ['name', 'operation_code', 'start_date', 'end_date', + list_display = ['year', 'operation_code', 'start_date', 'end_date', 'operation_type'] - list_filter = ("operation_type",) + list_filter = ("year", "operation_type",) search_fields = ['towns__name', 'operation_code'] if settings.COUNTRY == 'fr': list_display += ['code_patriarche'] @@ -197,7 +197,7 @@ basic_models = [models.PersonType, models.IshtarUser, models.FileType, models.OperationType, models.DatingType, models.DatingQuality, models.SourceType, models.MaterialType, models.ParcelOwner, models.WarehouseType, models.ActType, models.AuthorType, - models.OrganizationType, models.TreatmentType] + models.OrganizationType, models.TreatmentType, models.RemainType] if settings.COUNTRY == 'fr': basic_models += [models.Arrondissement, models.Canton, models.SaisineType] diff --git a/ishtar/furnitures/forms.py b/ishtar/furnitures/forms.py index 8d5ee6c91..5abfe90f9 100644 --- a/ishtar/furnitures/forms.py +++ b/ishtar/furnitures/forms.py @@ -133,11 +133,11 @@ class Wizard(NamedUrlSessionFormWizard): if not lbl: continue value = cleaned_data[key] + if not value: + continue if key in associated_models: value = unicode(associated_models[key].objects.get( pk=value)) - if not value: - continue form_datas.append((lbl, value, '')) if form_datas: datas.append((form.form_label, form_datas)) @@ -167,10 +167,14 @@ class Wizard(NamedUrlSessionFormWizard): # datas not managed continue value = frm.cleaned_data[key] + if not value: + continue value = associated_models[key].objects.get(pk=value) m2m.append((key, value)) 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: value = associated_models[key].objects.get(pk=value) @@ -292,12 +296,12 @@ class Wizard(NamedUrlSessionFormWizard): def get_form_initial(self, request, storage, step): current_obj = self.get_current_object(request, storage) + current_step = storage.get_current_step() or self.get_first_step( + request, storage) 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() - current_step = storage.get_current_step() or self.get_first_step( - request, storage) if step == current_step: self.reset_wizard(request, storage) val = model_name in request.session and request.session[model_name] @@ -306,6 +310,17 @@ class Wizard(NamedUrlSessionFormWizard): elif current_obj: return self.get_instanced_init(current_obj, request, storage, 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(request, storage, step) def get_instanced_init(self, obj, request, storage, step): @@ -353,7 +368,7 @@ class FileWizard(Wizard): def get_form(self, request, storage, step=None, data=None, files=None): """ - Manage formset + Manage towns """ if data: data = data.copy() @@ -385,7 +400,6 @@ class FileWizard(Wizard): def get_extra_model(self, dct, request, storage, form_list): dct = super(FileWizard, self).get_extra_model(dct, request, storage, form_list) - models.File.objects.filter(year=dct['year']) 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 @@ -432,6 +446,7 @@ def get_now(): class FileFormSelection(forms.Form): form_label = _("Archaelogical file") associated_models = {'pk':models.File} + currents = {'pk':models.File} pk = forms.IntegerField(label=_("References/location"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), associated_model=models.File), @@ -497,6 +512,8 @@ class TownFormSet(FormSet): towns = [] for i in range(0, self.total_form_count()): form = self.forms[i] + if not form.is_valid(): + continue if 'town' not in form.cleaned_data: continue town = form.cleaned_data['town'] @@ -618,3 +635,169 @@ file_modification_wizard = FileWizard([ 'preventive-file_modification':is_preventive('general-file_modification') }, url_name='file_modification',) + +class OperationWizard(Wizard): + model = models.Operation + + 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] + + # put hidden year field + general_form_key = 'general-' + self.url_name + if not data and step.startswith('refs-') \ + and storage.prefix in request.session \ + and 'step_data' in request.session[storage.prefix] \ + and general_form_key in request.session[storage.prefix]['step_data']: + prefix = 'refs-' + self.url_name + year = int(request.session[storage.prefix]['step_data']\ + [general_form_key][general_form_key+"-year"]) + data[prefix+'-hidden_year'] = year + max_val = models.Operation.objects.filter(year=year).aggregate( + Max('operation_code'))["operation_code__max"] + data[prefix+'-operation_code'] = max_val and (max_val + 1) or 1 + if step.startswith('towns-') and hasattr(form, 'management_form') \ + and storage.prefix in request.session \ + and 'step_data' in request.session[storage.prefix] \ + and general_form_key in request.session[storage.prefix]['step_data']: + towns = [] + try: + file_id = int(request.session[storage.prefix]['step_data']\ + [general_form_key][general_form_key+"-associated_file"]) + for town in models.File.objects.get(pk=file_id).towns.all(): + towns.append((town.pk, unicode(town))) + except (ValueError, ObjectDoesNotExist): + pass + if not data: + # by default fill with all towns + data['towns'] = towns + 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 + + + +class OperationFormGeneral(forms.Form): + form_label = _("General") + associated_models = {'in_charge':models.Person, + 'associated_file':models.File, + 'operation_type':models.OperationType} + currents = {'associated_file':models.File} + in_charge = forms.IntegerField(label=_("Person in charge of the operation"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', + args=[models.PersonType.objects.get(txt_idx='head_scientist').pk]), + associated_model=models.Person), + validators=[models.valid_id(models.Person)]) + associated_file = forms.IntegerField(label=_("Archaelogical file"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), + associated_model=models.File), + validators=[models.valid_id(models.File)]) + operation_type = forms.ChoiceField(label=_("Operation type"), + choices=models.OperationType.get_types()) + start_date = forms.DateField(label=_(u"Start date"), required=False, + initial=get_now, widget=widgets.JQueryDate) + end_date = forms.DateField(label=_(u"End date"), required=False, + widget=widgets.JQueryDate) + year = forms.IntegerField(label=_("Year"), + initial=lambda:datetime.datetime.now().year, + validators=[validators.MinValueValidator(1900), + validators.MaxValueValidator(2100)]) + comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, + required=False) + +class OperationFormReference(forms.Form): + form_label = _("References") + associated_models = {'in_charge':models.Person, + 'associated_file':models.File, + 'operation_type':models.OperationType} + currents = {'associated_file':models.File} + hidden_year = forms.IntegerField(widget=forms.HiddenInput) + operation_code = forms.IntegerField(label=u"Operation code") + if settings.COUNTRY == 'fr': + code_patriarche = forms.IntegerField(label=u"Code PATRIARCHE", + required=False) + code_dracar = forms.CharField(label=_(u"Code DRACAR"), required=False, + validators=[validators.MaxLengthValidator(10)]) + def clean(self): + cleaned_data = self.cleaned_data + year = cleaned_data.get("hidden_year") + operation_code = cleaned_data.get("operation_code") + ops = models.Operation.objects.filter(year=year, + operation_code=operation_code).count() + if ops: + max_val = models.Operation.objects.filter(year=year).aggregate( + Max('operation_code'))["operation_code__max"] + raise forms.ValidationError(_(u"Operation code already exist for " + "year: %d - use a value bigger than %d") % (year, max_val)) + return cleaned_data + +class SelectedTownForm(forms.Form): + form_label = _("Towns") + associated_models = {'town':models.Town} + town = forms.ChoiceField(label=_("Town"), choices=(), + validators=[models.valid_id(models.Town)]) + def __init__(self, *args, **kwargs): + towns = None + if 'data' in kwargs and 'TOWNS' in kwargs['data']: + towns = kwargs['data']['TOWNS'] + # clean data if not "real" data + prefix_value = kwargs['prefix'] + '-town' + if not [k for k in kwargs['data'].keys() + if k.startswith(prefix_value) and kwargs['data'][k]]: + kwargs['data'] = None + if 'files' in kwargs: + kwargs.pop('files') + super(SelectedTownForm, self).__init__(*args, **kwargs) + if towns: + self.fields['town'].choices = [('', '--')] + towns + +SelectedTownFormSet = formset_factory(SelectedTownForm, can_delete=True, + formset=TownFormSet) +SelectedTownFormSet.form_label = _("Towns") + +class RemainForm(forms.Form): + form_label = _("Remain types") + associated_models = {'remain':models.RemainType} + remain = forms.ChoiceField(label=_("Remain type"), required=False, + choices=models.RemainType.get_types()) + +class RemainFormSet(FormSet): + def clean(self): + """Checks that no remain types are duplicated.""" + if any(self.errors): + return + remains = [] + for i in range(0, self.total_form_count()): + form = self.forms[i] + if not form.is_valid(): + continue + if 'remain_type' not in form.cleaned_data: + continue + remain = form.cleaned_data['remain_type'] + if remain in remains: + raise forms.ValidationError, \ + _("There are identical remain types.") + remains.append(remain) + +RemainFormSet = formset_factory(RemainForm, can_delete=True, + formset=RemainFormSet) +RemainFormSet.form_label = _("Remain types") + +operation_creation_wizard = OperationWizard([ + ('general-operation_creation', OperationFormGeneral), + ('refs-operation_creation', OperationFormReference), + ('towns-operation_creation', SelectedTownFormSet), + ('remains-operation_creation', RemainFormSet), + ('final-file_creation', FinalForm)], + url_name='operation_creation',) diff --git a/ishtar/furnitures/menus.py b/ishtar/furnitures/menus.py index f96ff9280..fb15745f3 100644 --- a/ishtar/furnitures/menus.py +++ b/ishtar/furnitures/menus.py @@ -66,8 +66,13 @@ class Menu: access_controls=['change_file', 'change_own_file']), MenuItem('file_deletion', _(u"File deletion"), access_controls=['delete_file', 'delete_own_file']), - ]), -] + ]), + SectionItem('operation_management', _(u"Operation management"), + childs=[ + MenuItem('operation_creation', _(u"Operation creation"), + access_controls=['add_operation', 'add_own_operation']), + ]), + ] self.items = {} def init(self): diff --git a/ishtar/furnitures/models.py b/ishtar/furnitures/models.py index f77fe6caf..e3c434f7a 100644 --- a/ishtar/furnitures/models.py +++ b/ishtar/furnitures/models.py @@ -79,6 +79,7 @@ class GeneralType(models.Model): @classmethod def get_types(cls): + yield ('', '--') for item in cls.objects.filter(available=True).all(): yield (item.id, _(item.label)) @@ -288,28 +289,29 @@ class OperationType(GeneralType): verbose_name = _(u"Operation type") verbose_name_plural = _(u"Operation types") -class VestigeType(GeneralType): +class RemainType(GeneralType): class Meta: - verbose_name = _(u"Vestige type") - verbose_name_plural = _(u"Vestige types") + verbose_name = _(u"Remain type") + verbose_name_plural = _(u"Remain types") class Operation(BaseHistorizedItem, OwnPerms): - name = models.CharField(_(u"Name"), max_length=120) - start_date = models.DateField(_(u"Start date")) - end_date = models.DateField(_(u"End date")) + start_date = models.DateField(_(u"Start date"), null=True, blank=True) + end_date = models.DateField(_(u"End date"), null=True, blank=True) in_charge = models.ForeignKey('Person', related_name='+', verbose_name=_(u"In charge")) - operation_code = models.CharField(_(u"Operation code"), max_length=20) + year = models.IntegerField(_(u"Year")) + operation_code = models.IntegerField(_(u"Operation code")) associated_file = models.ForeignKey(File, related_name='+', verbose_name=_(u"File")) operation_type = models.ForeignKey(OperationType, related_name='+', verbose_name=_(u"Operation type")) - vestiges = models.ManyToManyField("VestigeType") + remains = models.ManyToManyField("RemainType") towns = models.ManyToManyField("Town") if settings.COUNTRY == 'fr': - code_patriarche = models.IntegerField(u"Code PATRIARCHE") - code_pat = models.CharField(u"Code PAT", max_length=10) - code_dracar = models.CharField(u"Code DRACAR", max_length=10) + code_patriarche = models.IntegerField(u"Code PATRIARCHE", null=True, + blank=True) + code_dracar = models.CharField(u"Code DRACAR", max_length=10, null=True, + blank=True) comment = models.TextField(_(u"Comment"), null=True, blank=True) history = HistoricalRecords() @@ -324,10 +326,16 @@ class Operation(BaseHistorizedItem, OwnPerms): ) def __unicode__(self): - return self.name + items = [unicode(_('Intercommunal'))] + if self.towns.count() == 1: + items[0] = unicode(self.towns.all()[0]) + items += [unicode(getattr(self, k))[:12] for k in ['year', + 'operation_code',] + if getattr(self, k)] + return u" - ".join(items) -class Parcel(LightHistorizedItem) : +class Parcel(LightHistorizedItem): associated_file = models.ForeignKey(File, related_name='parcels', blank=True, null=True, verbose_name=_(u"File")) operation = models.ForeignKey(Operation, related_name='parcel', blank=True, diff --git a/ishtar/furnitures/urls.py b/ishtar/furnitures/urls.py index b7ff515af..85071a141 100644 --- a/ishtar/furnitures/urls.py +++ b/ishtar/furnitures/urls.py @@ -21,7 +21,8 @@ from django.conf.urls.defaults import * from ishtar.urls import BASE_URL from menus import menu -from forms import file_creation_wizard, file_modification_wizard +from forms import file_creation_wizard, file_modification_wizard,\ + operation_creation_wizard urlpatterns, actions = [], [] @@ -30,6 +31,8 @@ urlpatterns = patterns('', name='file_creation'), url(BASE_URL + r'file_modification/(?P<step>.+)$', file_modification_wizard, name='file_modification'), + url(BASE_URL + r'operation_creation/(?P<step>.+)$', + operation_creation_wizard, name='operation_creation'), ) for section in menu.childs: for menu_item in section.childs: diff --git a/ishtar/furnitures/views.py b/ishtar/furnitures/views.py index 530984092..ab0a64560 100644 --- a/ishtar/furnitures/views.py +++ b/ishtar/furnitures/views.py @@ -32,7 +32,8 @@ from django.core import serializers from ishtar import settings from menus import menu -from forms import file_creation_wizard, file_modification_wizard +from forms import file_creation_wizard, file_modification_wizard,\ + operation_creation_wizard import models def index(request): @@ -46,7 +47,6 @@ def index(request): def update_current_item(request): if not request.is_ajax() and not request.method == 'POST': return Http404() - print request.POST if 'value' in request.POST and 'item' in request.POST: request.session[request.POST['item']] = request.POST['value'] return HttpResponse('ok') @@ -159,3 +159,5 @@ def file_creation(request, dct, obj_id, *args, **kwargs): def file_modification(request, dct, obj_id, *args, **kwargs): return file_modification_wizard(request, *args, **kwargs) +def operation_creation(request, dct, obj_id, *args, **kwargs): + return operation_creation_wizard(request, *args, **kwargs) |