prettier fix
This commit is contained in:
@@ -1,36 +1,42 @@
|
||||
'use server';
|
||||
|
||||
import type { PostgrestError } from '@supabase/supabase-js';
|
||||
import axios from 'axios';
|
||||
|
||||
import {
|
||||
GetMessageListResponse,
|
||||
MedipostAction,
|
||||
} from '@/lib/types/medipost';
|
||||
import { GetMessageListResponse, MedipostAction } from '@/lib/types/medipost';
|
||||
import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api';
|
||||
import { AnalysisOrderStatus } from '@/packages/shared/src/types/medipost-analysis';
|
||||
import type {
|
||||
ResponseUuringuGrupp,
|
||||
MedipostOrderResponse,
|
||||
ResponseUuringuGrupp,
|
||||
UuringElement,
|
||||
} from '@/packages/shared/src/types/medipost-analysis';
|
||||
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||
import axios from 'axios';
|
||||
|
||||
import { toArray } from '@kit/shared/utils';
|
||||
import { Tables } from '@kit/supabase/database';
|
||||
|
||||
import type { AnalysisOrder } from '~/lib/types/analysis-order';
|
||||
import type { AnalysisResponseElement } from '~/lib/types/analysis-response-element';
|
||||
import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api';
|
||||
|
||||
import { Tables } from '@kit/supabase/database';
|
||||
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||
import { getAnalysisElementsAdmin } from '../analysis-element.service';
|
||||
import { getAccountAdmin } from '../account.service';
|
||||
import { getAnalyses } from '../analyses.service';
|
||||
import { upsertMedipostActionLog, getLatestMessage } from './medipostMessageBase.service';
|
||||
import { validateMedipostResponse } from './medipostValidate.service';
|
||||
import { getAnalysisElementsAdmin } from '../analysis-element.service';
|
||||
import {
|
||||
getExistingAnalysisResponseElements,
|
||||
upsertAnalysisResponse,
|
||||
upsertAnalysisResponseElement,
|
||||
} from '../analysis-order.service';
|
||||
import { logMedipostDispatch } from '../audit.service';
|
||||
import { getAnalysisOrder, updateAnalysisOrderStatus } from '../order.service';
|
||||
import { parseXML } from '../util/xml.service';
|
||||
import { composeOrderXML, OrderedAnalysisElement } from './medipostXML.service';
|
||||
import { getAccountAdmin } from '../account.service';
|
||||
import { logMedipostDispatch } from '../audit.service';
|
||||
import { MedipostValidationError } from './MedipostValidationError';
|
||||
import { upsertAnalysisResponseElement, getExistingAnalysisResponseElements, upsertAnalysisResponse } from '../analysis-order.service';
|
||||
import {
|
||||
getLatestMessage,
|
||||
upsertMedipostActionLog,
|
||||
} from './medipostMessageBase.service';
|
||||
import { validateMedipostResponse } from './medipostValidate.service';
|
||||
import { OrderedAnalysisElement, composeOrderXML } from './medipostXML.service';
|
||||
|
||||
const BASE_URL = process.env.MEDIPOST_URL!;
|
||||
const USER = process.env.MEDIPOST_USER!;
|
||||
@@ -56,73 +62,102 @@ export async function getLatestPrivateMessageListItem({
|
||||
throw new Error('Failed to get private message list');
|
||||
}
|
||||
|
||||
return await getLatestMessage({ messages: data?.messages, excludedMessageIds });
|
||||
return await getLatestMessage({
|
||||
messages: data?.messages,
|
||||
excludedMessageIds,
|
||||
});
|
||||
}
|
||||
|
||||
const logger = (analysisOrder: AnalysisOrder, externalId: string, analysisResponseId: string) => (message: string, error?: PostgrestError | null) => {
|
||||
const messageFormatted = `[${analysisOrder.id}] [${externalId}] [${analysisResponseId}] ${message}`;
|
||||
if (error) {
|
||||
console.info(messageFormatted, error);
|
||||
} else {
|
||||
console.info(messageFormatted);
|
||||
}
|
||||
};
|
||||
const logger =
|
||||
(
|
||||
analysisOrder: AnalysisOrder,
|
||||
externalId: string,
|
||||
analysisResponseId: string,
|
||||
) =>
|
||||
(message: string, error?: PostgrestError | null) => {
|
||||
const messageFormatted = `[${analysisOrder.id}] [${externalId}] [${analysisResponseId}] ${message}`;
|
||||
if (error) {
|
||||
console.info(messageFormatted, error);
|
||||
} else {
|
||||
console.info(messageFormatted);
|
||||
}
|
||||
};
|
||||
|
||||
export async function canCreateAnalysisResponseElement({
|
||||
existingElements,
|
||||
groupUuring: {
|
||||
UuringuElement: {
|
||||
UuringOlek: status,
|
||||
UuringId: analysisElementOriginalId,
|
||||
},
|
||||
UuringuElement: { UuringOlek: status, UuringId: analysisElementOriginalId },
|
||||
},
|
||||
responseValue,
|
||||
log,
|
||||
}: {
|
||||
existingElements: Pick<AnalysisResponseElement, 'analysis_element_original_id' | 'status' | 'response_value'>[];
|
||||
groupUuring: { UuringuElement: Pick<UuringElement, 'UuringOlek' | 'UuringId'> };
|
||||
existingElements: Pick<
|
||||
AnalysisResponseElement,
|
||||
'analysis_element_original_id' | 'status' | 'response_value'
|
||||
>[];
|
||||
groupUuring: {
|
||||
UuringuElement: Pick<UuringElement, 'UuringOlek' | 'UuringId'>;
|
||||
};
|
||||
responseValue: number | null;
|
||||
log: ReturnType<typeof logger>;
|
||||
}) {
|
||||
const existingAnalysisResponseElement = existingElements.find(({ analysis_element_original_id }) => analysis_element_original_id === analysisElementOriginalId);
|
||||
const existingAnalysisResponseElement = existingElements.find(
|
||||
({ analysis_element_original_id }) =>
|
||||
analysis_element_original_id === analysisElementOriginalId,
|
||||
);
|
||||
if (!existingAnalysisResponseElement) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Number(existingAnalysisResponseElement.status) > status) {
|
||||
log(`Analysis response element id=${analysisElementOriginalId} already exists for order in higher status ${existingAnalysisResponseElement.status} than ${status}`);
|
||||
log(
|
||||
`Analysis response element id=${analysisElementOriginalId} already exists for order in higher status ${existingAnalysisResponseElement.status} than ${status}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (existingAnalysisResponseElement.response_value && !responseValue) {
|
||||
log(`Analysis response element id=${analysisElementOriginalId} already exists for order with response value ${existingAnalysisResponseElement.response_value} but new response has no value`);
|
||||
log(
|
||||
`Analysis response element id=${analysisElementOriginalId} already exists for order with response value ${existingAnalysisResponseElement.response_value} but new response has no value`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
export async function getAnalysisResponseElementsForGroup({
|
||||
analysisGroup,
|
||||
existingElements,
|
||||
log,
|
||||
}: {
|
||||
analysisGroup: Pick<ResponseUuringuGrupp, 'UuringuGruppNimi' | 'Uuring'>;
|
||||
existingElements: Pick<AnalysisResponseElement, 'analysis_element_original_id' | 'status' | 'response_value'>[];
|
||||
existingElements: Pick<
|
||||
AnalysisResponseElement,
|
||||
'analysis_element_original_id' | 'status' | 'response_value'
|
||||
>[];
|
||||
log: ReturnType<typeof logger>;
|
||||
}) {
|
||||
const groupUuringItems = toArray(analysisGroup.Uuring as ResponseUuringuGrupp['Uuring']);
|
||||
log(`Order has results in group '${analysisGroup.UuringuGruppNimi}' for ${groupUuringItems.length} analysis elements`);
|
||||
const groupUuringItems = toArray(
|
||||
analysisGroup.Uuring as ResponseUuringuGrupp['Uuring'],
|
||||
);
|
||||
log(
|
||||
`Order has results in group '${analysisGroup.UuringuGruppNimi}' for ${groupUuringItems.length} analysis elements`,
|
||||
);
|
||||
|
||||
const results: Omit<AnalysisResponseElement, 'created_at' | 'updated_at' | 'id' | 'analysis_response_id'>[] = [];
|
||||
const results: Omit<
|
||||
AnalysisResponseElement,
|
||||
'created_at' | 'updated_at' | 'id' | 'analysis_response_id'
|
||||
>[] = [];
|
||||
|
||||
for (const groupUuring of groupUuringItems) {
|
||||
const groupUuringElement = groupUuring.UuringuElement;
|
||||
const elementAnalysisResponses = toArray(groupUuringElement.UuringuVastus);
|
||||
|
||||
const status = groupUuringElement.UuringOlek;
|
||||
log(`Group uuring '${analysisGroup.UuringuGruppNimi}' has status ${status}`);
|
||||
log(
|
||||
`Group uuring '${analysisGroup.UuringuGruppNimi}' has status ${status}`,
|
||||
);
|
||||
|
||||
for (const response of elementAnalysisResponses) {
|
||||
const analysisElementOriginalId = groupUuringElement.UuringId;
|
||||
@@ -135,12 +170,20 @@ export async function getAnalysisResponseElementsForGroup({
|
||||
return valueAsNumber;
|
||||
})();
|
||||
|
||||
if (!await canCreateAnalysisResponseElement({ existingElements, groupUuring, responseValue, log })) {
|
||||
if (
|
||||
!(await canCreateAnalysisResponseElement({
|
||||
existingElements,
|
||||
groupUuring,
|
||||
responseValue,
|
||||
log,
|
||||
}))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mappedResponse = createUserAnalysesApi(getSupabaseServerAdminClient())
|
||||
.mapUuringVastus({ uuringVastus: response });
|
||||
const mappedResponse = createUserAnalysesApi(
|
||||
getSupabaseServerAdminClient(),
|
||||
).mapUuringVastus({ uuringVastus: response });
|
||||
|
||||
results.push({
|
||||
analysis_element_original_id: analysisElementOriginalId,
|
||||
@@ -153,7 +196,8 @@ export async function getAnalysisResponseElementsForGroup({
|
||||
response_value: mappedResponse.responseValue,
|
||||
unit: groupUuringElement.Mootyhik ?? null,
|
||||
original_response_element: groupUuringElement,
|
||||
analysis_name: groupUuringElement.UuringNimi || groupUuringElement.KNimetus,
|
||||
analysis_name:
|
||||
groupUuringElement.UuringNimi || groupUuringElement.KNimetus,
|
||||
comment: groupUuringElement.UuringuKommentaar ?? null,
|
||||
status: status.toString(),
|
||||
response_value_is_within_norm: mappedResponse.responseValueIsWithinNorm,
|
||||
@@ -174,9 +218,14 @@ async function getNewAnalysisResponseElements({
|
||||
existingElements: AnalysisResponseElement[];
|
||||
log: ReturnType<typeof logger>;
|
||||
}) {
|
||||
const newElements: Omit<AnalysisResponseElement, 'created_at' | 'updated_at' | 'id' | 'analysis_response_id'>[] = [];
|
||||
const newElements: Omit<
|
||||
AnalysisResponseElement,
|
||||
'created_at' | 'updated_at' | 'id' | 'analysis_response_id'
|
||||
>[] = [];
|
||||
for (const analysisGroup of analysisGroups) {
|
||||
log(`[${analysisGroups.indexOf(analysisGroup) + 1}/${analysisGroups.length}] Syncing analysis group '${analysisGroup.UuringuGruppNimi}'`);
|
||||
log(
|
||||
`[${analysisGroups.indexOf(analysisGroup) + 1}/${analysisGroups.length}] Syncing analysis group '${analysisGroup.UuringuGruppNimi}'`,
|
||||
);
|
||||
const elements = await getAnalysisResponseElementsForGroup({
|
||||
analysisGroup,
|
||||
existingElements,
|
||||
@@ -194,7 +243,9 @@ async function hasAllAnalysisResponseElements({
|
||||
analysisResponseId: number;
|
||||
order: Pick<AnalysisOrder, 'analysis_element_ids'>;
|
||||
}) {
|
||||
const allOrderResponseElements = await getExistingAnalysisResponseElements({ analysisResponseId });
|
||||
const allOrderResponseElements = await getExistingAnalysisResponseElements({
|
||||
analysisResponseId,
|
||||
});
|
||||
const expectedOrderResponseElements = order.analysis_element_ids?.length ?? 0;
|
||||
return allOrderResponseElements.length >= expectedOrderResponseElements;
|
||||
}
|
||||
@@ -208,7 +259,10 @@ export async function syncPrivateMessage({
|
||||
},
|
||||
order,
|
||||
}: {
|
||||
messageResponse: Pick<NonNullable<MedipostOrderResponse['Saadetis']['Vastus']>, 'ValisTellimuseId' | 'TellimuseNumber' | 'TellimuseOlek' | 'UuringuGrupp'>;
|
||||
messageResponse: Pick<
|
||||
NonNullable<MedipostOrderResponse['Saadetis']['Vastus']>,
|
||||
'ValisTellimuseId' | 'TellimuseNumber' | 'TellimuseOlek' | 'UuringuGrupp'
|
||||
>;
|
||||
order: Tables<{ schema: 'medreport' }, 'analysis_orders'>;
|
||||
}) {
|
||||
const supabase = getSupabaseServerAdminClient();
|
||||
@@ -232,11 +286,17 @@ export async function syncPrivateMessage({
|
||||
userId: analysisOrder.user_id,
|
||||
});
|
||||
|
||||
const existingElements = await getExistingAnalysisResponseElements({ analysisResponseId });
|
||||
const existingElements = await getExistingAnalysisResponseElements({
|
||||
analysisResponseId,
|
||||
});
|
||||
|
||||
const analysisGroups = toArray(UuringuGrupp);
|
||||
log(`Order has results for ${analysisGroups.length} analysis groups`);
|
||||
const newElements = await getNewAnalysisResponseElements({ analysisGroups, existingElements, log });
|
||||
const newElements = await getNewAnalysisResponseElements({
|
||||
analysisGroups,
|
||||
existingElements,
|
||||
log,
|
||||
});
|
||||
|
||||
for (const element of newElements) {
|
||||
try {
|
||||
@@ -247,11 +307,14 @@ export async function syncPrivateMessage({
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
log(`Failed to create order response element for response id ${analysisResponseId}, element id '${element.analysis_element_original_id}' (order id: ${order.id})`, e as PostgrestError);
|
||||
log(
|
||||
`Failed to create order response element for response id ${analysisResponseId}, element id '${element.analysis_element_original_id}' (order id: ${order.id})`,
|
||||
e as PostgrestError,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await hasAllAnalysisResponseElements({ analysisResponseId, order })
|
||||
return (await hasAllAnalysisResponseElements({ analysisResponseId, order }))
|
||||
? { isCompleted: orderStatus === 'COMPLETED' }
|
||||
: { isPartial: true };
|
||||
}
|
||||
@@ -276,7 +339,9 @@ export async function readPrivateMessageResponse({
|
||||
let analysisOrderId: number | undefined = undefined;
|
||||
|
||||
try {
|
||||
const privateMessage = await getLatestPrivateMessageListItem({ excludedMessageIds });
|
||||
const privateMessage = await getLatestPrivateMessageListItem({
|
||||
excludedMessageIds,
|
||||
});
|
||||
messageId = privateMessage?.messageId ?? null;
|
||||
|
||||
if (!privateMessage || !messageId) {
|
||||
@@ -286,17 +351,18 @@ export async function readPrivateMessageResponse({
|
||||
hasPartialAnalysisResponse: false,
|
||||
hasFullAnalysisResponse: false,
|
||||
medusaOrderId: undefined,
|
||||
analysisOrderId: undefined
|
||||
analysisOrderId: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const { messageId: privateMessageId } = privateMessage;
|
||||
const { message: privateMessageContent, xml: privateMessageXml } = await getPrivateMessage(
|
||||
privateMessageId,
|
||||
);
|
||||
const { message: privateMessageContent, xml: privateMessageXml } =
|
||||
await getPrivateMessage(privateMessageId);
|
||||
|
||||
const messageResponse = privateMessageContent?.Saadetis?.Vastus;
|
||||
const medipostExternalOrderId = privateMessageContent?.Saadetis?.Tellimus?.ValisTellimuseId || messageResponse?.ValisTellimuseId;
|
||||
const medipostExternalOrderId =
|
||||
privateMessageContent?.Saadetis?.Tellimus?.ValisTellimuseId ||
|
||||
messageResponse?.ValisTellimuseId;
|
||||
const patientPersonalCode = messageResponse?.Patsient.Isikukood?.toString();
|
||||
analysisOrderId = Number(medipostExternalOrderId);
|
||||
|
||||
@@ -318,27 +384,36 @@ export async function readPrivateMessageResponse({
|
||||
hasPartialAnalysisResponse: false,
|
||||
hasFullAnalysisResponse: false,
|
||||
medusaOrderId: hasInvalidOrderId ? undefined : medusaOrderId,
|
||||
analysisOrderId: hasInvalidOrderId ? undefined : analysisOrderId
|
||||
analysisOrderId: hasInvalidOrderId ? undefined : analysisOrderId,
|
||||
};
|
||||
}
|
||||
|
||||
let analysisOrder: AnalysisOrder;
|
||||
try {
|
||||
analysisOrder = await getAnalysisOrder({ analysisOrderId })
|
||||
analysisOrder = await getAnalysisOrder({ analysisOrderId });
|
||||
medusaOrderId = analysisOrder.medusa_order_id;
|
||||
} catch (e) {
|
||||
if (IS_ENABLED_DELETE_PRIVATE_MESSAGE) {
|
||||
await deletePrivateMessage(privateMessageId);
|
||||
}
|
||||
throw new Error(`No analysis order found for Medipost message ValisTellimuseId=${medipostExternalOrderId}`);
|
||||
throw new Error(
|
||||
`No analysis order found for Medipost message ValisTellimuseId=${medipostExternalOrderId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const orderPerson = await getAccountAdmin({ primaryOwnerUserId: analysisOrder.user_id });
|
||||
const orderPerson = await getAccountAdmin({
|
||||
primaryOwnerUserId: analysisOrder.user_id,
|
||||
});
|
||||
if (orderPerson.personal_code !== patientPersonalCode) {
|
||||
throw new Error(`Order person personal code does not match Medipost message Patsient.Isikukood=${patientPersonalCode}, orderPerson.personal_code=${orderPerson.personal_code}`);
|
||||
throw new Error(
|
||||
`Order person personal code does not match Medipost message Patsient.Isikukood=${patientPersonalCode}, orderPerson.personal_code=${orderPerson.personal_code}`,
|
||||
);
|
||||
}
|
||||
|
||||
const status = await syncPrivateMessage({ messageResponse, order: analysisOrder });
|
||||
const status = await syncPrivateMessage({
|
||||
messageResponse,
|
||||
order: analysisOrder,
|
||||
});
|
||||
|
||||
await upsertMedipostActionLog({
|
||||
action: 'sync_analysis_results_from_medipost',
|
||||
@@ -349,11 +424,17 @@ export async function readPrivateMessageResponse({
|
||||
medipostExternalOrderId,
|
||||
});
|
||||
if (status.isPartial) {
|
||||
await updateAnalysisOrderStatus({ medusaOrderId, orderStatus: 'PARTIAL_ANALYSIS_RESPONSE' });
|
||||
await updateAnalysisOrderStatus({
|
||||
medusaOrderId,
|
||||
orderStatus: 'PARTIAL_ANALYSIS_RESPONSE',
|
||||
});
|
||||
hasAnalysisResponse = true;
|
||||
hasPartialAnalysisResponse = true;
|
||||
} else if (status.isCompleted) {
|
||||
await updateAnalysisOrderStatus({ medusaOrderId, orderStatus: 'FULL_ANALYSIS_RESPONSE' });
|
||||
await updateAnalysisOrderStatus({
|
||||
medusaOrderId,
|
||||
orderStatus: 'FULL_ANALYSIS_RESPONSE',
|
||||
});
|
||||
if (IS_ENABLED_DELETE_PRIVATE_MESSAGE) {
|
||||
await deletePrivateMessage(privateMessageId);
|
||||
}
|
||||
@@ -361,10 +442,19 @@ export async function readPrivateMessageResponse({
|
||||
hasFullAnalysisResponse = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Failed to process private message id=${messageId}, message=${(e as Error).message}`);
|
||||
console.warn(
|
||||
`Failed to process private message id=${messageId}, message=${(e as Error).message}`,
|
||||
);
|
||||
}
|
||||
|
||||
return { messageId, hasAnalysisResponse, hasPartialAnalysisResponse, hasFullAnalysisResponse, medusaOrderId, analysisOrderId };
|
||||
return {
|
||||
messageId,
|
||||
hasAnalysisResponse,
|
||||
hasPartialAnalysisResponse,
|
||||
hasFullAnalysisResponse,
|
||||
medusaOrderId,
|
||||
analysisOrderId,
|
||||
};
|
||||
}
|
||||
|
||||
export async function deletePrivateMessage(messageId: string) {
|
||||
@@ -430,7 +520,9 @@ export async function sendOrderToMedipost({
|
||||
orderedAnalysisElements: OrderedAnalysisElement[];
|
||||
}) {
|
||||
const medreportOrder = await getAnalysisOrder({ medusaOrderId });
|
||||
const account = await getAccountAdmin({ primaryOwnerUserId: medreportOrder.user_id });
|
||||
const account = await getAccountAdmin({
|
||||
primaryOwnerUserId: medreportOrder.user_id,
|
||||
});
|
||||
|
||||
const orderedAnalysesIds = orderedAnalysisElements
|
||||
.map(({ analysisId }) => analysisId)
|
||||
@@ -441,11 +533,17 @@ export async function sendOrderToMedipost({
|
||||
|
||||
const analyses = await getAnalyses({ ids: orderedAnalysesIds });
|
||||
if (analyses.length !== orderedAnalysesIds.length) {
|
||||
throw new Error(`Got ${analyses.length} analyses, expected ${orderedAnalysesIds.length}`);
|
||||
throw new Error(
|
||||
`Got ${analyses.length} analyses, expected ${orderedAnalysesIds.length}`,
|
||||
);
|
||||
}
|
||||
const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds });
|
||||
const analysisElements = await getAnalysisElementsAdmin({
|
||||
ids: orderedAnalysisElementsIds,
|
||||
});
|
||||
if (analysisElements.length !== orderedAnalysisElementsIds.length) {
|
||||
throw new Error(`Got ${analysisElements.length} analysis elements, expected ${orderedAnalysisElementsIds.length}`);
|
||||
throw new Error(
|
||||
`Got ${analysisElements.length} analysis elements, expected ${orderedAnalysisElementsIds.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
const orderXml = await composeOrderXML({
|
||||
|
||||
Reference in New Issue
Block a user