summaryrefslogtreecommitdiff
path: root/archaeological_operations
diff options
context:
space:
mode:
Diffstat (limited to 'archaeological_operations')
-rw-r--r--archaeological_operations/forms.py166
-rw-r--r--archaeological_operations/tests.py105
-rw-r--r--archaeological_operations/views.py13
-rw-r--r--archaeological_operations/wizards.py6
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()