Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ihe stack 4/4 - DR Response #1405

Merged
merged 21 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
37b1ab8
feat(dr): dr response
jonahkaye Jan 4, 2024
f895426
feat(dr): removing old infra
jonahkaye Jan 4, 2024
670860c
feat(dr): rebasing
jonahkaye Jan 5, 2024
76084e2
feat(dr): refactoring error handling to reuse
jonahkaye Jan 5, 2024
3090d57
feat(dr): refactoring error handling and constants
jonahkaye Jan 5, 2024
3697e0e
Merge branch '1379-incoming-dq-dr' into 1379-dr-incoming
jonahkaye Jan 7, 2024
591a3f2
feat(dr): adding env vars to lambda
jonahkaye Jan 7, 2024
80edad9
feat(dr): deleting more deprecated files
jonahkaye Jan 8, 2024
d98af86
feat(dr): merging dq into dr and refactoring to use ihe gateway error
jonahkaye Jan 9, 2024
f1bca3c
feat(dr): merging 3/4 into 4/4
jonahkaye Jan 15, 2024
2988e27
feat(dr): merging develop into branch
jonahkaye Jan 25, 2024
9227dc3
feat(dq): nit
jonahkaye Jan 25, 2024
7f7a4b6
feat(dq): merge branch into branch
jonahkaye Jan 25, 2024
3519d73
feat(dr): nits and ready to merge
jonahkaye Jan 25, 2024
2293b94
feat(dr): merge branch to branch
jonahkaye Jan 25, 2024
d79316c
feat(dq): patch infra bug
jonahkaye Jan 25, 2024
aafd21e
Merge branch '1379-incoming-dq-dr' into 1379-dr-incoming
jonahkaye Jan 26, 2024
1bbec8f
feat(dq): make document retrieval endpoint work better on lambda
jonahkaye Jan 26, 2024
1d97394
Merge branch '1379-incoming-dq-dr' into 1379-dr-incoming
jonahkaye Jan 26, 2024
b7feac9
Merge branch 'develop' into 1379-dr-incoming
jonahkaye Jan 26, 2024
ac8499d
feat(dr): better error handling for debugging on internal requests
jonahkaye Jan 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(dr): rebasing
Refs: #1379
  • Loading branch information
jonahkaye committed Jan 5, 2024
commit 670860c3fa65a4d47d76e43c578ed7ce4f21d713
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Op } from "sequelize";
import NotFoundError from "../../errors/not-found";
import { ConnectedUser } from "../../models/connected-user";
import { ProviderOptions } from "../../shared/constants";
import { AtLeastOne } from "../../shared/types";
import { AtLeastOne } from "@metriport/shared";
import { capture } from "../../shared/notifications";

export const getConnectedUser = async ({
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/command/medical/admin/upload-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createDocReferenceContent, getFHIRDocRef } from "../../../external/fhir
import { metriportDataSourceExtension } from "../../../external/fhir/shared/extensions/metriport";
import { Config } from "../../../shared/config";
import { capture } from "../../../shared/notifications";
import { randomInt } from "../../../shared/numbers";
import { randomInt } from "@metriport/shared/common/numbers";
import { getPatientOrFail } from "../patient/get-patient";
import { cloneDeep } from "lodash";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ConvertResult,
DocumentQueryProgress,
DocumentQueryStatus,
} from "../../../../domain/medical/document-query";
} from "@metriport/core/domain/medical/document-query";
import { makeDocumentQueryProgress } from "../../../../domain/medical/__tests__/document-query";
import { makePatient, makePatientData } from "../../../../domain/medical/__tests__/patient";
import { PatientModel } from "../../../../models/medical/patient";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { uniqBy } from "lodash";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import { MAPIWebhookType } from "../../../domain/webhook";
import {
GroupedValidationResult,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Progress } from "../../../domain/medical/document-query";
import { Progress } from "@metriport/core/domain/medical/document-query";

