Skip to content

Commit

Permalink
fix: Fix enrollment and event tables [DHIS2-12600]
Browse files Browse the repository at this point in the history
  • Loading branch information
enricocolasante committed Nov 18, 2024
1 parent 97fb8ad commit 79f093d
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle;
import org.hisp.dhis.feedback.ErrorCode;
import org.hisp.dhis.feedback.ErrorReport;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.preheat.PreheatIdentifier;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.EnrollmentStatus;
Expand All @@ -58,6 +59,8 @@ public class ProgramObjectBundleHook extends AbstractObjectBundleHook<Program> {

private final ProgramStageService programStageService;

private final OrganisationUnitService organisationUnitService;

private final AclService aclService;

private final IdentifiableObjectManager identifiableObjectManager;
Expand Down Expand Up @@ -133,6 +136,8 @@ private void addProgramInstance(Program program) {
enrollment.setProgram(program);
enrollment.setStatus(EnrollmentStatus.ACTIVE);
enrollment.setStoredBy("system-process");
enrollment.setOrganisationUnit(
organisationUnitService.getRootOrganisationUnits().iterator().next());

identifiableObjectManager.save(enrollment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import org.hisp.dhis.common.IdentifiableObjectManager;
import org.hisp.dhis.feedback.ErrorCode;
import org.hisp.dhis.feedback.ErrorReport;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.EnrollmentStatus;
import org.hisp.dhis.program.EventProgramEnrollmentService;
Expand All @@ -71,6 +73,8 @@ class ProgramObjectBundleHookTest {

@Mock private ProgramStageService programStageService;

@Mock private OrganisationUnitService organisationUnitService;

@Mock private AclService aclService;

@Mock private IdentifiableObjectManager identifiableObjectManager;
Expand All @@ -83,6 +87,7 @@ public void setUp() {
new ProgramObjectBundleHook(
eventProgramEnrollmentService,
programStageService,
organisationUnitService,
aclService,
identifiableObjectManager);

Expand All @@ -106,6 +111,8 @@ void verifyMissingBundleIsIgnored() {

@Test
void verifyProgramInstanceIsSavedForEventProgram() {
when(organisationUnitService.getRootOrganisationUnits())
.thenReturn(List.of(new OrganisationUnit()));
ArgumentCaptor<Enrollment> argument = ArgumentCaptor.forClass(Enrollment.class);

programA.setProgramType(ProgramType.WITHOUT_REGISTRATION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.EnrollmentStatus;
import org.hisp.dhis.program.ProgramType;
import org.hisp.dhis.security.acl.AclService;
import org.hisp.dhis.tracker.export.Order;
import org.hisp.dhis.tracker.export.Page;
Expand Down Expand Up @@ -192,6 +193,8 @@ private QueryWithOrderBy buildEnrollmentHql(EnrollmentQueryParams params) {
hql += hlp.whereAnd() + "en.program.uid = '" + params.getProgram().getUid() + "'";
}

hql += hlp.whereAnd() + "en.program.programType = '" + ProgramType.WITH_REGISTRATION + "'";

if (params.hasEnrollmentStatus()) {
hql += hlp.whereAnd() + "en." + STATUS + " = '" + params.getEnrollmentStatus() + "'";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,7 @@ public void validate(
// If event is newly created, or going to be deleted, capture scope
// has to be checked
if (program.isWithoutRegistration() || strategy.isCreate() || strategy.isDelete()) {
if (organisationUnit == null) {
log.warn(ORG_UNIT_NO_USER_ASSIGNED, event.getUid());
} else {
checkOrgUnitInCaptureScope(reporter, event, organisationUnit, bundle.getUser());
}
checkOrgUnitInCaptureScope(reporter, event, organisationUnit, bundle.getUser());
}

UID teUid = getTeUidFromEvent(bundle, event, program);
Expand Down Expand Up @@ -304,9 +300,7 @@ private void checkEventOrgUnitWriteAccess(
OrganisationUnit eventOrgUnit,
boolean isCreatableInSearchScope,
UserDetails user) {
if (eventOrgUnit == null) {
log.warn(ORG_UNIT_NO_USER_ASSIGNED, event.getUid());
} else if (isCreatableInSearchScope
if (isCreatableInSearchScope
? !user.isInUserEffectiveSearchOrgUnitHierarchy(eventOrgUnit.getPath())
: !user.isInUserHierarchy(eventOrgUnit.getPath())) {
reporter.addError(event, ValidationCode.E1000, user, eventOrgUnit);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- Delete invalid events linked to invalid enrollments.
delete from event e where e.enrollmentid in (
select en.enrollmentid
from enrollment en join program p on en.programid = p.programid
where p.type = 'WITH_REGISTRATION'
and en.trackedentityid is null
);

-- Delete invalid enrollments that are part of a tracker program and
-- have null tracked entity.
delete from enrollment en where en.programid in (
select p.programid
from program p
where p.type = 'WITH_REGISTRATION'
)
and en.trackedentityid is null;

-- Update null organisation unit of enrollments to organisation unit of one of its events
update enrollment en set organisationunitid =
(select distinct ev.organisationunitid
from event ev
where en.enrollmentid = ev.enrollmentid
and ev.organisationunitid is not null
limit 1)
where en.organisationunitid is null;

-- If organisationunitid column is still null for any placeholder enrollment,
-- update organisation unit to root organisation unit.
-- Placeholder enrollments do not have a tracked entity, so we need to use one well-know
-- organisation unit.
-- Organisation unit for this enrollments is never used anyway but we still need to fill in a value.
update enrollment en set organisationunitid = (
select distinct organisationunitid
from organisationunit
where parentid is null
limit 1
)
where en.organisationunitid is null
and (select type from program p where en.programid = p.programid) = 'WITHOUT_REGISTRATION';

-- If organisationunitid column is still null for any enrollment that is not a placeholder,
-- use the tracked entity organisation unit.
-- Tracked entity organisation unit is guaranteed to be not null.
update enrollment en set organisationunitid =
(select te.organisationunitid
from trackedentity te
where en.trackedentityid = te.trackedentityid)
where en.organisationunitid is null
and (select type from program p where en.programid = p.programid) = 'WITH_REGISTRATION';

alter table enrollment alter column organisationunitid set not null;

-- Update null organisation unit of event to organisation unit the enrollment
-- that at this point is guaranteed to be not null.
update event ev set organisationunitid = (
select organisationunitid
from enrollment en
where en.enrollmentid = ev.enrollmentid)
where ev.organisationunitid is null;

alter table event alter column organisationunitid set not null;

0 comments on commit 79f093d

Please sign in to comment.