diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/AbstractEventService.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/AbstractEventService.java index ad9acb7c3ca8..dcd11558b0a3 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/AbstractEventService.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/AbstractEventService.java @@ -790,6 +790,15 @@ public ImportSummary updateEventDataValues( // data elements .collect(Collectors.toSet()); + for (DataValue dataValue : event.getDataValues()) { + // data element has been deleted + if (eventDataValues.stream() + .noneMatch(e -> e.getDataElement().equals(dataValue.getDataElement()))) { + EventDataValue eventDataValue = new EventDataValue(); + eventDataValue.setDataElement(dataValue.getDataElement()); + eventDataValues.add(eventDataValue); + } + } return eventManager.updateEventDataValues(event, eventDataValues, context); } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/persistence/DefaultEventPersistenceService.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/persistence/DefaultEventPersistenceService.java index aa4b0b11d4af..b2a490f9e1db 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/persistence/DefaultEventPersistenceService.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/deprecated/tracker/event/persistence/DefaultEventPersistenceService.java @@ -128,34 +128,55 @@ public void updateEventDataValues( org.hisp.dhis.dxf2.deprecated.tracker.event.Event event, WorkContext workContext) throws JsonProcessingException { - - String uid = de.getDataElement(); - de.setDataElement(null); // de uid is used as a key in the json, so we don't need it here - - String query = - """ - UPDATE event SET - eventdatavalues= (CASE - WHEN eventdatavalues->:de IS NOT NULL - THEN jsonb_set(eventdatavalues, '{%1$s}', (eventdatavalues->:de) || '%2$s') - WHEN eventdatavalues->:de IS NULL - THEN jsonb_insert(eventdatavalues, '{%1$s}', '%2$s') - END) , - lastupdated = current_timestamp, - lastupdatedbyuserinfo = CAST(:lastupdatedbyuserinfo as jsonb) - WHERE uid = :event - """ - .formatted(uid, mapper.writeValueAsString(de)); - - entityManager - .createNativeQuery(query) - .setParameter("event", event.getEvent()) - .setParameter("de", uid) - .setParameter( - "lastupdatedbyuserinfo", - mapper.writeValueAsString( - UserInfoSnapshot.from(workContext.getImportOptions().getUser()))) - .executeUpdate(); + String query; + String deUid = de.getDataElement(); + + if (de.getValue() == null) { + // delete + query = + String.format( + " UPDATE event SET eventdatavalues = eventdatavalues\\:\\:jsonb - '%1$s'" + + ", lastupdated = current_timestamp" + + ", lastupdatedbyuserinfo = CAST(:lastupdatedbyuserinfo as jsonb) " + + " WHERE uid = :event", + deUid); + + entityManager + .createNativeQuery(query) + .setParameter("event", event.getEvent()) + .setParameter( + "lastupdatedbyuserinfo", + mapper.writeValueAsString( + UserInfoSnapshot.from(workContext.getImportOptions().getUser()))) + .executeUpdate(); + } else { + // merge + de.setDataElement(null); // de uid is used as a key in the json, so we don't need it here + + query = + String.format( + " UPDATE event SET" + + " eventdatavalues= (CASE" + + " WHEN eventdatavalues->:de IS NOT NULL" + + " THEN jsonb_set(eventdatavalues, '{%1$s}', (eventdatavalues->:de) || '%2$s')" + + " WHEN eventdatavalues->:de IS NULL" + + " THEN jsonb_insert(eventdatavalues, '{%1$s}', '%2$s')" + + " END) ," + + " lastupdated = current_timestamp" + + " ,lastupdatedbyuserinfo = CAST(:lastupdatedbyuserinfo as jsonb)" + + " WHERE uid = :event", + deUid, mapper.writeValueAsString(de)); + + entityManager + .createNativeQuery(query) + .setParameter("event", event.getEvent()) + .setParameter("de", deUid) + .setParameter( + "lastupdatedbyuserinfo", + mapper.writeValueAsString( + UserInfoSnapshot.from(workContext.getImportOptions().getUser()))) + .executeUpdate(); + } } @Override diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dxf2/deprecated/tracker/EventImportTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dxf2/deprecated/tracker/EventImportTest.java index 20406468b1e7..3fc59e8e5e8e 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dxf2/deprecated/tracker/EventImportTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dxf2/deprecated/tracker/EventImportTest.java @@ -336,6 +336,56 @@ void shouldUpdateEventDataValues_whenAddingDataValuesToEvent() throws IOExceptio assertTrue(trackedEntityInstance.getLastUpdated().compareTo(toIso8601NoTz(now)) > 0); } + @Test + void shouldDeleteDataElementFromEventDataValues_whenSetDataValueToNull() throws IOException { + InputStream is = + createEventJsonInputStream( + programB.getUid(), + programStageB.getUid(), + organisationUnitB.getUid(), + trackedEntityInstanceMaleA.getTrackedEntityInstance(), + dataElementB, + "10"); + String uid = eventService.addEventsJson(is, null).getImportSummaries().get(0).getReference(); + + org.hisp.dhis.dxf2.deprecated.tracker.event.Event event = createEvent(uid); + + Event ev = programStageInstanceService.getEvent(event.getUid()); + + assertNotNull(ev); + assertEquals(1, ev.getEventDataValues().size()); + + // delete data Element in Event Data Values by setting its value to null + + DataValue dataValueB = new DataValue(); + dataValueB.setValue(null); + dataValueB.setDataElement(dataElementB.getUid()); + dataValueB.setStoredBy(superUser.getName()); + + event.setDataValues(Set.of(dataValueB)); + + Date now = new Date(); + + eventService.updateEventDataValues(event); + + manager.clear(); + + ev = programStageInstanceService.getEvent(event.getUid()); + + EventDataValue eventDataValueB = + ev.getEventDataValues().stream() + .filter(edv -> edv.getDataElement().equals(dataValueB.getDataElement())) + .findFirst() + .orElse(null); + + assertNull(eventDataValueB); + + TrackedEntityInstance trackedEntityInstance = + trackedEntityInstanceService.getTrackedEntityInstance( + trackedEntityInstanceMaleA.getTrackedEntityInstance()); + assertTrue(trackedEntityInstance.getLastUpdated().compareTo(toIso8601NoTz(now)) > 0); + } + @Test void testAddEventOnProgramWithoutRegistration() throws IOException { InputStream is =