export type MainProgressProps = keyof Pick<Progress, "total" | "status">;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
DocumentQueryProgress,
DocumentQueryStatus,
Progress,
} from "../../../domain/medical/document-query";
import { Patient, PatientCreate, PatientData } from "../../../domain/medical/patient";
} from "@metriport/core/domain/medical/document-query";
import { Patient, PatientCreate, PatientData } from "@metriport/core/domain/medical/patient";
import { PatientModel } from "../../../models/medical/patient";
import { executeOnDBTx } from "../../../models/transaction-wrapper";
import { capture } from "../../../shared/notifications";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocumentReferenceContent } from "@medplum/fhirtypes";
import { Document } from "@metriport/commonwell-sdk";
import { S3Utils } from "@metriport/core/external/aws/s3";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import {
DocumentWithMetriportId,
getFileExtension,
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/command/medical/document/document-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
DocumentQueryProgress,
DocumentQueryStatus,
Progress,
} from "../../../domain/medical/document-query";
import { Patient } from "../../../domain/medical/patient";
} from "@metriport/core/domain/medical/document-query";
import { Patient } from "@metriport/core/domain/medical/patient";
import { validateOptionalFacilityId } from "../../../domain/medical/patient-facility";
import { queryAndProcessDocuments as getDocumentsFromCW } from "../../../external/commonwell/document/document-query";
import { PatientModel } from "../../../models/medical/patient";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import { groupBy } from "lodash";
import { DocRefMapping } from "../../../domain/medical/docref-mapping";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import { convertCDAToFHIR } from "../../../external/fhir-converter/converter";
import { getDocuments as getDocumentsFromFHIRServer } from "../../../external/fhir/document/get-documents";
import { countResources } from "../../../external/fhir/patient/count-resources";
import { downloadedFromHIEs } from "../../../external/fhir/shared";
import { getMetriportContent } from "../../../external/fhir/shared/extensions/metriport";
import { Config } from "../../../shared/config";
import { errorToString } from "../../../shared/log";
import { formatNumber } from "../../../shared/numbers";
import { formatNumber } from "@metriport/shared/common/numbers";
import { getDocRefMappings } from "../docref-mapping/get-docref-mapping";
import { deleteConsolidated as deleteConsolidatedOnFHIRServer } from "../patient/consolidated-delete";
import { getPatientOrFail } from "../patient/get-patient";
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/command/medical/document/document-status.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DocumentQueryProgress, isProcessing } from "../../../domain/medical/document-query";
import { Patient } from "../../../domain/medical/patient";
import { DocumentQueryProgress, isProcessing } from "@metriport/core/domain/medical/document-query";
import { Patient } from "@metriport/core/domain/medical/patient";

export function areDocumentsProcessing(patient: Patient): boolean;
export function areDocumentsProcessing(progress: DocumentQueryProgress | undefined): boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import {
BulkGetDocumentsUrlProgress,
isBulkGetDocUrlProcessing,
BulkGetDocUrlStatus,
} from "../../../domain/medical/bulk-get-document-url";
} from "@metriport/core/domain/medical/bulk-get-document-url";
import { Util } from "../../../shared/util";
import { getPatientOrFail } from "../patient/get-patient";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import { uuidv7 } from "@metriport/core/util/uuid-v7";
import { storeBulkGetDocumentUrlQueryInit } from "../patient/bulk-get-doc-url-progress";
import { makeLambdaClient } from "../../../external/aws/lambda";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { faker } from "@faker-js/faker";
import { DocumentQueryProgress } from "../../../../domain/medical/document-query";
import { Patient } from "../../../../domain/medical/patient";
import { DocumentQueryProgress } from "@metriport/core/domain/medical/document-query";
import { Patient } from "@metriport/core/domain/medical/patient";
import { makeProgress } from "../../../../domain/medical/__tests__/document-query";
import { makePatient, makePatientData } from "../../../../domain/medical/__tests__/patient";
import { PatientModel } from "../../../../models/medical/patient";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Patient } from "../../../domain/medical/patient";
import { QueryProgress } from "../../../domain/medical/query-status";
import { Patient } from "@metriport/core/domain/medical/patient";
import { QueryProgress } from "@metriport/core/domain/medical/query-status";
import { PatientModel } from "../../../models/medical/patient";
import { executeOnDBTx } from "../../../models/transaction-wrapper";
import { getPatientOrFail } from "./get-patient";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStatusFromProgress, Progress } from "../../../domain/medical/document-query";
import { Patient } from "../../../domain/medical/patient";
import { getStatusFromProgress, Progress } from "@metriport/core/domain/medical/document-query";
import { Patient } from "@metriport/core/domain/medical/patient";
import { PatientModel } from "../../../models/medical/patient";
import { executeOnDBTx } from "../../../models/transaction-wrapper";
import { getPatientOrFail } from "./get-patient";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
BulkGetDocUrlStatus,
BulkGetDocumentsUrlProgress,
} from "../../../domain/medical/bulk-get-document-url";
import { Patient } from "../../../domain/medical/patient";
} from "@metriport/core/domain/medical/bulk-get-document-url";
import { Patient } from "@metriport/core/domain/medical/patient";
import { PatientModel } from "../../../models/medical/patient";
import { executeOnDBTx } from "../../../models/transaction-wrapper";
import { BaseUpdateCmdWithCustomer } from "../base-update-command";
Expand Down
129 changes: 77 additions & 52 deletions packages/api/src/command/medical/patient/consolidated-delete.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { OperationOutcomeError } from "@medplum/core";
import { OperationOutcomeIssue } from "@medplum/fhirtypes";
import { BundleEntry, Resource } from "@medplum/fhirtypes";
import { ResourceTypeForConsolidation } from "@metriport/api-sdk";
import { flatten } from "lodash";
import { Patient } from "../../../domain/medical/patient";
import { FhirClient } from "@metriport/core/external/fhir/api/api";
import { logDuration } from "@metriport/shared/common/duration";
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import { chunk, flatten } from "lodash";
import { Patient } from "@metriport/core/domain/medical/patient";
import { makeFhirApi } from "../../../external/fhir/api/api-factory";
import { getDetailFromOutcomeError } from "../../../external/fhir/shared";
import { capture } from "../../../shared/notifications";
import { Util } from "../../../shared/util";
import { getConsolidatedPatientData } from "./consolidated-get";

