#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2017 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. import json from archaeological_finds.tests import FindInit from ishtar_common.tests import WizardTest, WizardTestFormData as FormData, \ TestCase, WAREHOUSE_FIXTURES, GenericSerializationTest, COMMON_FIXTURES from ishtar_common.models import IshtarSiteProfile, SpatialReferenceSystem from archaeological_operations.models import Operation from archaeological_context_records.models import ContextRecord from archaeological_finds.models import Find from archaeological_warehouse import models, views, forms, serializers from archaeological_operations.serializers import operation_serialization from archaeological_context_records.serializers import cr_serialization from archaeological_finds.serializers import find_serialization class SerializationTest(GenericSerializationTest, FindInit, TestCase): fixtures = COMMON_FIXTURES + WAREHOUSE_FIXTURES def setUp(self): ope1 = self.create_operation()[0] ope2 = self.create_operation()[1] cr = self.create_context_record( data={"label": u"CR 1", "operation": ope1} )[0] cr2 = self.create_context_record( data={"label": u"CR 2", "operation": ope2} )[1] self.create_finds(data_base={"context_record": cr}) self.create_finds(data_base={"context_record": cr2}) self.create_finds(data_base={"context_record": cr2}) w1 = models.Warehouse.objects.create( name="Test1", external_id="test", warehouse_type=models.WarehouseType.objects.all()[0], ) w2 = models.Warehouse.objects.create( name="Test2", external_id="test2", warehouse_type=models.WarehouseType.objects.all()[0], ) w3 = models.Warehouse.objects.create( name="Test3", external_id="test3", warehouse_type=models.WarehouseType.objects.all()[0], ) self.warehouses = [w1, w2, w3] c1 = models.Container.objects.create( location=w1, responsible=w1, container_type=models.ContainerType.objects.all()[0], reference="Réf1", index=1, external_id="ref1-1" ) c2 = models.Container.objects.create( location=w2, responsible=w1, container_type=models.ContainerType.objects.all()[0], reference="Réf2", index=2, external_id="ref2-2" ) f0 = self.finds[0] f0.container = c1 f0.container_ref = c2 f0.save() c3 = models.Container.objects.create( location=w1, responsible=w2, container_type=models.ContainerType.objects.all()[0], reference="Réf3", index=1, external_id="ref3-1" ) c4 = models.Container.objects.create( location=w2, responsible=w2, container_type=models.ContainerType.objects.all()[0], reference="Réf4", index=2, external_id="ref4-2" ) f1 = self.finds[1] f1.container = c3 f1.container_ref = c4 f1.save() c5 = models.Container.objects.create( location=w3, responsible=w3, container_type=models.ContainerType.objects.all()[0], reference="Réf5", index=1, external_id="ref5-2" ) f2 = self.finds[2] f2.container = c5 f2.container_ref = c5 f2.save() wd1 = models.WarehouseDivision.objects.create( label="Étagère", txt_idx="etagere" ) wd2 = models.WarehouseDivision.objects.create( label="Allée", txt_idx="allee" ) wl1 = models.WarehouseDivisionLink.objects.create( warehouse=w1, division=wd1 ) wl2 = models.WarehouseDivisionLink.objects.create( warehouse=w1, division=wd2 ) wl3 = models.WarehouseDivisionLink.objects.create( warehouse=w2, division=wd2 ) wl4 = models.WarehouseDivisionLink.objects.create( warehouse=w3, division=wd1 ) models.ContainerLocalisation.objects.create( container=c1, division=wl1, reference="A1" ) models.ContainerLocalisation.objects.create( container=c1, division=wl2, reference="A2" ) models.ContainerLocalisation.objects.create( container=c2, division=wl3, reference="A4" ) models.ContainerLocalisation.objects.create( container=c3, division=wl4, reference="A5" ) def test_serialization(self): res = self.generic_serialization_test( serializers.warehouse_serialization) warehouse_json = json.loads( res[('warehouse', "archaeological_warehouse__Warehouse")] ) self.assertEqual(len(warehouse_json), 3) container_json = json.loads( res[('warehouse', "archaeological_warehouse__Container")] ) self.assertEqual(len(container_json), 5) div_json = json.loads( res[('warehouse', "archaeological_warehouse__WarehouseDivisionLink")] ) self.assertEqual(len(div_json), 4) loca_json = json.loads( res[('warehouse', "archaeological_warehouse__ContainerLocalisation")] ) self.assertEqual(len(loca_json), 4) result_queryset = Operation.objects.filter(uuid=self.operations[0].uuid) res = self.generic_serialization_test( serializers.warehouse_serialization, no_test=True, kwargs={"operation_queryset": result_queryset} ) warehouse_json = json.loads( res[('warehouse', "archaeological_warehouse__Warehouse")] ) self.assertEqual(len(warehouse_json), 2) container_json = json.loads( res[('warehouse', "archaeological_warehouse__Container")] ) self.assertEqual(len(container_json), 2) div_json = json.loads( res[('warehouse', "archaeological_warehouse__WarehouseDivisionLink")] ) self.assertEqual(len(div_json), 3) loca_json = json.loads( res[('warehouse', "archaeological_warehouse__ContainerLocalisation")] ) self.assertEqual(len(loca_json), 3) result_queryset = ContextRecord.objects.filter( uuid=self.context_records[0].uuid) res = self.generic_serialization_test( serializers.warehouse_serialization, no_test=True, kwargs={"cr_queryset": result_queryset} ) warehouse_json = json.loads( res[('warehouse', "archaeological_warehouse__Warehouse")] ) self.assertEqual(len(warehouse_json), 2) container_json = json.loads( res[('warehouse', "archaeological_warehouse__Container")] ) self.assertEqual(len(container_json), 2) div_json = json.loads( res[('warehouse', "archaeological_warehouse__WarehouseDivisionLink")] ) self.assertEqual(len(div_json), 3) loca_json = json.loads( res[('warehouse', "archaeological_warehouse__ContainerLocalisation")] ) self.assertEqual(len(loca_json), 3) result_queryset = Find.objects.filter(uuid=self.finds[0].uuid) res = self.generic_serialization_test( serializers.warehouse_serialization, no_test=True, kwargs={"find_queryset": result_queryset} ) warehouse_json = json.loads( res[('warehouse', "archaeological_warehouse__Warehouse")] ) self.assertEqual(len(warehouse_json), 2) container_json = json.loads( res[('warehouse', "archaeological_warehouse__Container")] ) self.assertEqual(len(container_json), 2) div_json = json.loads( res[('warehouse', "archaeological_warehouse__WarehouseDivisionLink")] ) self.assertEqual(len(div_json), 3) loca_json = json.loads( res[('warehouse', "archaeological_warehouse__ContainerLocalisation")] ) self.assertEqual(len(loca_json), 3) result_queryset = models.Warehouse.objects.filter( id=self.warehouses[0].id) res = self.generic_serialization_test( serializers.warehouse_serialization, no_test=True, kwargs={"warehouse_queryset": result_queryset} ) warehouse_json = json.loads( res[('warehouse', "archaeological_warehouse__Warehouse")] ) self.assertEqual(len(warehouse_json), 1) container_json = json.loads( res[('warehouse', "archaeological_warehouse__Container")] ) self.assertEqual(len(container_json), 3) div_json = json.loads( res[('warehouse', "archaeological_warehouse__WarehouseDivisionLink")] ) self.assertEqual(len(div_json), 2) loca_json = json.loads( res[('warehouse', "archaeological_warehouse__ContainerLocalisation")] ) self.assertEqual(len(loca_json), 2) def test_ope_serialization_with_warehouse_filter(self): res = self.generic_serialization_test( operation_serialization, no_test=True, ) ope_json = json.loads( res[('operations', 'archaeological_operations__Operation')] ) self.assertEqual(len(ope_json), 2) result_queryset = models.Warehouse.objects.filter( id=self.warehouses[0].pk) res = self.generic_serialization_test( operation_serialization, no_test=True, kwargs={"warehouse_queryset": result_queryset} ) ope_json = json.loads( res[('operations', 'archaeological_operations__Operation')] ) self.assertEqual(len(ope_json), 1) def test_cr_serialization_with_warehouse_filter(self): res = self.generic_serialization_test( cr_serialization, no_test=True, ) cr_json = json.loads( res[('context_records', 'archaeological_context_records__ContextRecord')] ) self.assertEqual(len(cr_json), 2) result_queryset = models.Warehouse.objects.filter( id=self.warehouses[0].pk) res = self.generic_serialization_test( cr_serialization, no_test=True, kwargs={"warehouse_queryset": result_queryset} ) cr_json = json.loads( res[('context_records', 'archaeological_context_records__ContextRecord')] ) self.assertEqual(len(cr_json), 1) def test_find_serialization_with_warehouse_filter(self): res = self.generic_serialization_test( find_serialization, no_test=True, ) find_json = json.loads( res[('finds', 'archaeological_finds__Find')] ) self.assertEqual(len(find_json), 3) bfind_json = json.loads( res[('finds', 'archaeological_finds__BaseFind')] ) self.assertEqual(len(bfind_json), 3) result_queryset = models.Warehouse.objects.filter( id=self.warehouses[0].pk) res = self.generic_serialization_test( find_serialization, no_test=True, kwargs={"warehouse_queryset": result_queryset} ) find_json = json.loads( res[('finds', 'archaeological_finds__Find')] ) self.assertEqual(len(find_json), 1) bfind_json = json.loads( res[('finds', 'archaeological_finds__BaseFind')] ) self.assertEqual(len(bfind_json), 1) def test_restore(self): current_number, zip_filename = self.generic_restore_test_genzip( serializers.WAREHOUSE_MODEL_LIST, serializers.warehouse_serialization) self.generic_restore_test(zip_filename, current_number, serializers.WAREHOUSE_MODEL_LIST) class WarehouseWizardCreationTest(WizardTest, FindInit, TestCase): fixtures = WAREHOUSE_FIXTURES url_name = 'warehouse_creation' wizard_name = 'warehouse_wizard' steps = views.warehouse_creation_steps redirect_url = "/warehouse_modification/selec-warehouse_modification"\ "?open_item={last_id}" model = models.Warehouse # back is messing with divisions but it is not a real problem because # reinit is necessary test_back = False form_datas = [ FormData( 'Warehouse creation', form_datas={ 'warehouse-warehouse_creation': { 'name': 'warehouse-ref', 'warehouse_type': None, 'location': None, 'responsible': None, }, 'divisions-warehouse_creation': [ { 'division': None, 'order': 42 } ] }, ), FormData( 'Warehouse creation with no division', form_datas={ 'warehouse-warehouse_creation': { 'name': 'warehouse-ref', 'warehouse_type': None, 'location': None, 'responsible': None, }, }, ignored=['divisions-warehouse_creation'] ), ] def pre_wizard(self): main_data = self.form_datas[0].form_datas alt_data = self.form_datas[1].form_datas main_data['warehouse-warehouse_creation']['warehouse_type'] = \ models.WarehouseType.objects.all()[0].pk alt_data['warehouse-warehouse_creation']['warehouse_type'] = \ models.WarehouseType.objects.all()[0].pk main_data['divisions-warehouse_creation'][0]['division'] = \ models.WarehouseDivision.create_default_for_test()[0].pk self.warehouse_number = models.Warehouse.objects.count() self.warehouse_div_link = models.WarehouseDivisionLink.objects.count() super(WarehouseWizardCreationTest, self).pre_wizard() def post_wizard(self): self.assertEqual(models.Warehouse.objects.count(), self.warehouse_number + 2) self.assertEqual(models.WarehouseDivisionLink.objects.count(), self.warehouse_div_link + 1) class ContainerWizardCreationTest(WizardTest, FindInit, TestCase): fixtures = WAREHOUSE_FIXTURES url_name = 'container_creation' wizard_name = 'container_wizard' steps = views.container_creation_steps redirect_url = '/container_modification/selec-container_modification'\ '?open_item={last_id}' model = models.Container form_datas = [ FormData( 'Container creation', form_datas={ 'container-container_creation': { 'reference': 'hop-ref', 'container_type': None, 'location': None, }, }, ), FormData( 'Other container on the same warehouse', form_datas={ 'container-container_creation': { 'reference': 'hop-ref2', 'container_type': None, 'location': None, }, }, ), FormData( 'Container creation with location', form_datas={ 'container-container_creation': { 'reference': 'hop-ref3', 'container_type': None, 'location': None, }, }, ), ] def pre_wizard(self): main_warehouse = models.Warehouse.objects.create( name="Main", warehouse_type=models.WarehouseType.objects.all()[0] ) main_data = self.form_datas[0].form_datas main_data_bis = self.form_datas[1].form_datas alt_data = self.form_datas[2].form_datas for data in [main_data, main_data_bis, alt_data]: forms_data = data['container-container_creation'] forms_data["responsible"] = main_warehouse.pk forms_data["location"] = main_warehouse.pk forms_data["container_type"] = \ models.ContainerType.objects.all()[0].pk alt_warehouse = models.Warehouse.objects.create( name="Alt", warehouse_type=models.WarehouseType.objects.all()[0] ) div = models.WarehouseDivision.objects.create(label='division') div_link = models.WarehouseDivisionLink.objects.create( warehouse=alt_warehouse, division=div) alt_data['container-container_creation']["location"] = alt_warehouse.pk alt_data['localisation-container_creation'] = { 'division_{}'.format(div_link.pk): 'Combien ?' } self.container_number = models.Container.objects.count() self.localisation_detail_number = \ models.ContainerLocalisation.objects.count() super(ContainerWizardCreationTest, self).pre_wizard() def post_wizard(self): self.assertEqual(models.Container.objects.count(), self.container_number + 3) self.assertEqual(models.ContainerLocalisation.objects.count(), self.localisation_detail_number + 1) class WarehouseTest(TestCase): fixtures = WAREHOUSE_FIXTURES def test_orga_from_warehouse(self): w = models.Warehouse.objects.create( name="Hophop", warehouse_type=models.WarehouseType.objects.all()[0], address="Adresse" ) w.create_attached_organization() w = models.Warehouse.objects.get(pk=w.pk) self.assertIsNotNone(w.organization) self.assertEqual(w.organization.name, "Hophop") self.assertEqual(w.organization.address, "Adresse") self.assertIsNone(w.address) class ContainerTest(FindInit, TestCase): fixtures = WAREHOUSE_FIXTURES def setUp(self): self.main_warehouse = models.Warehouse.objects.create( name="Main", warehouse_type=models.WarehouseType.objects.all()[0] ) self.division = models.WarehouseDivision.objects.create( label='division') self.alt_division = models.WarehouseDivision.objects.create( label='division2') self.div_link = models.WarehouseDivisionLink.objects.create( warehouse=self.main_warehouse, division=self.division) self.alt_warehouse = models.Warehouse.objects.create( name="Alt", warehouse_type=models.WarehouseType.objects.all()[0] ) def test_form_creation(self): data = { 'reference': 'hop-ref', "responsible": self.main_warehouse.pk, "location": self.main_warehouse.pk, "container_type": models.ContainerType.objects.all()[0].pk } form = forms.ContainerForm(data=data) self.assertTrue(form.is_valid(), msg="{}".format(form.errors)) self.container_number = models.Container.objects.count() self.create_user() form.save(self.user) self.assertEqual(models.Container.objects.count(), self.container_number + 1) def test_change_location(self): container = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=models.ContainerType.objects.all()[0] ) container.save() container = models.Container.objects.get(pk=container.pk) self.assertIn(self.main_warehouse.name, container.cached_location) models.ContainerLocalisation.objects.create( container=container, division=self.div_link, ) self.assertTrue(models.ContainerLocalisation.objects.filter( division__warehouse=self.main_warehouse).count()) # changing location remove irrelevant localisation other_warehouse = models.Warehouse.objects.create( name="Other", warehouse_type=models.WarehouseType.objects.all()[0] ) container.location = other_warehouse container.save() self.assertFalse(models.ContainerLocalisation.objects.filter( division__warehouse=self.main_warehouse).count()) def test_reassign_existing_division_on_warehouse_change(self): container = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=models.ContainerType.objects.all()[0] ) container_loca = models.ContainerLocalisation.objects.create( container=container, division=self.div_link, ) alt_warehouse = models.Warehouse.objects.create( name="Alternative", warehouse_type=models.WarehouseType.objects.all()[0] ) new_div_link = models.WarehouseDivisionLink.objects.create( warehouse=alt_warehouse, division=self.division) nb_container_loca = models.ContainerLocalisation.objects.count() container.location = alt_warehouse container.save() # no new container localisation self.assertEqual(nb_container_loca, models.ContainerLocalisation.objects.count()) # but the new one is reaffected container_loca = models.ContainerLocalisation.objects.get( pk=container_loca.pk) self.assertEqual(container_loca.division, new_div_link) # reaffect first division link self.div_link.division = self.alt_division self.div_link.save() container.location = self.main_warehouse container.save() # cannot reaffect -> the location is not preserved self.assertEqual(nb_container_loca, models.ContainerLocalisation.objects.count() + 1) def test_update_containers_on_warehouse_update(self): container = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=models.ContainerType.objects.all()[0] ) container.save() container = models.Container.objects.get(pk=container.pk) self.assertIn(self.main_warehouse.name, container.cached_location) self.main_warehouse.name = "New name" self.main_warehouse.save() self.assertEqual( models.Container.objects.filter( need_update=True ).count(), 1) self.assertEqual( models.Container.objects.filter( pk=container.pk, need_update=True ).count(), 1) container = models.Container.objects.get(pk=container.pk) # process pending update container.skip_history_when_saving = True container._no_move = True container.save() container = models.Container.objects.get(pk=container.pk) self.assertIn("New name", container.cached_location) def test_update_container_localisation_on_warehouse_update(self): profile, created = IshtarSiteProfile.objects.get_or_create( slug='default', active=True) profile.mapping = True profile.locate_warehouses = True profile.save() wgs84 = SpatialReferenceSystem.objects.get(srid=4326) container = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=models.ContainerType.objects.all()[0] ) container.save() self.assertEqual(container.x, None) main_warehouse = models.Warehouse.objects.get(pk=self.main_warehouse.pk) main_warehouse.x, main_warehouse.y = 33, 42 main_warehouse.spatial_reference_system = wgs84 main_warehouse.save() # an update is pending self.assertEqual( models.Container.objects.filter( pk=container.pk, need_update=True ).count(), 1) # process pending update container = models.Container.objects.get(pk=container.pk) self.assertEqual(container.x, None) # update has to be done container.skip_history_when_saving = True container._no_move = True container.save() container = models.Container.objects.get(pk=container.pk) self.assertEqual(container.x, 33) def test_external_id(self): ct = models.ContainerType.objects.all()[0] container_1 = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=ct ) container_2 = models.Container.objects.create( reference="Test 2", responsible=self.main_warehouse, parent=container_1, location=self.main_warehouse, container_type=ct ) container_3 = models.Container.objects.create( reference="Test 3", responsible=self.main_warehouse, parent=container_2, location=self.main_warehouse, container_type=ct ) self.assertEqual( container_1.external_id, "{}-{}-{}".format( self.main_warehouse.external_id, ct.txt_idx, container_1.reference)) self.assertEqual( container_2.external_id, "{}-{}-{}".format( container_1.external_id, ct.txt_idx, container_2.reference)) self.assertEqual( container_3.external_id, "{}-{}-{}".format( container_2.external_id, ct.txt_idx, container_3.reference)) def test_merge_candidate(self): ct = models.ContainerType.objects.all()[0] container_1 = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, container_type=ct) init_mc = container_1.merge_candidate.count() models.Container.objects.create( reference="TEST", responsible=self.main_warehouse, location=self.main_warehouse, container_type=ct) self.assertEqual(container_1.merge_candidate.count(), init_mc + 1) container_1.archive() self.assertEqual(container_1.merge_candidate.count(), init_mc) def test_merge_container(self): ct = models.ContainerType.objects.all()[0] ct2 = models.ContainerType.objects.all()[1] self.create_finds() self.create_finds() self.create_finds() find0 = self.finds[0] find1 = self.finds[1] find2 = self.finds[2] container_1 = models.Container.objects.create( reference="Test 1", location=self.main_warehouse, container_type=ct) find0.container = container_1 find0.container_ref = container_1 find0.save() find1.container = container_1 find1.container_ref = container_1 find1.save() container_2 = models.Container.objects.create( reference="Test 2", location=self.alt_warehouse, container_type=ct2) find2.container = container_2 find2.container_ref = container_2 find2.save() container_1.merge(container_2) container_1 = models.Container.objects.get(pk=container_1.pk) self.assertEqual( models.Container.objects.filter(pk=container_2.pk).count(), 0) # preserve existing fields self.assertEqual(container_1.reference, 'Test 1') self.assertEqual(container_1.container_type, ct) find_lst = [f for f in container_1.finds.all()] for f in [find0, find1, find2]: self.assertIn(f, find_lst)