diff --git a/src/data/Dhis2Events.ts b/src/data/Dhis2Events.ts index 37835a58..1e0d1c5d 100644 --- a/src/data/Dhis2Events.ts +++ b/src/data/Dhis2Events.ts @@ -5,19 +5,9 @@ import { SynchronizationResult } from "../domain/entities/SynchronizationResult" import i18n from "../utils/i18n"; import { promiseMap } from "../utils/promises"; import { ImportPostResponse, postImport } from "./Dhis2Import"; -import { Program, TrackedEntityInstance } from "../domain/entities/TrackedEntityInstance"; -import { getApiTeiToUpload, Metadata } from "./Dhis2TrackedEntityInstances"; -import { Maybe } from "../types/utils"; -import { ImportDataPackageOptions } from "../domain/repositories/InstanceRepository"; -export async function postEvents( - api: D2Api, - events: Event[], - options: Maybe -): Promise { - const eventsWithEnrollment = options ? setEnrollmentToEvent(events, options) : events; - - const eventsResult = await promiseMap(_.chunk(eventsWithEnrollment, 200), eventsToSave => { +export async function postEvents(api: D2Api, events: Event[]): Promise { + return promiseMap(_.chunk(events, 200), eventsToSave => { return postImport( api, async () => await api.post("/tracker", {}, { events: eventsToSave }).getData(), @@ -28,29 +18,4 @@ export async function postEvents( } ); }); - - return eventsResult; -} - -function setEnrollmentToEvent(events: Event[], options: OptionEvents): Event[] { - const { existingTeis, teis, program, metadata } = options; - const apiTeis = teis.map(tei => getApiTeiToUpload(program, metadata, tei, existingTeis, options.importOptions)); - const teisByIds = _.keyBy(apiTeis, tei => tei.trackedEntity); - return events.map(event => { - const eventTeiId = event.trackedEntity ?? ""; - const tei = teisByIds[eventTeiId]; - const enrollmentId = tei?.enrollments[0]?.enrollment; - if (!enrollmentId) { - throw new Error(`Enrollment not found for event-tei: ${eventTeiId}-${event.trackedEntity}`); - } - return { ...event, enrollment: enrollmentId }; - }); } - -type OptionEvents = { - existingTeis: TrackedEntityInstance[]; - teis: TrackedEntityInstance[]; - program: Program; - metadata: Metadata; - importOptions: ImportDataPackageOptions; -}; diff --git a/src/data/Dhis2TrackedEntityInstances.ts b/src/data/Dhis2TrackedEntityInstances.ts index 9e458cb4..441bbaa2 100644 --- a/src/data/Dhis2TrackedEntityInstances.ts +++ b/src/data/Dhis2TrackedEntityInstances.ts @@ -15,7 +15,6 @@ import { D2Api, D2RelationshipType, Id, Ref } from "../types/d2-api"; import { KeysOfUnion } from "../types/utils"; import { promiseMap } from "../utils/promises"; import { getUid } from "./dhis2-uid"; -import { postEvents } from "./Dhis2Events"; import { buildOrgUnitMode, fromApiRelationships, @@ -162,13 +161,27 @@ export async function updateTrackedEntityInstances( if (!program) throw new Error(`Program not found: ${programId}`); const apiEvents = await getApiEvents(api, teis, dataEntries, metadata, teiSeed); + const eventsMap = _.groupBy(apiEvents, event => event.trackedEntity); const { preTeis, postTeis } = await splitTeis(api, teis, metadata); const options = { api, program, metadata, existingTeis }; return runSequentialPromisesOnSuccess([ - () => uploadTeis({ ...options, teis: preTeis, title: i18n.t("Create/update"), importOptions }), - () => uploadTeis({ ...options, teis: postTeis, title: i18n.t("Relationships"), importOptions }), - () => postEvents(api, apiEvents, { existingTeis, teis: teis, program, metadata, importOptions }), + () => + uploadTeis({ + ...options, + teis: preTeis, + title: i18n.t("Create/update"), + importOptions, + eventsByTei: eventsMap, + }), + () => + uploadTeis({ + ...options, + teis: postTeis, + title: i18n.t("Relationships"), + importOptions, + eventsByTei: eventsMap, + }), ]); } @@ -235,12 +248,15 @@ async function uploadTeis(options: { existingTeis: TrackedEntityInstance[]; title: string; importOptions: ImportDataPackageOptions; + eventsByTei: EventMap; }): Promise { - const { api, importOptions, program, metadata, teis, existingTeis, title } = options; + const { api, importOptions, program, metadata, teis, existingTeis, title, eventsByTei } = options; if (_.isEmpty(teis)) return []; - const apiTeis = teis.map(tei => getApiTeiToUpload(program, metadata, tei, existingTeis, importOptions)); + const apiTeis = teis.map(tei => + getApiTeiToUpload({ program, metadata, tei, existingTeis, importOptions, eventsByTei }) + ); const model = i18n.t("Tracked Entity Instance"); const teisResult = await promiseMap(_.chunk(apiTeis, 200), teisToSave => { @@ -358,13 +374,15 @@ async function getApiEvents( .value(); } -export function getApiTeiToUpload( - program: Program, - metadata: Metadata, - tei: TrackedEntityInstance, - existingTeis: TrackedEntityInstance[], - importOptions: ImportDataPackageOptions -): TrackedEntity { +function getApiTeiToUpload(options: { + program: Program; + metadata: Metadata; + tei: TrackedEntityInstance; + existingTeis: TrackedEntityInstance[]; + importOptions: ImportDataPackageOptions; + eventsByTei: EventMap; +}): TrackedEntityToSave { + const { program, metadata, tei, existingTeis, importOptions, eventsByTei } = options; const { orgUnit, enrollment, relationships } = tei; const optionById = _.keyBy(metadata.options, option => option.id); @@ -389,6 +407,9 @@ export function getApiTeiToUpload( }; }); + const enrollmentEvents = eventsByTei[tei.id] || []; + const apiEvents = enrollmentEvents.map(event => ({ ...event, enrollment: enrollmentId })); + return { trackedEntity: tei.id, trackedEntityType: program.trackedEntityType.id, @@ -404,6 +425,7 @@ export function getApiTeiToUpload( enrolledAt: enrollment.enrolledAt, occurredAt: enrollment.occurredAt || enrollment.enrolledAt, attributes: attributes, + events: apiEvents, }, ] : [], @@ -650,6 +672,14 @@ export type TrackedEntitiesD2ApiResponse = { pageCount?: number; }; +type TEIId = string; +type EventMap = Record; + +type EnrollmentWithEvents = Enrollment & { events: Event[] }; +type TrackedEntityToSave = Omit & { + enrollments: EnrollmentWithEvents[]; +}; + const constraintfields = { program: true, programStage: true, diff --git a/src/data/InstanceDhisRepository.ts b/src/data/InstanceDhisRepository.ts index f0cf1320..930f53cc 100644 --- a/src/data/InstanceDhisRepository.ts +++ b/src/data/InstanceDhisRepository.ts @@ -541,8 +541,7 @@ export class InstanceDhisRepository implements InstanceRepository { }; }); - // third value only required for program trackers - return postEvents(this.api, eventsToSave, undefined); + return postEvents(this.api, eventsToSave); } private async getEventProgramStage(programId: Id): Promise {