feat(MED-131): handle analysis order

This commit is contained in:
2025-08-04 11:53:04 +03:00
parent 08950896e5
commit 91f6dd11be
10 changed files with 310 additions and 140 deletions

View File

@@ -35,6 +35,10 @@ import { uniqBy } from 'lodash';
import { Tables } from '@kit/supabase/database';
import { createAnalysisGroup } from './analysis-group.service';
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
import { getOrder } from './order.service';
import { getAnalysisElements } from './analysis-element.service';
import { getAnalyses } from './analyses.service';
const BASE_URL = process.env.MEDIPOST_URL!;
const USER = process.env.MEDIPOST_USER!;
@@ -85,7 +89,7 @@ export async function getLatestPublicMessageListItem() {
throw new Error('Failed to get public message list');
}
return getLatestMessage(data?.messages);
return getLatestMessage({ messages: data?.messages });
}
export async function getPublicMessage(messageId: string) {
@@ -104,12 +108,12 @@ export async function getPublicMessage(messageId: string) {
return parseXML(data) as MedipostPublicMessageResponse;
}
export async function sendPrivateMessage(messageXml: string, receiver: string) {
export async function sendPrivateMessage(messageXml: string) {
const body = new FormData();
body.append('Action', MedipostAction.SendPrivateMessage);
body.append('User', USER);
body.append('Password', PASSWORD);
body.append('Receiver', receiver);
body.append('Receiver', RECIPIENT);
body.append('MessageType', 'Tellimus');
body.append(
'Message',
@@ -123,7 +127,11 @@ export async function sendPrivateMessage(messageXml: string, receiver: string) {
await validateMedipostResponse(data);
}
export async function getLatestPrivateMessageListItem() {
export async function getLatestPrivateMessageListItem({
excludedMessageIds,
}: {
excludedMessageIds: string[];
}) {
const { data } = await axios.get<GetMessageListResponse>(BASE_URL, {
params: {
Action: MedipostAction.GetPrivateMessageList,
@@ -136,7 +144,7 @@ export async function getLatestPrivateMessageListItem() {
throw new Error('Failed to get private message list');
}
return getLatestMessage(data?.messages);
return getLatestMessage({ messages: data?.messages, excludedMessageIds });
}
export async function getPrivateMessage(messageId: string) {
@@ -172,19 +180,30 @@ export async function deletePrivateMessage(messageId: string) {
}
}
export async function readPrivateMessageResponse() {
export async function readPrivateMessageResponse({
excludedMessageIds,
}: {
excludedMessageIds: string[];
}) {
let messageIdErrored: string | null = null;
try {
const privateMessage = await getLatestPrivateMessageListItem();
const privateMessage = await getLatestPrivateMessageListItem({ excludedMessageIds });
if (!privateMessage) {
return null;
throw new Error(`No private message found`);
}
messageIdErrored = privateMessage.messageId;
const privateMessageContent = await getPrivateMessage(
privateMessage.messageId,
);
const messageResponse = privateMessageContent?.Saadetis?.Vastus;
const status = await syncPrivateMessage(privateMessageContent);
if (!messageResponse) {
throw new Error(`Invalid data in private message response`);
}
const status = await syncPrivateMessage({ messageResponse });
if (status === 'COMPLETED') {
await deletePrivateMessage(privateMessage.messageId);
@@ -192,6 +211,8 @@ export async function readPrivateMessageResponse() {
} catch (e) {
console.error(e);
}
return { messageIdErrored };
}
async function saveAnalysisGroup(
@@ -366,63 +387,28 @@ export async function syncPublicMessage(
}
}
export async function composeOrderXML(
export async function composeOrderXML({
person,
orderedAnalysisElementsIds,
orderedAnalysesIds,
orderId,
orderCreatedAt,
comment,
}: {
person: {
idCode: string,
firstName: string,
lastName: string,
phone: string,
},
comment?: string,
) {
const supabase = createCustomClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
persistSession: false,
autoRefreshToken: false,
detectSessionInUrl: false,
},
},
);
// TODO remove dummy when actual implemetation is present
const orderedElements = [1, 75];
const orderedAnalyses = [10, 11, 100];
const createdAnalysisOrder = {
id: 4,
user_id: 'currentUser.user?.id',
analysis_element_ids: orderedElements,
analysis_ids: orderedAnalyses,
status: AnalysisOrderStatus[1],
created_at: new Date(),
};
const { data: analysisElements } = (await supabase
.schema('medreport')
.from('analysis_elements')
.select(`*, analysis_groups(*)`)
.in('id', orderedElements)) as {
data: ({
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
} & Tables<{ schema: 'medreport' }, 'analysis_elements'>)[];
};
const { data: analyses } = (await supabase
.schema('medreport')
.from('analyses')
.select(`*, analysis_elements(*, analysis_groups(*))`)
.in('id', orderedAnalyses)) as {
data: ({
analysis_elements: Tables<
{ schema: 'medreport' },
'analysis_elements'
> & {
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
};
} & Tables<{ schema: 'medreport' }, 'analyses'>)[];
idCode: string;
firstName: string;
lastName: string;
phone: string;
};
orderedAnalysisElementsIds: number[];
orderedAnalysesIds: number[];
orderId: string;
orderCreatedAt: Date;
comment?: string;
}) {
const analysisElements = await getAnalysisElements({ ids: orderedAnalysisElementsIds });
const analyses = await getAnalyses({ ids: orderedAnalysesIds });
const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =
uniqBy(
@@ -492,12 +478,11 @@ export async function composeOrderXML(
analysisSection.push(groupXml);
}
// TODO get actual data when order creation is implemented
return `<?xml version="1.0" encoding="UTF-8"?>
<Saadetis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="TellimusLOINC.xsd">
${getPais(process.env.MEDIPOST_USER!, process.env.MEDIPOST_RECIPIENT!, createdAnalysisOrder.created_at, createdAnalysisOrder.id)}
${getPais(USER, RECIPIENT, orderCreatedAt, orderId)}
<Tellimus cito="EI">
<ValisTellimuseId>${createdAnalysisOrder.id}</ValisTellimuseId>
<ValisTellimuseId>${orderId}</ValisTellimuseId>
<!--<TellijaAsutus>-->
${getClientInstitution()}
<!--<TeostajaAsutus>-->
@@ -513,48 +498,48 @@ export async function composeOrderXML(
</Saadetis>`;
}
function getLatestMessage(messages?: Message[]) {
function getLatestMessage({
messages,
excludedMessageIds,
}: {
messages?: Message[];
excludedMessageIds?: string[];
}) {
if (!messages?.length) {
return null;
}
return messages.reduce((prev, current) =>
const filtered = messages.filter(({ messageId }) => !excludedMessageIds?.includes(messageId));
if (!filtered.length) {
return null;
}
return filtered.reduce((prev, current) =>
Number(prev.messageId) > Number(current.messageId) ? prev : current,
{ messageId: '' } as Message,
);
}
export async function syncPrivateMessage(
parsedMessage?: MedipostOrderResponse,
) {
const supabase = createCustomClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
persistSession: false,
autoRefreshToken: false,
detectSessionInUrl: false,
},
},
);
export async function syncPrivateMessage({
messageResponse,
}: {
messageResponse: MedipostOrderResponse['Saadetis']['Vastus'];
}) {
const supabase = getSupabaseServerAdminClient()
const response = parsedMessage?.Saadetis?.Vastus;
if (!response) {
throw new Error(`Invalid data in private message response`);
}
const status = response.TellimuseOlek;
const status = messageResponse.TellimuseOlek;
const order = await getOrder({ medusaOrderId: messageResponse.ValisTellimuseId });
const { data: analysisOrder, error: analysisOrderError } = await supabase
.schema('medreport')
.from('analysis_orders')
.select('user_id')
.eq('id', response.ValisTellimuseId);
.eq('id', order.id);
if (analysisOrderError || !analysisOrder?.[0]?.user_id) {
throw new Error(
`Could not find analysis order with id ${response.ValisTellimuseId}`,
`Could not find analysis order with id ${messageResponse.ValisTellimuseId}`,
);
}
@@ -563,8 +548,8 @@ export async function syncPrivateMessage(
.from('analysis_responses')
.upsert(
{
analysis_order_id: response.ValisTellimuseId,
order_number: response.TellimuseNumber,
analysis_order_id: order.id,
order_number: messageResponse.TellimuseNumber,
order_status: AnalysisOrderStatus[status],
user_id: analysisOrder[0].user_id,
},
@@ -574,10 +559,10 @@ export async function syncPrivateMessage(
if (error || !analysisResponse?.[0]?.id) {
throw new Error(
`Failed to insert or update analysis order response (external id: ${response?.TellimuseNumber})`,
`Failed to insert or update analysis order response (external id: ${messageResponse?.TellimuseNumber})`,
);
}
const analysisGroups = toArray(response.UuringuGrupp);
const analysisGroups = toArray(messageResponse.UuringuGrupp);
const responses: Omit<
Tables<{ schema: 'medreport' }, 'analysis_response_elements'>,