diff --git a/package.json b/package.json index 9b5581c..9eaa1ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@eyeseetea/d2-api", "description": "Typed wrapper over DHIS2 API", - "version": "1.9.2", + "version": "1.9.3", "license": "GPL-3.0", "author": "EyeSeeTea team", "repository": { diff --git a/src/api/d2Api.ts b/src/api/d2Api.ts index 3e094d4..2996305 100644 --- a/src/api/d2Api.ts +++ b/src/api/d2Api.ts @@ -20,9 +20,10 @@ import { MessageConversations } from "./messageConversations"; import { Metadata } from "./metadata"; import { Model } from "./model"; import { Sharing } from "./sharing"; +import { SqlViews } from "./SqlViews"; import { System } from "./system"; +import { TrackedEntityInstances } from "./trackedEntityInstances"; import { D2ApiOptions, D2ApiRequest, IndexedModels } from "./types"; -import { SqlViews } from "./SqlViews"; export class D2ApiGeneric { public baseUrl: string; @@ -141,6 +142,11 @@ export abstract class D2ApiVersioned< return new Events(this); } + @cache() + get trackedEntityInstances() { + return new TrackedEntityInstances(this); + } + @cache() get system() { return new System(this); diff --git a/src/api/system.ts b/src/api/system.ts index ef57ae9..fe41652 100644 --- a/src/api/system.ts +++ b/src/api/system.ts @@ -6,6 +6,7 @@ import { D2ApiGeneric } from "./d2Api"; import { DataValueSetsPostResponse } from "./dataValues"; import { EventsPostResponse } from "./events"; import { MetadataResponse } from "./metadata"; +import { TeiPostResponse } from "./trackedEntityInstances"; export class System { constructor(public d2Api: D2ApiGeneric) {} @@ -209,4 +210,5 @@ export type WaitForResponse = { DATAVALUE_IMPORT: DataValueSetsPostResponse; EVENT_IMPORT: EventsPostResponse; METADATA_IMPORT: MetadataResponse; + TEI_IMPORT: TeiPostResponse; }; diff --git a/src/api/trackedEntityInstances.ts b/src/api/trackedEntityInstances.ts new file mode 100644 index 0000000..9d5c36a --- /dev/null +++ b/src/api/trackedEntityInstances.ts @@ -0,0 +1,197 @@ +import { Id, Pager } from "./base"; +import { AsyncPostResponse, D2ApiResponse, HttpResponse } from "./common"; +import { D2ApiGeneric } from "./d2Api"; + +export class TrackedEntityInstances { + constructor(public d2Api: D2ApiGeneric) {} + + get(params: TeiGetRequest): D2ApiResponse { + return this.d2Api.get("/trackedEntityInstances", { + ...params, + ou: params.ou ? params.ou.join(";") : undefined, + paging: true, + }); + } + + getAll(params: TeiGetRequest): D2ApiResponse { + return this.d2Api.get("/trackedEntityInstances", { + ...params, + ou: params.ou ? params.ou.join(";") : undefined, + paging: false, + page: undefined, + pageSize: undefined, + }); + } + + post( + params: TeiPostParams, + request: TeiPostRequest + ): D2ApiResponse> { + return this.d2Api.post>( + "/trackedEntityInstances", + { ...params, async: false }, + request + ); + } + + postAsync( + params: TeiPostParams, + request: TeiPostRequest + ): D2ApiResponse> { + return this.d2Api.post>( + "/trackedEntityInstances", + { ...params, async: true }, + request + ); + } +} + +export interface TrackedEntityInstance { + trackedEntityInstance: Id; + trackedEntityType: Id; + inactive: boolean; + orgUnit: Id; + attributes: Attribute[]; + enrollments: Enrollment[]; + relationships: Relationship[]; +} + +export interface Relationship { + relationship: Id; + relationshipType: Id; + relationshipName: string; + from: RelationshipItem; + to: RelationshipItem; +} + +export interface RelationshipItem { + trackedEntityInstance?: { + trackedEntityInstance: Id; + }; + event?: { event: Id }; +} + +export interface Enrollment { + enrollment: Id; + program: Id; + orgUnit: Id; + enrollmentDate: string; + incidentDate: string; + events?: Event[]; +} + +export interface AttributeValue { + attribute: Attribute; + value: string; + optionId?: Id; +} + +export interface Attribute { + attribute: Id; + valueType?: string; + value: string; +} + +export type TeiOuRequest = + | { ouMode?: "ACCESSIBLE" | "CAPTURE" | "ALL"; ou?: never[] } + | { ouMode?: "SELECTED" | "CHILDREN" | "DESCENDANTS"; ou: Id[] }; + +export type TeiGetRequest = TeiOuRequest & { + // Program and tracked entity type cannot be specified simultaneously + program?: Id; + trackedEntityType?: Id; + programStatus?: "ACTIVE" | "COMPLETED" | "CANCELLED"; + followUp?: boolean; + order?: string; + pageSize?: number; + page?: number; + totalPages: true; + fields?: string; // TODO: Add inference + programStartDate?: string; + programEndDate?: string; + lastUpdatedStartDate?: string; + lastUpdatedEndDate?: string; + lastUpdatedDuration?: string; + assignedUserMode?: "CURRENT" | "PROVIDED" | "NONE" | "ANY"; + trackedEntityInstance?: string; + includeDeleted?: boolean; +}; + +export interface TeiGetResponse { + trackedEntityInstances: TrackedEntityInstance[]; +} + +export interface PaginatedTeiGetResponse extends TeiGetResponse { + pager: Pager; +} + +export interface TeiPostRequest { + trackedEntityInstances: Array<{ + trackedEntityInstance: Id; + trackedEntityType: Id; + inactive?: boolean; + orgUnit: Id; + attributes: Attribute[]; + enrollments: Enrollment[]; + relationships: Relationship[]; + }>; +} + +export type TeiPostParams = Partial<{ + idScheme: string; + dataElementIdScheme: string; + orgUnitIdScheme: string; + skipNotifications: boolean; + skipFirst: boolean; + strategy: "CREATE" | "UPDATE" | "CREATE_AND_UPDATE" | "DELETE"; + importReportMode: "FULL" | "ERRORS" | "DEBUG"; + async: boolean; + dryRun: boolean; +}>; + +export interface TeiPostResponse { + responseType: "ImportSummaries"; + status: "ERROR" | "SUCCESS"; + imported: number; + updated: number; + deleted: number; + ignored: number; + total: number; + importSummaries?: Array< + | { + responseType: "ImportSummary"; + status: "ERROR"; + reference?: string; + conflicts: Array<{ + object: string; + value: string; + }>; + importCount: { + imported: number; + updated: number; + ignored: number; + deleted: number; + }; + } + | { + responseType: "ImportSummary"; + status: "SUCCESS"; + reference: string; + importCount: { + imported: number; + updated: number; + ignored: number; + deleted: number; + }; + enrollments: { + responseType: "ImportSummaries"; + status: "ERROR" | "SUCCESS"; + imported: number; + updated: number; + deleted: number; + ignored: number; + total: number; + }; + } + >; +}