diff --git a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditor.java b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditor.java index b2b119c61..cc7270f99 100644 --- a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditor.java +++ b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditor.java @@ -2,6 +2,7 @@ import org.avni.server.dao.LocationRepository; import org.avni.server.domain.AddressLevel; +import org.avni.server.domain.AddressLevelType; import org.avni.server.importer.batch.csv.creator.ObservationCreator; import org.avni.server.importer.batch.model.Row; import org.avni.server.service.ImportLocationsConstants; @@ -42,6 +43,14 @@ public void editLocation(Row row, List allErrorMsgs) { newLocationParentAddressLevel = locationRepository.findByTitleLineageIgnoreCase(newLocationParentTitleLineage).orElse(null); if (newLocationParentAddressLevel == null) { allErrorMsgs.add(String.format("Provided new location parent does not exist in Avni. Please add it or check for spelling mistakes and ensure space between two locations - '%s'", newLocationParentTitleLineage)); + throw new RuntimeException(String.join(", ", allErrorMsgs)); + } + AddressLevelType currentParentType = null; + AddressLevel currentParent = existingLocationAddressLevel.get().getParentLocation(); + if (currentParent != null) {currentParentType = currentParent.getType();} + if (!newLocationParentAddressLevel.getType().equals(currentParentType)) { + allErrorMsgs.add("Provided new location parent is of a different type from current parent."); + throw new RuntimeException(String.join(", ", allErrorMsgs)); } } updateExistingLocation(existingLocationAddressLevel.get(), newLocationParentAddressLevel, row, allErrorMsgs); diff --git a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationModifier.java b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationModifier.java index f427ea0df..bc7394577 100644 --- a/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationModifier.java +++ b/avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/BulkLocationModifier.java @@ -3,6 +3,8 @@ import org.avni.server.application.FormType; import org.avni.server.dao.LocationRepository; import org.avni.server.domain.AddressLevel; +import org.avni.server.domain.ObservationCollection; +import org.avni.server.geo.Point; import org.avni.server.importer.batch.csv.creator.LocationCreator; import org.avni.server.importer.batch.csv.creator.ObservationCreator; import org.avni.server.importer.batch.csv.writer.header.LocationHeaders; @@ -22,8 +24,10 @@ public BulkLocationModifier(LocationRepository locationRepository, ObservationCr protected void updateLocationProperties(Row row, List allErrorMsgs, AddressLevel location) { LocationCreator locationCreator = new LocationCreator(); - location.setGpsCoordinates(locationCreator.getGeoLocation(row, LocationHeaders.gpsCoordinates, allErrorMsgs)); - location.setLocationProperties(observationCreator.getObservations(row, headers, allErrorMsgs, FormType.Location, location.getLocationProperties())); + Point gpsCoordinates = locationCreator.getGeoLocation(row, LocationHeaders.gpsCoordinates, allErrorMsgs); + if (gpsCoordinates != null) location.setGpsCoordinates(gpsCoordinates); + ObservationCollection locationProperties = observationCreator.getObservations(row, headers, allErrorMsgs, FormType.Location, location.getLocationProperties()); + if (!locationProperties.isEmpty()) location.setLocationProperties(locationProperties); locationRepository.save(location); } } diff --git a/avni-server-api/src/main/java/org/avni/server/service/LocationService.java b/avni-server-api/src/main/java/org/avni/server/service/LocationService.java index 93b239ea0..8dac0d0c8 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/LocationService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/LocationService.java @@ -178,11 +178,12 @@ public AddressLevel update(LocationEditContract locationEditContract, Long id) { } public void updateParent(AddressLevel location, AddressLevel newParent) { - updateDescendantLocationLineage(locationRepository.findAllByParent(location), location.getParentId(), newParent.getId()); - updateLocationMapping(location, newParent); - location.setLineage(updateLineage(location.getLineage(), location.getParentId(), newParent.getId())); Long oldParentId = location.getParentId(); + location.setLineage(updateLineage(location, newParent.getLineage())); location.setParent(newParent); + locationRepository.save(location); + updateDescendantLocationLineage(locationRepository.findAllByParent(location), location.getLineage()); + updateLocationMapping(location, newParent); resetSyncService.recordLocationParentChange(location, oldParentId); } @@ -198,22 +199,16 @@ private void updateLocationMapping(AddressLevel location, AddressLevel newParent locationMappingRepository.saveAll(updatedLocationMappings); } - private String updateLineage(String lineage, Long oldParentId, Long newParentId) { - if (oldParentId == null) { - return newParentId + "." + lineage; - } - return lineage.replaceAll(oldParentId.toString(), newParentId.toString()); + private String updateLineage(AddressLevel location, String parentLineage) { + return parentLineage + "." + location.getId(); } - private void updateDescendantLocationLineage(List children, Long oldId, Long newId) { - if (children.isEmpty()) { - return; - } else { + private void updateDescendantLocationLineage(List children, String parentLineage) { + if (!children.isEmpty()) { children.forEach(child -> { - String lineage = child.getLineage(); - child.setLineage(updateLineage(lineage, oldId, newId)); + child.setLineage(updateLineage(child, parentLineage)); locationRepository.save(child); - updateDescendantLocationLineage(locationRepository.findAllByParent(child), oldId, newId); + updateDescendantLocationLineage(locationRepository.findAllByParent(child), child.getLineage()); }); } } diff --git a/avni-server-api/src/test/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditorIntegrationTest.java b/avni-server-api/src/test/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditorIntegrationTest.java index 25688cf8d..3faaa464e 100644 --- a/avni-server-api/src/test/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditorIntegrationTest.java +++ b/avni-server-api/src/test/java/org/avni/server/importer/batch/csv/writer/BulkLocationEditorIntegrationTest.java @@ -1,7 +1,6 @@ package org.avni.server.importer.batch.csv.writer; import org.avni.server.application.*; -import org.avni.server.dao.AddressLevelTypeRepository; import org.avni.server.dao.LocationRepository; import org.avni.server.dao.application.FormRepository; import org.avni.server.domain.AddressLevel; @@ -12,7 +11,6 @@ import org.avni.server.domain.factory.AddressLevelTypeBuilder; import org.avni.server.domain.factory.metadata.TestFormBuilder; import org.avni.server.importer.batch.model.Row; -import org.avni.server.service.LocationHierarchyService; import org.avni.server.service.builder.TestConceptService; import org.avni.server.service.builder.TestDataSetupService; import org.avni.server.service.builder.TestLocationService; @@ -21,7 +19,6 @@ import org.springframework.test.context.jdbc.Sql; import java.util.*; -import java.util.stream.IntStream; import static org.junit.Assert.*; @@ -203,6 +200,13 @@ public void shouldEdit() { verifyExists("Bihar", "District2", "Block21"), verifyNotExists("Bihar, District2, Block21Town")); + // change to parent at a different level from current parent's level + failure(header("Location with full hierarchy", "New location name", "Parent location with full hierarchy", "GPS coordinates"), + dataRow("Bihar, District2, Block21", " Block21Town", "Bihar", "23.45,43.85"), + error("Provided new location parent is of a different type from current parent."), + verifyExists("Bihar", "District2", "Block21"), + verifyNotExists("Bihar, District2, Block21Town")); + treatAsDescriptor(header("Location with full hierarchy", "New location name", "Parent location with full hierarchy", "GPS coordinates"), dataRow("Can be found from Admin -> Locations -> Click Export. Used to specify which location's fields need to be updated. mandatory field", "Enter new name here ONLY if it needs to be updated",