diff options
Diffstat (limited to 'archaeological_operations')
-rw-r--r-- | archaeological_operations/forms.py | 166 | ||||
-rw-r--r-- | archaeological_operations/tests.py | 105 | ||||
-rw-r--r-- | archaeological_operations/views.py | 13 | ||||
-rw-r--r-- | archaeological_operations/wizards.py | 6 |
4 files changed, 216 insertions, 74 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index f456eae86..c61b75f7c 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -49,7 +49,7 @@ from ishtar_common import widgets from ishtar_common.forms import FinalForm, FormSet, get_now, \ reverse_lazy, get_form_selection, TableSelect, get_data_from_formset, \ - ManageOldType, IshtarForm + ManageOldType, IshtarForm, CustomForm, FieldType from ishtar_common.forms_common import TownFormSet, SourceForm, SourceSelect, \ get_town_field @@ -477,6 +477,8 @@ class RecordRelationsFormSetBase(FormSet): RecordRelationsFormSet = formset_factory( RecordRelationsForm, can_delete=True, formset=RecordRelationsFormSetBase) RecordRelationsFormSet.form_label = _(u"Relations") +RecordRelationsFormSet.form_admin_name = _("Operations - Relations") +RecordRelationsFormSet.form_slug = "operation-relations" class OperationSelect(TableSelect): @@ -675,12 +677,15 @@ class OperationFormFileChoice(IshtarForm): validators=[valid_id(File)], required=False) -class OperationFormAbstract(IshtarForm): +class OperationFormAbstract(CustomForm, IshtarForm): form_label = _(u"Abstract") + form_admin_name = _("Operations - Abstract") + form_slug = "operation-abstract" abstract = forms.CharField( label=_(u"Abstract"), widget=forms.Textarea(attrs={'class': 'xlarge'}), required=False) + SLICING = (("month", _(u"months")), ('year', _(u"years")),) DATE_SOURCE = (('creation', _(u"Creation date")), @@ -761,8 +766,11 @@ class DashboardForm(forms.Form): return fltr -class OperationFormGeneral(ManageOldType): +class OperationFormGeneral(CustomForm, ManageOldType): form_label = _(u"General") + form_admin_name = _(u"Operation - General") + form_slug = "operation-general" + file_upload = True associated_models = {'scientist': Person, 'in_charge': Person, @@ -882,33 +890,36 @@ class OperationFormGeneral(ManageOldType): 'height': settings.IMAGE_MAX_SIZE[1]}), max_length=255, required=False, widget=widgets.ImageFileInput()) + FILE_FIELDS = [ + 'report_delivery_date', + 'report_processing', + 'cira_rapporteur', + 'cira_date', + 'negative_result' + ] + WAREHOUSE_FIELDS = [ + 'documentation_deadline', + 'documentation_received', + 'finds_deadline', + 'finds_received', + ] + TYPES = [ + FieldType('operation_type', models.OperationType), + FieldType('report_processing', models.ReportState), + ] + def __init__(self, *args, **kwargs): super(OperationFormGeneral, self).__init__(*args, **kwargs) profile = get_current_profile() if not profile.files: - self.fields.pop('report_delivery_date') - self.fields.pop('report_processing') - self.fields.pop('cira_rapporteur') - self.fields.pop('cira_date') - self.fields.pop('negative_result') + for key in self.FILE_FIELDS: + self.remove_field(key) if not profile.warehouse: - self.fields.pop('documentation_deadline') - self.fields.pop('documentation_received') - self.fields.pop('finds_deadline') - self.fields.pop('finds_received') - self.fields['operation_type'].choices = \ - models.OperationType.get_types( - initial=self.init_data.get('operation_type')) - self.fields['operation_type'].help_text = \ - models.OperationType.get_help() - if 'report_processing' in self.fields: - self.fields['report_processing'].choices = \ - models.ReportState.get_types( - initial=self.init_data.get('report_processing')) - self.fields['report_processing'].help_text = \ - models.ReportState.get_help() - self.fields['record_quality'].choices = \ - [('', '--')] + list(models.QUALITY) + for key in self.WAREHOUSE_FIELDS: + self.remove_field(key) + if 'record_quality' in self.fields: + self.fields['record_quality'].choices = \ + [('', '--')] + list(models.QUALITY) if 'operation_code' in self.fields: fields = OrderedDict() ope_code = self.fields.pop('operation_code') @@ -920,17 +931,20 @@ class OperationFormGeneral(ManageOldType): def clean(self): cleaned_data = self.cleaned_data + # verify the logic between start date and excavation end date - if cleaned_data.get('excavation_end_date'): + if self.are_available(['excavation_end_date', 'start_date']) \ + and cleaned_data.get('excavation_end_date'): if not self.cleaned_data['start_date']: raise forms.ValidationError( - _(u"If you want to set an excavation end date you have to " - u"provide a start date.")) + _(u"If you want to set an excavation end date you " + u"have to provide a start date.")) if cleaned_data['excavation_end_date'] \ < cleaned_data['start_date']: raise forms.ValidationError( _(u"The excavation end date cannot be before the start " u"date.")) + # verify patriarche code_p = self.cleaned_data.get('code_patriarche', None) @@ -942,11 +956,13 @@ class OperationFormGeneral(ManageOldType): msg = u"Ce code OA a déjà été affecté à une "\ u"autre opération" raise forms.ValidationError(msg) + # manage unique operation ID year = self.cleaned_data.get("year") operation_code = cleaned_data.get("operation_code", None) if not operation_code: return self.cleaned_data + ops = models.Operation.objects.filter(year=year, operation_code=operation_code) if 'pk' in cleaned_data and cleaned_data['pk']: @@ -989,14 +1005,18 @@ class OperationFormModifGeneral(OperationFormGeneral): fields[key] = value self.fields = fields + OperationFormModifGeneral.associated_models = \ OperationFormGeneral.associated_models.copy() OperationFormModifGeneral.associated_models['associated_file'] = File -class CollaboratorForm(IshtarForm): +class CollaboratorForm(CustomForm, IshtarForm): form_label = _(u"Collaborators") + form_admin_name = _(u"Operation - Collaborators") + form_slug = "operation-collaborators" + base_models = ['collaborator'] associated_models = {'collaborator': Person, } collaborator = widgets.Select2MultipleField( @@ -1004,11 +1024,15 @@ class CollaboratorForm(IshtarForm): def __init__(self, *args, **kwargs): super(CollaboratorForm, self).__init__(*args, **kwargs) - self.fields['collaborator'].widget.attrs['full-width'] = True + if 'collaborator' in self.fields: + self.fields['collaborator'].widget.attrs['full-width'] = True -class OperationFormPreventive(IshtarForm): +class OperationFormPreventive(CustomForm, IshtarForm): form_label = _(u"Preventive informations - excavation") + form_admin_name = _(u"Operation - Preventive - Excavation") + form_slug = "operation-preventive-excavation" + cost = forms.IntegerField(label=_(u"Cost (euros)"), required=False) scheduled_man_days = forms.IntegerField(label=_(u"Scheduled man-days"), required=False) @@ -1023,8 +1047,11 @@ class OperationFormPreventive(IshtarForm): validators.MaxValueValidator(100)]) -class OperationFormPreventiveDiag(IshtarForm): +class OperationFormPreventiveDiag(CustomForm, IshtarForm): form_label = _("Preventive informations - diagnostic") + form_admin_name = _(u"Operation - Preventive - Diagnostic") + form_slug = "operation-preventive-diagnostic" + if settings.COUNTRY == 'fr': zoning_prescription = forms.NullBooleanField( required=False, label=_(u"Prescription on zoning")) @@ -1049,9 +1076,11 @@ class SelectedTownForm(IshtarForm): if towns and towns != -1: self.fields['town'].choices = [('', '--')] + towns + SelectedTownFormset = formset_factory(SelectedTownForm, can_delete=True, formset=TownFormSet) SelectedTownFormset.form_label = _(u"Towns") +SelectedTownFormset.form_slug = "towns" class SelectedParcelForm(IshtarForm): @@ -1068,13 +1097,17 @@ class SelectedParcelForm(IshtarForm): if parcels: self.fields['parcel'].choices = [('', '--')] + parcels + SelectedParcelFormSet = formset_factory(SelectedParcelForm, can_delete=True, formset=ParcelFormSet) SelectedParcelFormSet.form_label = _("Parcels") +SelectedParcelFormSet.form_admin_name = _(u"Operations - Parcels") +SelectedParcelFormSet.form_slug = "operation-parcels" SelectedParcelGeneralFormSet = formset_factory(ParcelForm, can_delete=True, formset=ParcelFormSet) -SelectedParcelGeneralFormSet.form_label = _("Parcels") +SelectedParcelGeneralFormSet.form_admin_name = _("Parcels") +SelectedParcelGeneralFormSet.form_slug = "operation-parcels" """ class SelectedParcelFormSet(forms.Form): @@ -1102,36 +1135,36 @@ class SelectedParcelFormSet(forms.Form): """ -class RemainForm(ManageOldType): +class RemainForm(CustomForm, ManageOldType): form_label = _("Remain types") + form_admin_name = _("Operations - Remains") + form_slug = "operation-remains" + base_model = 'remain' associated_models = {'remain': models.RemainType} remain = forms.MultipleChoiceField( label=_("Remain type"), required=False, choices=[], widget=forms.CheckboxSelectMultiple) - def __init__(self, *args, **kwargs): - super(RemainForm, self).__init__(*args, **kwargs) - self.fields['remain'].choices = models.RemainType.get_types( - initial=self.init_data.get('remain'), - empty_first=False) - self.fields['remain'].help_text = models.RemainType.get_help() + TYPES = [ + FieldType('remain', models.RemainType, True), + ] -class PeriodForm(ManageOldType): +class PeriodForm(CustomForm, ManageOldType): form_label = _("Periods") + form_admin_name = _("Operations - Periods") + form_slug = "operation-periods" + base_model = 'period' associated_models = {'period': models.Period} period = forms.MultipleChoiceField( label=_("Period"), required=False, choices=[], widget=forms.CheckboxSelectMultiple) - def __init__(self, *args, **kwargs): - super(PeriodForm, self).__init__(*args, **kwargs) - self.fields['period'].choices = models.Period.get_types( - initial=self.init_data.get('period'), - empty_first=False) - self.fields['period'].help_text = models.Period.get_help() + TYPES = [ + FieldType('period', models.Period, True), + ] class ArchaeologicalSiteForm(ManageOldType): @@ -1144,21 +1177,16 @@ class ArchaeologicalSiteForm(ManageOldType): label=_("Remains"), choices=[], widget=widgets.Select2Multiple, required=False) + TYPES = [ + FieldType('periods', models.Period, True), + FieldType('remains', models.RemainType, True), + ] + def __init__(self, *args, **kwargs): self.limits = {} if 'limits' in kwargs: kwargs.pop('limits') super(ArchaeologicalSiteForm, self).__init__(*args, **kwargs) - self.fields['periods'].choices = \ - models.Period.get_types( - empty_first=False, - initial=self.init_data.get('periods')) - self.fields['periods'].help_text = models.Period.get_help() - self.fields['remains'].choices = \ - models.RemainType.get_types( - initial=self.init_data.get('remains'), - empty_first=False) - self.fields['remains'].help_text = models.RemainType.get_help() def clean_reference(self): reference = self.cleaned_data['reference'] @@ -1197,6 +1225,9 @@ class ArchaeologicalSiteBasicForm(IshtarForm): ArchaeologicalSiteFormSet = formset_factory(ArchaeologicalSiteBasicForm, can_delete=True, formset=FormSet) ArchaeologicalSiteFormSet.form_label = _("Archaeological sites") +ArchaeologicalSiteFormSet.form_admin_name = _("Operation - Archaeological " + "sites") +ArchaeologicalSiteFormSet.form_slug = "operation-archaeological-sites" class ArchaeologicalSiteSelectionForm(IshtarForm): @@ -1224,6 +1255,9 @@ class OperationDeletionForm(FinalForm): class OperationSourceForm(SourceForm): + form_admin_name = _("Operation Sources - Main") + form_slug = "operation-source-relations" + pk = forms.IntegerField(required=False, widget=forms.HiddenInput) index = forms.IntegerField(label=_(u"Index")) hidden_operation_id = forms.IntegerField(label="", @@ -1371,8 +1405,11 @@ class AdministrativeActOpeFormSelection(IshtarForm): return cleaned_data -class AdministrativeActOpeForm(ManageOldType): +class AdministrativeActOpeForm(CustomForm, ManageOldType): form_label = _("General") + form_admin_name = _("Operations - Administrative act - General") + form_slug = "operation-adminact-general" + associated_models = {'act_type': models.ActType, } # 'signatory':Person} act_type = forms.ChoiceField(label=_("Act type"), choices=[]) @@ -1388,13 +1425,10 @@ class AdministrativeActOpeForm(ManageOldType): ref_sra = forms.CharField(label=u"Autre référence", max_length=15, required=False) - def __init__(self, *args, **kwargs): - super(AdministrativeActOpeForm, self).__init__(*args, **kwargs) - self.fields['act_type'].choices = models.ActType.get_types( - initial=self.init_data.get('act_type'), - dct={'intented_to': 'O'}) - self.fields['act_type'].help_text = models.ActType.get_help( - dct={'intented_to': 'O'}) + TYPES = [ + FieldType('act_type', models.ActType, + extra_args={"dct": {'intented_to': 'O'}}), + ] class AdministrativeActModifForm(object): @@ -1410,7 +1444,7 @@ class AdministrativeActModifForm(object): def clean(self): # manage unique act ID - year = self.cleaned_data.get("signature_date") + year = self.cleaned_data.get("signature_date", None) if not year or not hasattr(year, 'year'): return self.cleaned_data year = year.year diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index ec7ae44c5..af6199774 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -40,7 +40,7 @@ from ishtar_common.models import OrganizationType, Organization, ItemKey, \ ImporterType, IshtarUser, TargetKey, ImporterModel, IshtarSiteProfile, \ Town, ImporterColumn, Person, Author, SourceType, AuthorType, \ DocumentTemplate, PersonType, TargetKeyGroup, JsonDataField, \ - JsonDataSection, ImportTarget, FormaterType + JsonDataSection, ImportTarget, FormaterType, CustomForm, ExcludedField from archaeological_files.models import File, FileType from archaeological_context_records.models import Unit @@ -1142,6 +1142,109 @@ class OperationTest(TestCase, OperationInitTest): self.assertNotIn(u"Marmotte".encode('utf-8'), response.content) +class CustomFormTest(TestCase, OperationInitTest): + fixtures = FILE_FIXTURES + + def setUp(self): + IshtarSiteProfile.objects.get_or_create( + slug='default', active=True) + self.username, self.password, self.user = create_superuser() + self.alt_username, self.alt_password, self.alt_user = create_user() + self.alt_user.user_permissions.add(Permission.objects.get( + codename='view_own_operation')) + self.orgas = self.create_orgas(self.user) + self.operations = self.create_operation(self.user, self.orgas[0]) + self.operations += self.create_operation(self.alt_user, self.orgas[0]) + self.item = self.operations[0] + + def test_filters(self): + c = Client() + c.login(username=self.username, password=self.password) + + cls_wiz = OperationWizardModifTest + url = reverse(cls_wiz.url_name) + # first wizard step + step = 'selec-operation_modification' + cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) + + step = 'general-operation_modification' + data = { + '{}{}-current_step'.format(cls_wiz.url_name, + cls_wiz.wizard_name): [step], + } + key_in_charge = "in_charge" + response = c.post(url, data) + self.assertIn( + key_in_charge, response.content, + msg="filter all - 'in charge' field not found on the modification " + "wizard") + f = CustomForm.objects.create(name="Test", form="operation-general", + available=True, apply_to_all=True) + ExcludedField.objects.create(custom_form=f, field="in_charge") + + response = c.post(url, data) + self.assertNotIn( + key_in_charge, response.content, + msg="filter all - 'in charge' field found on the modification " + "wizard. It should have been filtered.") + + # user type form prevail on "all" + f_scientist = CustomForm.objects.create( + name="Test", form="operation-general", available=True) + tpe = PersonType.objects.get(txt_idx='head_scientist') + key_address = "address" + f_scientist.user_types.add(tpe) + self.user.ishtaruser.person.person_types.add(tpe) + ExcludedField.objects.create(custom_form=f_scientist, field="address") + response = c.post(url, data) + self.assertIn( + key_in_charge, response.content, + msg="filter user type - 'in charge' field not found on the " + "modification wizard. It should not have been filtered.") + self.assertNotIn( + key_address, response.content, + msg="filter user type - 'address' field found on the " + "modification wizard. It should have been filtered.") + + # user prevail on "all" and "user_types" + f_user = CustomForm.objects.create( + name="Test", form="operation-general", available=True) + f_user.users.add(self.user.ishtaruser) + self.user.ishtaruser.person.person_types.add(tpe) + response = c.post(url, data) + self.assertIn( + key_in_charge, response.content, + msg="filter user - 'in charge' field not found on the modification " + "wizard. It should not have been filtered.") + self.assertIn( + key_address, response.content, + msg="filter user - 'address' field not found on the modification " + "wizard. It should not have been filtered.") + + def test_enabled(self): + c = Client() + c.login(username=self.username, password=self.password) + + cls_wiz = OperationWizardModifTest + url = reverse(cls_wiz.url_name) + # first wizard step + step = 'selec-operation_modification' + cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) + + step = 'collaborators-operation_modification' + data = { + '{}{}-current_step'.format(cls_wiz.url_name, + cls_wiz.wizard_name): [step], + } + response = c.post(url, data) + self.assertNotEqual(response.status_code, 404) + CustomForm.objects.create( + name="Test2", form="operation-collaborators", available=True, + apply_to_all=True, enabled=False) + response = c.post(url, data) + self.assertEqual(response.status_code, 404) + + class OperationSearchTest(TestCase, OperationInitTest): fixtures = FILE_FIXTURES diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 1fecce9cd..f295e0f9d 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -36,7 +36,7 @@ from forms import * import models -def autocomplete_patriarche(request, non_closed=True): +def autocomplete_patriarche(request): if (not request.user.has_perm('ishtar_common.view_operation', models.Operation) and not request.user.has_perm('ishtar_common.view_own_operation', @@ -50,8 +50,6 @@ def autocomplete_patriarche(request, non_closed=True): query = Q() for q in q.split(' '): query &= Q(code_patriarche__startswith=q) - if non_closed: - query &= Q(end_date__isnull=True) limit = 15 operations = models.Operation.objects\ .filter(query).order_by('code_patriarche')[:limit] @@ -84,11 +82,12 @@ def autocomplete_archaeologicalsite(request): for site in sites]) return HttpResponse(data, content_type='text/plain') + new_archaeologicalsite = new_item(models.ArchaeologicalSite, ArchaeologicalSiteForm, many=True) -def autocomplete_operation(request, non_closed=True): +def autocomplete_operation(request): # person_types = request.user.ishtaruser.person.person_type if (not request.user.has_perm('ishtar_common.view_operation', models.Operation) @@ -117,8 +116,6 @@ def autocomplete_operation(request, non_closed=True): except ValueError: pass query = query & extra - if non_closed: - query &= Q(end_date__isnull=True) limit = 15 operations = models.Operation.objects.filter(query)[:limit] data = json.dumps([{'id': operation.pk, 'value': unicode(operation)} @@ -136,6 +133,7 @@ def get_available_operation_code(request, year=None): models.Operation.get_available_operation_code(year)}) return HttpResponse(data, content_type='text/plain') + get_operation = get_item(models.Operation, 'get_operation', 'operation') show_operation = show_item(models.Operation, 'operation') @@ -162,11 +160,13 @@ def dashboard_operation(request, *args, **kwargs): dct = {'dashboard': models.OperationDashboard()} return render(request, 'ishtar/dashboards/dashboard_operation.html', dct) + operation_search_wizard = SearchWizard.as_view( [('general-operation_search', OperationFormSelection)], label=_(u"Operation search"), url_name='operation_search',) + wizard_steps = [ ('filechoice-operation_creation', OperationFormFileChoice), ('general-operation_creation', OperationFormGeneral), @@ -195,6 +195,7 @@ def get_check_files_for_operation(other_check=None): return other_check(self) return func + check_files_for_operation = get_check_files_for_operation() diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index fffe34ca7..24c1af45b 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -23,6 +23,7 @@ from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db.models import Max +from django.http import Http404 from django.shortcuts import render from django.utils.translation import ugettext_lazy as _ @@ -149,7 +150,10 @@ class OperationWizard(Wizard): data = {} if not step: step = self.steps.current - form = self.get_form_list()[step] + try: + form = self.get_form_list()[step] + except KeyError: + raise Http404() # manage the dynamic choice of towns if step.startswith('towns') and hasattr(form, 'management_form'): data['TOWNS'] = self.get_towns() |