dayjs.extend(duration);

const MAX_ITEMS_PER_BATCH = 100;
const SUCCESS_CODE = `SUCCESSFUL_DELETE`;

export type DeleteConsolidatedFilters = {
resources?: ResourceTypeForConsolidation[];
docIds: string[];
Expand All @@ -28,37 +37,46 @@ export async function deleteConsolidated(params: DeleteConsolidatedParams): Prom
const { log } = Util.out(`deleteConsolidated - cxId ${patient.cxId}, patientId ${patient.id}`);
const fhir = makeFhirApi(patient.cxId);

const getResourcesToDelete = async () => {
try {
const bundle = await getConsolidatedPatientData({
patient,
documentIds: docIds,
resources,
});
const resourcesFromFHIRServer = bundle.entry;
if (!resourcesFromFHIRServer || resourcesFromFHIRServer.length <= 0) {
log(`No resources to delete`);
return;
}
const resourcesToDelete = await getResourcesToDelete(patient, docIds, resources, log);
if (!resourcesToDelete || resourcesToDelete.length <= 0) return;

const resourcesToDelete = resourcesFromFHIRServer.filter(r => {
const resource = r.resource;
if (!resource) return false;
// TODO make this dynamic, get a list of resources to exclude
return resource.resourceType !== "DocumentReference";
});
return resourcesToDelete;
} catch (error) {
const msg = `Failed to get consolidated FHIR resources`;
log(`${msg}: ${JSON.stringify(params)}`);
throw error;
}
};
await deleteResources(resourcesToDelete, patient, fhir, dryRun, log);
}

const resourcesToDelete = await getResourcesToDelete();
if (!resourcesToDelete || resourcesToDelete.length <= 0) return;
async function getResourcesToDelete(
patient: Pick<Patient, "id" | "cxId">,
documentIds: string[],
resources: ResourceTypeForConsolidation[] | undefined,
log: typeof console.log
): Promise<BundleEntry<Resource>[]> {
const bundle = await getConsolidatedPatientData({
patient,
documentIds,
resources,
});
const resourcesFromFHIRServer = bundle.entry;
if (!resourcesFromFHIRServer || resourcesFromFHIRServer.length <= 0) {
log(`No resources to delete`);
return [];
}

const resourcesToDelete = resourcesFromFHIRServer.filter(r => {
const resource = r.resource;
if (!resource) return false;
// TODO make this dynamic, get a list of resources to exclude
return resource.resourceType !== "DocumentReference";
});
return resourcesToDelete;
}

