diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-02-19 17:41:32 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-02-19 17:45:14 +0100 |
commit | cc4b9d92baf57f29ff57fec6f9fdda3d6d4602e0 (patch) | |
tree | 0bd1799533ece0a06528d24be44763b02b61ec24 /archaeological_operations | |
parent | dfdebf20b3d1e2bd701e3559faa18931e017c044 (diff) | |
download | Ishtar-cc4b9d92baf57f29ff57fec6f9fdda3d6d4602e0.tar.bz2 Ishtar-cc4b9d92baf57f29ff57fec6f9fdda3d6d4602e0.zip |
Creation of virtual operation for site (refs #3935)
Diffstat (limited to 'archaeological_operations')
-rw-r--r-- | archaeological_operations/migrations/0018_archaeologicalsite_top_operation.py | 21 | ||||
-rw-r--r-- | archaeological_operations/models.py | 52 | ||||
-rw-r--r-- | archaeological_operations/tests.py | 89 |
3 files changed, 162 insertions, 0 deletions
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) |