Skip to content

Commit 9ed772c

Browse files
1t5j0ypetmongrels
authored andcommitted
#688 | Create SubjectMigration (if required) if Subject is updated via csv upload
1 parent 0116227 commit 9ed772c

File tree

5 files changed

+25
-17
lines changed

5 files changed

+25
-17
lines changed

avni-server-api/src/main/java/org/avni/server/importer/batch/csv/writer/SubjectWriter.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class SubjectWriter extends EntityWriter implements ItemWriter<Row>, Seri
4646
private final S3Service s3Service;
4747
private final EntityApprovalStatusWriter entityApprovalStatusWriter;
4848
private AddressLevelCreator addressLevelCreator;
49+
private final SubjectMigrationService subjectMigrationService;
4950

5051
private static final Logger logger = LoggerFactory.getLogger(SubjectWriter.class);
5152

@@ -63,7 +64,7 @@ public SubjectWriter(AddressLevelTypeRepository addressLevelTypeRepository,
6364
ObservationCreator observationCreator, IndividualService individualService, EntityApprovalStatusWriter entityApprovalStatusWriter,
6465
S3Service s3Service,
6566
OrganisationConfigService organisationConfigService,
66-
AddressLevelCreator addressLevelCreator) {
67+
AddressLevelCreator addressLevelCreator, SubjectMigrationService subjectMigrationService) {
6768
super(organisationConfigService);
6869
this.addressLevelTypeRepository = addressLevelTypeRepository;
6970
this.locationRepository = locationRepository;
@@ -79,6 +80,7 @@ public SubjectWriter(AddressLevelTypeRepository addressLevelTypeRepository,
7980
this.individualService = individualService;
8081
this.entityApprovalStatusWriter = entityApprovalStatusWriter;
8182
this.addressLevelCreator = addressLevelCreator;
83+
this.subjectMigrationService = subjectMigrationService;
8284
this.locationCreator = new LocationCreator();
8385
this.s3Service = s3Service;
8486
}
@@ -94,6 +96,8 @@ private void write(Row row) throws Exception {
9496
locationTypes.sort(Comparator.comparingDouble(AddressLevelType::getLevel).reversed());
9597

9698
Individual individual = getOrCreateIndividual(row);
99+
AddressLevel oldAddressLevel = individual.getAddressLevel();
100+
ObservationCollection oldObservations = individual.getObservations();
97101
List<String> allErrorMsgs = new ArrayList<>();
98102

99103
SubjectType subjectType = subjectTypeCreator.getSubjectType(row.get(SubjectHeaders.subjectTypeHeader), SubjectHeaders.subjectTypeHeader);
@@ -127,6 +131,9 @@ private void write(Row row) throws Exception {
127131
savedIndividual = individualService.save(individual);
128132
visitCreator.saveScheduledVisits(formMapping.getType(), savedIndividual.getUuid(), null, ruleResponse.getVisitSchedules(), null);
129133
}
134+
if (oldAddressLevel != null) { // existing subject is being updated
135+
subjectMigrationService.markSubjectMigrationIfRequired(savedIndividual.getUuid(), oldAddressLevel, savedIndividual.getAddressLevel(), oldObservations, savedIndividual.getObservations(), false);
136+
}
130137
entityApprovalStatusWriter.saveStatus(formMapping, savedIndividual.getId(), EntityApprovalStatus.EntityType.Subject, savedIndividual.getSubjectType().getUuid());
131138
} catch (Exception e) {
132139
logger.warn("Error in writing row", e);

avni-server-api/src/main/java/org/avni/server/service/SubjectMigrationService.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -75,28 +75,29 @@ public boolean isScopeEntityChanged(DateTime lastModifiedDateTime, String subjec
7575
This problem is illustrated in this test - org.avni.server.dao.SubjectMigrationIntegrationTest.migrations_created_by_one_user_is_returned_for_another_user_even_when_concept_attributes_dont_match
7676
At this moment the performance of this seems small as other filters help in reducing the number of records. Functionally this is not an issue because mobile app does the checks before applying subject migration. */
7777
@Transactional
78-
public void markSubjectMigrationIfRequired(String individualUuid, AddressLevel newAddressLevel, ObservationCollection newObservations, boolean executingInBulk) {
78+
public void markSubjectMigrationIfRequired(String individualUuid, AddressLevel oldAddressLevel, AddressLevel newAddressLevel, ObservationCollection oldObservations, ObservationCollection newObservations, boolean executingInBulk) {
7979
Individual individual = individualRepository.findByUuid(individualUuid);
8080
if (individual == null || newAddressLevel == null) {
8181
return;
8282
}
8383
SubjectType subjectType = individual.getSubjectType();
8484
String syncConcept1 = subjectType.getSyncRegistrationConcept1();
8585
String syncConcept2 = subjectType.getSyncRegistrationConcept2();
86-
ObservationCollection oldObservations = individual.getObservations();
86+
if (oldObservations == null) oldObservations = individual.getObservations();
8787
String oldObsSingleStringValueSyncConcept1 = oldObservations.getObjectAsSingleStringValue(syncConcept1);
8888
String newObsSingleStringValueSyncConcept1 = newObservations.getObjectAsSingleStringValue(syncConcept1);
8989
String oldObsSingleStringValueSyncConcept2 = oldObservations.getObjectAsSingleStringValue(syncConcept2);
9090
String newObsSingleStringValueSyncConcept2 = newObservations.getObjectAsSingleStringValue(syncConcept2);
91-
if (!Objects.equals(individual.getAddressLevel().getId(), newAddressLevel.getId()) ||
91+
if (oldAddressLevel == null) oldAddressLevel = individual.getAddressLevel();
92+
if (!Objects.equals(oldAddressLevel.getId(), newAddressLevel.getId()) ||
9293
!Objects.equals(oldObsSingleStringValueSyncConcept1, newObsSingleStringValueSyncConcept1) ||
9394
!Objects.equals(oldObsSingleStringValueSyncConcept2, newObsSingleStringValueSyncConcept2)) {
9495
logger.info(String.format("Migrating subject with UUID %s from %s to %s", individualUuid, addressLevelService.getTitleLineage(individual.getAddressLevel()), addressLevelService.getTitleLineage(newAddressLevel)));
9596
SubjectMigration subjectMigration = new SubjectMigration();
9697
subjectMigration.assignUUID();
9798
subjectMigration.setIndividual(individual);
9899
subjectMigration.setSubjectType(individual.getSubjectType());
99-
subjectMigration.setOldAddressLevel(individual.getAddressLevel());
100+
subjectMigration.setOldAddressLevel(oldAddressLevel);
100101
subjectMigration.setNewAddressLevel(newAddressLevel);
101102
if (!Objects.equals(oldObsSingleStringValueSyncConcept1, newObsSingleStringValueSyncConcept1)) {
102103
subjectMigration.setOldSyncConcept1Value(oldObsSingleStringValueSyncConcept1);
@@ -124,7 +125,7 @@ public void markSubjectMigrationIfRequired(String individualUuid, AddressLevel n
124125
@Transactional
125126
public void changeSubjectsAddressLevel(List<Individual> subjects, AddressLevel destAddressLevel) {
126127
subjects.forEach(individual -> {
127-
this.markSubjectMigrationIfRequired(individual.getUuid(), destAddressLevel, individual.getObservations(), true);
128+
this.markSubjectMigrationIfRequired(individual.getUuid(), null, destAddressLevel, null, individual.getObservations(), true);
128129
individual.setAddressLevel(destAddressLevel);
129130
individualRepository.save(individual);
130131
});

avni-server-api/src/main/java/org/avni/server/web/IndividualController.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public AvniEntityResponse save(@RequestBody IndividualRequest individualRequest)
117117
}
118118

119119
private void markSubjectMigrationIfRequired(IndividualRequest individualRequest, ObservationCollection newObservations) {
120-
subjectMigrationService.markSubjectMigrationIfRequired(individualRequest.getUuid(), getAddressLevel(individualRequest), newObservations, false);
120+
subjectMigrationService.markSubjectMigrationIfRequired(individualRequest.getUuid(), null, getAddressLevel(individualRequest), null, newObservations, false);
121121
}
122122

123123
private void addObservationsFromDecisions(ObservationCollection observations, Decisions decisions) {

avni-server-api/src/main/java/org/avni/server/web/api/SubjectApiController.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ private void updateSubjectDetails(Individual subject, ApiSubjectRequest request)
193193
subject.setRegistrationDate(request.getRegistrationDate());
194194
ObservationCollection observations = RequestUtils.createObservations(request.getObservations(), conceptRepository);
195195
AddressLevel newAddressLevel = addressLevel.orElse(null);
196-
subjectMigrationService.markSubjectMigrationIfRequired(subject.getUuid(), newAddressLevel, observations, false);
196+
subjectMigrationService.markSubjectMigrationIfRequired(subject.getUuid(), null, newAddressLevel, null, observations, false);
197197
subject.setAddressLevel(newAddressLevel);
198198
if (subjectType.isPerson()) {
199199
subject.setDateOfBirth(request.getDateOfBirth());
@@ -268,7 +268,7 @@ private void patchSubject(Individual subject, Map<String, Object> request) throw
268268
Optional<AddressLevel> addressLevel = locationRepository.findByTitleLineageIgnoreCase(locationTitleLineage);
269269
AddressLevel newAddressLevel = addressLevel.orElseThrow(() -> new IllegalArgumentException(String.format("Address '%s' not found", locationTitleLineage)));
270270
subject.setAddressLevel(newAddressLevel);
271-
subjectMigrationService.markSubjectMigrationIfRequired(subject.getUuid(), newAddressLevel, subject.getObservations(), false);
271+
subjectMigrationService.markSubjectMigrationIfRequired(subject.getUuid(), null, newAddressLevel, null, subject.getObservations(), false);
272272
}
273273

274274
if (subject.getSubjectType().isPerson()) {

avni-server-api/src/test/java/org/avni/server/dao/SubjectMigrationIntegrationTest.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,23 @@ public void checkSyncStrategy() {
105105
// Subject with one concept attribute, location migrated
106106
ObservationCollection observations = ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 11").getUuid());
107107
Individual s1 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(observations).build());
108-
subjectMigrationService.markSubjectMigrationIfRequired(s1.getUuid(), catchmentData.getAddressLevel2(), observations, false);
108+
subjectMigrationService.markSubjectMigrationIfRequired(s1.getUuid(), null, catchmentData.getAddressLevel2(), null, observations, false);
109109
List syncDetails = getSyncDetails();
110110
assertTrue(syncDetails.contains(EntitySyncStatusContract.createForComparison(SyncEntityName.SubjectMigration.name(), subjectType.getUuid())));
111111
assertEquals(1, getMigrations(subjectType, DateTime.now().minusDays(1), DateTime.now()).size());
112112
assertTrue(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s1));
113113

114114
// Subject with one concept attribute, attribute migrated
115115
Individual s3 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 11").getUuid())).build());
116-
subjectMigrationService.markSubjectMigrationIfRequired(s3.getUuid(), catchmentData.getAddressLevel1(), ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 12").getUuid()), false);
116+
subjectMigrationService.markSubjectMigrationIfRequired(s3.getUuid(), null, catchmentData.getAddressLevel1(), null, ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 12").getUuid()), false);
117117
assertTrue(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s3));
118118
assertEquals(2, getMigrations(subjectType, DateTime.now().minusDays(1), DateTime.now()).size());
119119

120120
// Subject migrated but its old and new attributes are not assigned to user
121121
observations = ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 12").getUuid());
122122
ObservationCollection newObservations = ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 13").getUuid());
123123
Individual s7 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(observations).build());
124-
subjectMigrationService.markSubjectMigrationIfRequired(s7.getUuid(), catchmentData.getAddressLevel1(), newObservations, false);
124+
subjectMigrationService.markSubjectMigrationIfRequired(s7.getUuid(), null, catchmentData.getAddressLevel1(), null, newObservations, false);
125125
assertFalse(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s7));
126126
assertEquals(2, getMigrations(subjectType, DateTime.now().minusDays(1), DateTime.now()).size());
127127

@@ -140,23 +140,23 @@ public void checkSyncStrategy() {
140140
// Subject with two concept attributes, location migrated
141141
observations = new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 12")).addObservation(concept2, concept2.getAnswerConcept("Answer 22")).build();
142142
Individual s2 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(observations).build());
143-
subjectMigrationService.markSubjectMigrationIfRequired(s2.getUuid(), catchmentData.getAddressLevel2(), observations, false);
143+
subjectMigrationService.markSubjectMigrationIfRequired(s2.getUuid(), null, catchmentData.getAddressLevel2(), null, observations, false);
144144
assertTrue(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s2));
145145

146146
// Subject with two concept attributes, first attribute migrated
147147
Individual s4 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 11")).addObservation(concept2, concept2.getAnswerConcept("Answer 21")).build()).build());
148-
subjectMigrationService.markSubjectMigrationIfRequired(s4.getUuid(), catchmentData.getAddressLevel1(), new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 12")).addObservation(concept2, concept2.getAnswerConcept("Answer 21")).build(), false);
148+
subjectMigrationService.markSubjectMigrationIfRequired(s4.getUuid(), null, catchmentData.getAddressLevel1(), null, new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 12")).addObservation(concept2, concept2.getAnswerConcept("Answer 21")).build(), false);
149149
assertTrue(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s4));
150150

151151
// Subject with two concept attributes, second attribute migrated
152152
Individual s5 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 11")).addObservation(concept2, concept2.getAnswerConcept("Answer 21")).build()).build());
153-
subjectMigrationService.markSubjectMigrationIfRequired(s5.getUuid(), catchmentData.getAddressLevel1(), new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 11")).addObservation(concept2, concept2.getAnswerConcept("Answer 22")).build(), false);
153+
subjectMigrationService.markSubjectMigrationIfRequired(s5.getUuid(), null, catchmentData.getAddressLevel1(), null, new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 11")).addObservation(concept2, concept2.getAnswerConcept("Answer 22")).build(), false);
154154
boolean hasMigrationFor = hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s5);
155155
assertTrue(hasMigrationFor);
156156

157157
// Subject with two concept attributes, both attributes migrated
158158
Individual s6 = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 11")).addObservation(concept2, concept2.getAnswerConcept("Answer 21")).build()).build());
159-
subjectMigrationService.markSubjectMigrationIfRequired(s6.getUuid(), catchmentData.getAddressLevel1(), new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 12")).addObservation(concept2, concept2.getAnswerConcept("Answer 22")).build(), false);
159+
subjectMigrationService.markSubjectMigrationIfRequired(s6.getUuid(), null, catchmentData.getAddressLevel1(), null, new ObservationCollectionBuilder().addObservation(concept1, concept1.getAnswerConcept("Answer 12")).addObservation(concept2, concept2.getAnswerConcept("Answer 22")).build(), false);
160160
assertTrue(hasMigrationFor(subjectType, DateTime.now().minusDays(1), DateTime.now(), s6));
161161

162162
// User without sync attributes setup will not get any migration as that is more performance optimised. Setting
@@ -178,7 +178,7 @@ public void migrations_created_by_one_user_is_returned_for_another_user_even_whe
178178
ObservationCollection observations = ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 11").getUuid());
179179
ObservationCollection newObservations = ObservationCollectionBuilder.withOneObservation(concept1, concept1.getAnswerConcept("Answer 11").getUuid());
180180
Individual s = testSubjectService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(subjectType).withLocation(catchmentData.getAddressLevel1()).withObservations(observations).build());
181-
subjectMigrationService.markSubjectMigrationIfRequired(s.getUuid(), catchmentData.getAddressLevel2(), newObservations, false);
181+
subjectMigrationService.markSubjectMigrationIfRequired(s.getUuid(), null, catchmentData.getAddressLevel2(), null, newObservations, false);
182182
assertTrue(getSyncDetails().contains(EntitySyncStatusContract.createForComparison(SyncEntityName.SubjectMigration.name(), subjectType.getUuid())));
183183
assertEquals(1, getMigrations(subjectType, DateTime.now().minusDays(1), DateTime.now()).size());
184184

0 commit comments

Comments
 (0)