const entries = resourcesToDelete.flatMap(r => {
async function deleteResources(
resourcesToDelete: BundleEntry<Resource>[],
patient: Pick<Patient, "id" | "cxId">,
fhir: FhirClient,
dryRun: boolean,
log: typeof console.log
): Promise<void> {
const entriesForFHIRBundle = resourcesToDelete.flatMap(r => {
const resource = r.resource;
if (!resource || !resource.id || !resource.resourceType) return [];
return {
Expand All @@ -70,17 +88,34 @@ export async function deleteConsolidated(params: DeleteConsolidatedParams): Prom
});

if (dryRun) {
log(`[DRY-RUN] Would delete ${entries.length} resources from FHIR server`);
log(`[DRY-RUN] Would delete ${entriesForFHIRBundle.length} resources from FHIR server`);
return;
}

const chunks = chunk(entriesForFHIRBundle, MAX_ITEMS_PER_BATCH);
for (const [i, chunk] of chunks.entries()) {
log(`Deleting chunk ${i + 1}/${chunks.length}...`);
await deleteChunk(chunk, patient.id, fhir, log);
}
}

async function deleteChunk(
entries: BundleEntry<Resource>[],
patientId: string,
fhir: FhirClient,
log: typeof console.log
): Promise<void> {
try {
log(`Deleting ${entries.length} resources from FHIR server...`);
const resp = await fhir.executeBatch({
resourceType: "Bundle",
type: "transaction",
entry: entries,
});
const resp = await logDuration(
() =>
fhir.executeBatch({
resourceType: "Bundle",
type: "transaction",
entry: entries,
}),
{ log, withMinutes: true }
);
const issues = resp.entry?.flatMap(e => {
return e.response?.outcome?.issue?.flatMap(i => {
return i.details?.coding?.map(c => {
Expand All @@ -99,35 +134,25 @@ export async function deleteConsolidated(params: DeleteConsolidatedParams): Prom
capture.error(msg, {
extra: {
context: `deleteConsolidated.graceful-fail`,
patientId: patient.id,
patientId: patientId,
issues: issuesFlattened,
},
});
}
} catch (error) {
const detailMsg = error instanceof OperationOutcomeError ? getMessage(error) : String(error);
const detailMsg =
error instanceof OperationOutcomeError ? getDetailFromOutcomeError(error) : String(error);
const msg = `Failed to delete FHIR resources`;
log(`${msg} - ${detailMsg} - ${JSON.stringify(error)}`);
capture.error(msg, {
extra: {
context: `deleteConsolidated.catch`,
patientId: patient.id,
patientId: patientId,
detailMsg,
entries,
error,
},
});
throw error;
}
}

function getMessage(err: OperationOutcomeError): string {
return err.outcome.issue ? err.outcome.issue.map(issueToString).join(",") : "";
}

function issueToString(issue: OperationOutcomeIssue): string {
return (
issue.details?.text ??
(issue.diagnostics ? issue.diagnostics.slice(0, 100) + "..." : null) ??
JSON.stringify(issue)
);
}
4 changes: 2 additions & 2 deletions packages/api/src/command/medical/patient/consolidated-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
import { ResourceTypeForConsolidation } from "@metriport/api-sdk";
import { ConsolidationConversionType } from "@metriport/core/domain/conversion/fhir-to-medical-record";
import { emptyFunction } from "@metriport/shared";
import { Patient } from "../../../domain/medical/patient";
import { QueryProgress } from "../../../domain/medical/query-status";
import { Patient } from "@metriport/core/domain/medical/patient";
import { QueryProgress } from "@metriport/core/domain/medical/query-status";
import { makeFhirApi } from "../../../external/fhir/api/api-factory";
import {
fullDateQueryForResource,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Bundle, Resource } from "@medplum/fhirtypes";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import { Product } from "../../../domain/product";
import { errorToString } from "../../../shared/log";
import { capture } from "../../../shared/notifications";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getLambdaResultPayload, makeLambdaClient } from "@metriport/core/extern
import { makeS3Client } from "@metriport/core/external/aws/s3";
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import { Patient } from "../../../domain/medical/patient";
import { Patient } from "@metriport/core/domain/medical/patient";
import { makeFhirApi } from "../../../external/fhir/api/api-factory";
import { Config } from "../../../shared/config";
import { createS3FileName } from "../../../shared/external";
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/command/medical/patient/create-patient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { uuidv7 } from "@metriport/core/util/uuid-v7";
import { Patient, PatientCreate, PatientData } from "../../../domain/medical/patient";
import { Patient, PatientCreate, PatientData } from "@metriport/core/domain/medical/patient";
import { processAsyncError } from "../../../errors";
import cwCommands from "../../../external/commonwell";
import cqCommands from "../../../external/carequality";
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.