summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_files/wizards.py4
-rw-r--r--archaeological_operations/migrations/0018_archaeologicalsite_top_operation.py21
-rw-r--r--archaeological_operations/models.py52
-rw-r--r--archaeological_operations/tests.py89
4 files changed, 164 insertions, 2 deletions
diff --git a/archaeological_files/wizards.py b/archaeological_files/wizards.py
index e8d6ca9ae..7fdb5e8ff 100644
--- a/archaeological_files/wizards.py
+++ b/archaeological_files/wizards.py
@@ -48,9 +48,9 @@ class FileWizard(OperationWizard):
return dct
def done(self, form_list, **kwargs):
- '''
+ """
Save parcels and make numeric_reference unique
- '''
+ """
r = super(FileWizard, self).done(form_list, return_object=True,
**kwargs)
if type(r) not in (list, tuple) or len(r) != 2:
diff --git a/archaeological_operations/migrations/0018_archaeologicalsite_top_operation.py b/archaeological_operations/migrations/0018_archaeologicalsite_top_operation.py
new file mode 100644
index 000000000..e27d1389c
--- /dev/null
+++ b/archaeological_operations/migrations/0018_archaeologicalsite_top_operation.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-02-19 17:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_operations', '0017_archaeologicalsite_towns'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='top_operation',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.Operation', verbose_name='Top operation'),
+ ),
+ ]
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 60bdd5f2d..7d0efe34c 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -104,6 +104,9 @@ class ArchaeologicalSite(BaseHistorizedItem):
blank=True)
towns = models.ManyToManyField(Town, verbose_name=_(u"Towns"),
related_name='sites', blank=True)
+ top_operation = models.ForeignKey("Operation", blank=True, null=True,
+ verbose_name=_(u"Top operation"),
+ on_delete=models.SET_NULL)
class Meta:
verbose_name = _(u"Archaeological site")
@@ -142,6 +145,55 @@ class ArchaeologicalSite(BaseHistorizedItem):
return [u"{} ({})".format(town.name, town.numero_insee) for town in
self.towns.all()]
+ def create_or_update_top_operation(self, create=False):
+ """
+ Create a virtual operation to associate with the site.
+ A cluster operation is created for site with many operation.
+ This cluster operation can be used to attach context records
+ which are only attached to the site.
+ """
+ if not self.top_operation:
+ if not create:
+ return
+ operation_type, created = OperationType.objects.get_or_create(
+ txt_idx='unknown',
+ defaults={'label': _(u"Unknown"), 'available': True,
+ 'order': 999})
+ name = unicode(
+ _(u"Virtual operation of site: {}")
+ ).format(self.reference)
+ if self.towns.count():
+ name += u' - ' + u", ".join([town.name
+ for town in self.towns.all()])
+ self.top_operation = Operation.objects.create(
+ operation_type=operation_type,
+ common_name=name,
+ virtual_operation=True
+ )
+ self.skip_history_when_saving = True
+ self.save()
+ current_operations = dict(
+ [(ope.pk, ope)
+ for ope in self.operations.exclude(pk=self.top_operation.pk).all()
+ ]
+ )
+ q = RecordRelations.objects.filter(
+ left_record=self.top_operation,
+ relation_type__txt_idx='has_got'
+ )
+ for relation in q.all():
+ if relation.right_record.pk not in current_operations:
+ relation.delete()
+ else:
+ current_operations.pop(relation.right_record.pk)
+ rel_type = RelationType.get_cache('has_got')
+ for missing in current_operations:
+ RecordRelations.objects.create(
+ left_record=self.top_operation,
+ right_record=current_operations[missing],
+ relation_type=rel_type
+ )
+
def get_values_town_related(item, prefix, values):
values[prefix + 'parcellist'] = item.render_parcels()
diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py
index 947be204e..8fe1d8850 100644
--- a/archaeological_operations/tests.py
+++ b/archaeological_operations/tests.py
@@ -1926,3 +1926,92 @@ class OperationSourceWizardModificationTest(WizardTest, OperationInitTest,
def post_wizard(self):
source = models.OperationSource.objects.get(pk=self.source.pk)
self.assertEqual(source.authors.count(), 0)
+
+
+class SiteTest(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)
+
+ def test_create_or_update_top_operation(self):
+ operation_0 = self.create_operation(self.user, self.orgas[0])[0]
+ operation_1 = self.create_operation(self.alt_user, self.orgas[0])[1]
+ site = models.ArchaeologicalSite.objects.create(
+ reference="ref-site"
+ )
+ site.create_or_update_top_operation()
+ q = models.ArchaeologicalSite.objects.filter(reference='ref-site')
+ site = q.all()[0]
+ # creation not forced - no creation
+ self.assertIsNone(site.top_operation)
+
+ site.create_or_update_top_operation(create=True)
+ site = q.all()[0]
+ # a default operation has been created
+ self.assertIsNotNone(site.top_operation)
+ self.assertTrue(site.top_operation.virtual_operation)
+ self.assertEqual(site.top_operation.right_relations.count(), 0)
+
+ # create with one operation attached
+ site.top_operation.delete()
+ site = q.all()[0]
+ site.operations.add(operation_0)
+ site.create_or_update_top_operation(create=True)
+ site = q.all()[0]
+ self.assertIsNotNone(site.top_operation)
+ self.assertTrue(site.top_operation.virtual_operation)
+ self.assertEqual(site.top_operation.right_relations.count(), 1)
+ self.assertEqual(
+ site.top_operation.right_relations.all()[0].right_record,
+ operation_0
+ )
+
+ # create with two operations attached
+ site.top_operation.delete()
+ site = q.all()[0]
+ site.operations.add(operation_0)
+ site.operations.add(operation_1)
+ site.create_or_update_top_operation(create=True)
+ site = q.all()[0]
+ self.assertIsNotNone(site.top_operation)
+ self.assertTrue(site.top_operation.virtual_operation)
+ self.assertEqual(site.top_operation.right_relations.count(), 2)
+ attached = [
+ rel.right_record
+ for rel in site.top_operation.right_relations.all()
+ ]
+ self.assertIn(operation_0, attached)
+ self.assertIn(operation_1, attached)
+
+ # detach one operation
+ site.operations.remove(operation_1)
+ site.create_or_update_top_operation()
+ site = q.all()[0]
+ self.assertIsNotNone(site.top_operation)
+ self.assertTrue(site.top_operation.virtual_operation)
+ self.assertEqual(site.top_operation.right_relations.count(), 1)
+ self.assertEqual(
+ site.top_operation.right_relations.all()[0].right_record,
+ operation_0
+ )
+
+ # reattach it
+ site.operations.add(operation_1)
+ site.create_or_update_top_operation()
+ site = q.all()[0]
+ self.assertIsNotNone(site.top_operation)
+ self.assertTrue(site.top_operation.virtual_operation)
+ self.assertEqual(site.top_operation.right_relations.count(), 2)
+ attached = [
+ rel.right_record
+ for rel in site.top_operation.right_relations.all()
+ ]
+ self.assertIn(operation_0, attached)
+ self.assertIn(operation_1, attached)