feat(MED-131): handle analysis order
This commit is contained in:
@@ -2,7 +2,7 @@ import { cache } from 'react';
|
|||||||
|
|
||||||
import { AdminAccountPage } from '@kit/admin/components/admin-account-page';
|
import { AdminAccountPage } from '@kit/admin/components/admin-account-page';
|
||||||
import { AdminGuard } from '@kit/admin/components/admin-guard';
|
import { AdminGuard } from '@kit/admin/components/admin-guard';
|
||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getAccount } from '~/lib/services/account.service';
|
||||||
|
|
||||||
interface Params {
|
interface Params {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
@@ -28,21 +28,4 @@ async function AccountPage(props: Params) {
|
|||||||
|
|
||||||
export default AdminGuard(AccountPage);
|
export default AdminGuard(AccountPage);
|
||||||
|
|
||||||
const loadAccount = cache(accountLoader);
|
const loadAccount = cache(getAccount);
|
||||||
|
|
||||||
async function accountLoader(id: string) {
|
|
||||||
const client = getSupabaseServerClient();
|
|
||||||
|
|
||||||
const { data, error } = await client
|
|
||||||
.schema('medreport')
|
|
||||||
.from('accounts')
|
|
||||||
.select('*, memberships: accounts_memberships (*)')
|
|
||||||
.eq('id', id)
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|||||||
51
app/api/order/medipost-create/route.ts
Normal file
51
app/api/order/medipost-create/route.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { retrieveOrder } from "@lib/data";
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { getAccountAdmin } from "~/lib/services/account.service";
|
||||||
|
import { composeOrderXML, sendPrivateMessage } from "~/lib/services/medipost.service";
|
||||||
|
import { getOrder, updateOrder } from "~/lib/services/order.service";
|
||||||
|
|
||||||
|
interface MedipostCreateRequest {
|
||||||
|
medusaOrderId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (request: NextRequest) => {
|
||||||
|
const { medusaOrderId } = (await request.json()) as MedipostCreateRequest;
|
||||||
|
const medusaOrder = await retrieveOrder(medusaOrderId)
|
||||||
|
const medreportOrder = await getOrder({ medusaOrderId });
|
||||||
|
|
||||||
|
const account = await getAccountAdmin({ primaryOwnerUserId: medreportOrder.user_id });
|
||||||
|
|
||||||
|
const ANALYSIS_ELEMENT_HANDLE_PREFIX = 'analysis-element-';
|
||||||
|
const orderedAnalysisElementsIds = (medusaOrder?.items ?? [])
|
||||||
|
.filter((item) => item.product?.handle?.startsWith(ANALYSIS_ELEMENT_HANDLE_PREFIX))
|
||||||
|
.map((item) => {
|
||||||
|
const id = Number(item.product?.handle?.replace(ANALYSIS_ELEMENT_HANDLE_PREFIX, ''));
|
||||||
|
if (Number.isNaN(id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
})
|
||||||
|
.filter(Boolean) as number[];
|
||||||
|
const orderXml = await composeOrderXML({
|
||||||
|
person: {
|
||||||
|
idCode: account.personal_code!,
|
||||||
|
firstName: account.name ?? '',
|
||||||
|
lastName: account.last_name ?? '',
|
||||||
|
phone: account.phone ?? '',
|
||||||
|
},
|
||||||
|
orderedAnalysisElementsIds,
|
||||||
|
orderedAnalysesIds: [],
|
||||||
|
orderId: medusaOrderId,
|
||||||
|
orderCreatedAt: new Date(medreportOrder.created_at),
|
||||||
|
comment: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
await sendPrivateMessage(orderXml);
|
||||||
|
|
||||||
|
await updateOrder({
|
||||||
|
orderId: medreportOrder.id,
|
||||||
|
orderStatus: 'PROCESSING',
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({ orderXml });
|
||||||
|
};
|
||||||
41
lib/services/account.service.ts
Normal file
41
lib/services/account.service.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { getSupabaseServerClient } from "@kit/supabase/server-client";
|
||||||
|
import { getSupabaseServerAdminClient } from "@kit/supabase/server-admin-client";
|
||||||
|
import type { Tables } from "@/packages/supabase/src/database.types";
|
||||||
|
|
||||||
|
type Account = Tables<{ schema: 'medreport' }, 'accounts'>;
|
||||||
|
type Membership = Tables<{ schema: 'medreport' }, 'accounts_memberships'>;
|
||||||
|
|
||||||
|
export type AccountWithMemberships = Account & { memberships: Membership[] }
|
||||||
|
|
||||||
|
export async function getAccount(id: string): Promise<AccountWithMemberships> {
|
||||||
|
const { data } = await getSupabaseServerClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('accounts')
|
||||||
|
.select('*, memberships: accounts_memberships (*)')
|
||||||
|
.eq('id', id)
|
||||||
|
.single()
|
||||||
|
.throwOnError();
|
||||||
|
|
||||||
|
return data as unknown as AccountWithMemberships;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAccountAdmin({
|
||||||
|
primaryOwnerUserId,
|
||||||
|
}: {
|
||||||
|
primaryOwnerUserId: string;
|
||||||
|
}): Promise<AccountWithMemberships> {
|
||||||
|
const query = getSupabaseServerAdminClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('accounts')
|
||||||
|
.select('*, memberships: accounts_memberships (*)')
|
||||||
|
|
||||||
|
if (primaryOwnerUserId) {
|
||||||
|
query.eq('primary_owner_user_id', primaryOwnerUserId);
|
||||||
|
} else {
|
||||||
|
throw new Error('primaryOwnerUserId is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await query.single().throwOnError();
|
||||||
|
|
||||||
|
return data as unknown as AccountWithMemberships;
|
||||||
|
}
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
|
import type { Tables } from '@/packages/supabase/src/database.types';
|
||||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||||
import type { IUuringElement } from "./medipost.types";
|
import type { IUuringElement } from "./medipost.types";
|
||||||
|
|
||||||
|
type AnalysesWithGroupsAndElements = ({
|
||||||
|
analysis_elements: Tables<{ schema: 'medreport' }, 'analysis_elements'> & {
|
||||||
|
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
|
||||||
|
};
|
||||||
|
} & Tables<{ schema: 'medreport' }, 'analyses'>)[];
|
||||||
|
|
||||||
export const createAnalysis = async (
|
export const createAnalysis = async (
|
||||||
analysis: IUuringElement,
|
analysis: IUuringElement,
|
||||||
insertedAnalysisElementId: number,
|
insertedAnalysisElementId: number,
|
||||||
@@ -97,3 +104,13 @@ export const createMedusaSyncSuccessEntry = async () => {
|
|||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAnalyses({ ids }: { ids: number[] }): Promise<AnalysesWithGroupsAndElements> {
|
||||||
|
const { data } = await getSupabaseServerAdminClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analyses')
|
||||||
|
.select(`*, analysis_elements(*, analysis_groups(*))`)
|
||||||
|
.in('id', ids);
|
||||||
|
|
||||||
|
return data as unknown as AnalysesWithGroupsAndElements;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ export type AnalysisElement = Tables<{ schema: 'medreport' }, 'analysis_elements
|
|||||||
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
|
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getAnalysisElements({ originalIds }: {
|
export async function getAnalysisElements({
|
||||||
originalIds?: string[]
|
originalIds,
|
||||||
} = {}) {
|
ids,
|
||||||
|
}: {
|
||||||
|
originalIds?: string[];
|
||||||
|
ids?: number[];
|
||||||
|
}): Promise<AnalysisElement[]> {
|
||||||
const query = getSupabaseServerClient()
|
const query = getSupabaseServerClient()
|
||||||
.schema('medreport')
|
.schema('medreport')
|
||||||
.from('analysis_elements')
|
.from('analysis_elements')
|
||||||
@@ -20,6 +24,10 @@ export async function getAnalysisElements({ originalIds }: {
|
|||||||
query.in('analysis_id_original', [...new Set(originalIds)]);
|
query.in('analysis_id_original', [...new Set(originalIds)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(ids)) {
|
||||||
|
query.in('id', ids);
|
||||||
|
}
|
||||||
|
|
||||||
const { data: analysisElements } = await query;
|
const { data: analysisElements } = await query;
|
||||||
|
|
||||||
return analysisElements ?? [];
|
return analysisElements ?? [];
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ import { uniqBy } from 'lodash';
|
|||||||
|
|
||||||
import { Tables } from '@kit/supabase/database';
|
import { Tables } from '@kit/supabase/database';
|
||||||
import { createAnalysisGroup } from './analysis-group.service';
|
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 BASE_URL = process.env.MEDIPOST_URL!;
|
||||||
const USER = process.env.MEDIPOST_USER!;
|
const USER = process.env.MEDIPOST_USER!;
|
||||||
@@ -85,7 +89,7 @@ export async function getLatestPublicMessageListItem() {
|
|||||||
throw new Error('Failed to get public message list');
|
throw new Error('Failed to get public message list');
|
||||||
}
|
}
|
||||||
|
|
||||||
return getLatestMessage(data?.messages);
|
return getLatestMessage({ messages: data?.messages });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPublicMessage(messageId: string) {
|
export async function getPublicMessage(messageId: string) {
|
||||||
@@ -104,12 +108,12 @@ export async function getPublicMessage(messageId: string) {
|
|||||||
return parseXML(data) as MedipostPublicMessageResponse;
|
return parseXML(data) as MedipostPublicMessageResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendPrivateMessage(messageXml: string, receiver: string) {
|
export async function sendPrivateMessage(messageXml: string) {
|
||||||
const body = new FormData();
|
const body = new FormData();
|
||||||
body.append('Action', MedipostAction.SendPrivateMessage);
|
body.append('Action', MedipostAction.SendPrivateMessage);
|
||||||
body.append('User', USER);
|
body.append('User', USER);
|
||||||
body.append('Password', PASSWORD);
|
body.append('Password', PASSWORD);
|
||||||
body.append('Receiver', receiver);
|
body.append('Receiver', RECIPIENT);
|
||||||
body.append('MessageType', 'Tellimus');
|
body.append('MessageType', 'Tellimus');
|
||||||
body.append(
|
body.append(
|
||||||
'Message',
|
'Message',
|
||||||
@@ -123,7 +127,11 @@ export async function sendPrivateMessage(messageXml: string, receiver: string) {
|
|||||||
await validateMedipostResponse(data);
|
await validateMedipostResponse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLatestPrivateMessageListItem() {
|
export async function getLatestPrivateMessageListItem({
|
||||||
|
excludedMessageIds,
|
||||||
|
}: {
|
||||||
|
excludedMessageIds: string[];
|
||||||
|
}) {
|
||||||
const { data } = await axios.get<GetMessageListResponse>(BASE_URL, {
|
const { data } = await axios.get<GetMessageListResponse>(BASE_URL, {
|
||||||
params: {
|
params: {
|
||||||
Action: MedipostAction.GetPrivateMessageList,
|
Action: MedipostAction.GetPrivateMessageList,
|
||||||
@@ -136,7 +144,7 @@ export async function getLatestPrivateMessageListItem() {
|
|||||||
throw new Error('Failed to get private message list');
|
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) {
|
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 {
|
try {
|
||||||
const privateMessage = await getLatestPrivateMessageListItem();
|
const privateMessage = await getLatestPrivateMessageListItem({ excludedMessageIds });
|
||||||
|
|
||||||
if (!privateMessage) {
|
if (!privateMessage) {
|
||||||
return null;
|
throw new Error(`No private message found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageIdErrored = privateMessage.messageId;
|
||||||
|
|
||||||
const privateMessageContent = await getPrivateMessage(
|
const privateMessageContent = await getPrivateMessage(
|
||||||
privateMessage.messageId,
|
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') {
|
if (status === 'COMPLETED') {
|
||||||
await deletePrivateMessage(privateMessage.messageId);
|
await deletePrivateMessage(privateMessage.messageId);
|
||||||
@@ -192,6 +211,8 @@ export async function readPrivateMessageResponse() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { messageIdErrored };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveAnalysisGroup(
|
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: {
|
person: {
|
||||||
idCode: string,
|
idCode: string;
|
||||||
firstName: string,
|
firstName: string;
|
||||||
lastName: string,
|
lastName: string;
|
||||||
phone: 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'>)[];
|
|
||||||
};
|
};
|
||||||
|
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'>[] =
|
const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =
|
||||||
uniqBy(
|
uniqBy(
|
||||||
@@ -492,12 +478,11 @@ export async function composeOrderXML(
|
|||||||
analysisSection.push(groupXml);
|
analysisSection.push(groupXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO get actual data when order creation is implemented
|
|
||||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Saadetis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="TellimusLOINC.xsd">
|
<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">
|
<Tellimus cito="EI">
|
||||||
<ValisTellimuseId>${createdAnalysisOrder.id}</ValisTellimuseId>
|
<ValisTellimuseId>${orderId}</ValisTellimuseId>
|
||||||
<!--<TellijaAsutus>-->
|
<!--<TellijaAsutus>-->
|
||||||
${getClientInstitution()}
|
${getClientInstitution()}
|
||||||
<!--<TeostajaAsutus>-->
|
<!--<TeostajaAsutus>-->
|
||||||
@@ -513,48 +498,48 @@ export async function composeOrderXML(
|
|||||||
</Saadetis>`;
|
</Saadetis>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLatestMessage(messages?: Message[]) {
|
function getLatestMessage({
|
||||||
|
messages,
|
||||||
|
excludedMessageIds,
|
||||||
|
}: {
|
||||||
|
messages?: Message[];
|
||||||
|
excludedMessageIds?: string[];
|
||||||
|
}) {
|
||||||
if (!messages?.length) {
|
if (!messages?.length) {
|
||||||
return null;
|
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,
|
Number(prev.messageId) > Number(current.messageId) ? prev : current,
|
||||||
|
{ messageId: '' } as Message,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function syncPrivateMessage(
|
export async function syncPrivateMessage({
|
||||||
parsedMessage?: MedipostOrderResponse,
|
messageResponse,
|
||||||
) {
|
}: {
|
||||||
const supabase = createCustomClient(
|
messageResponse: MedipostOrderResponse['Saadetis']['Vastus'];
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
}) {
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
const supabase = getSupabaseServerAdminClient()
|
||||||
{
|
|
||||||
auth: {
|
|
||||||
persistSession: false,
|
|
||||||
autoRefreshToken: false,
|
|
||||||
detectSessionInUrl: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const response = parsedMessage?.Saadetis?.Vastus;
|
const status = messageResponse.TellimuseOlek;
|
||||||
|
const order = await getOrder({ medusaOrderId: messageResponse.ValisTellimuseId });
|
||||||
if (!response) {
|
|
||||||
throw new Error(`Invalid data in private message response`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const status = response.TellimuseOlek;
|
|
||||||
|
|
||||||
const { data: analysisOrder, error: analysisOrderError } = await supabase
|
const { data: analysisOrder, error: analysisOrderError } = await supabase
|
||||||
.schema('medreport')
|
.schema('medreport')
|
||||||
.from('analysis_orders')
|
.from('analysis_orders')
|
||||||
.select('user_id')
|
.select('user_id')
|
||||||
.eq('id', response.ValisTellimuseId);
|
.eq('id', order.id);
|
||||||
|
|
||||||
if (analysisOrderError || !analysisOrder?.[0]?.user_id) {
|
if (analysisOrderError || !analysisOrder?.[0]?.user_id) {
|
||||||
throw new Error(
|
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')
|
.from('analysis_responses')
|
||||||
.upsert(
|
.upsert(
|
||||||
{
|
{
|
||||||
analysis_order_id: response.ValisTellimuseId,
|
analysis_order_id: order.id,
|
||||||
order_number: response.TellimuseNumber,
|
order_number: messageResponse.TellimuseNumber,
|
||||||
order_status: AnalysisOrderStatus[status],
|
order_status: AnalysisOrderStatus[status],
|
||||||
user_id: analysisOrder[0].user_id,
|
user_id: analysisOrder[0].user_id,
|
||||||
},
|
},
|
||||||
@@ -574,10 +559,10 @@ export async function syncPrivateMessage(
|
|||||||
|
|
||||||
if (error || !analysisResponse?.[0]?.id) {
|
if (error || !analysisResponse?.[0]?.id) {
|
||||||
throw new Error(
|
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<
|
const responses: Omit<
|
||||||
Tables<{ schema: 'medreport' }, 'analysis_response_elements'>,
|
Tables<{ schema: 'medreport' }, 'analysis_response_elements'>,
|
||||||
|
|||||||
88
lib/services/order.service.ts
Normal file
88
lib/services/order.service.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||||
|
import type { Tables } from '@kit/supabase/database';
|
||||||
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
import type { StoreOrder } from '@medusajs/types';
|
||||||
|
|
||||||
|
export async function createOrder({
|
||||||
|
medusaOrder,
|
||||||
|
}: {
|
||||||
|
medusaOrder: StoreOrder;
|
||||||
|
}) {
|
||||||
|
const supabase = getSupabaseServerClient();
|
||||||
|
|
||||||
|
const analysisElementIds = medusaOrder.items
|
||||||
|
?.filter(({ product }) => product?.handle?.startsWith('analysis-element-'))
|
||||||
|
.map(({ product }) => Number(product?.handle.replace('analysis-element-', '')))
|
||||||
|
.filter((id) => !Number.isNaN(id)) as number[];
|
||||||
|
const { data: { user } } = await supabase.auth.getUser();
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
const orderResult = await supabase.schema('medreport')
|
||||||
|
.from('analysis_orders')
|
||||||
|
.insert({
|
||||||
|
analysis_element_ids: analysisElementIds,
|
||||||
|
analysis_ids: [],
|
||||||
|
status: 'QUEUED',
|
||||||
|
user_id: user.id,
|
||||||
|
medusa_order_id: medusaOrder.id,
|
||||||
|
})
|
||||||
|
.select('id')
|
||||||
|
.single()
|
||||||
|
.throwOnError();
|
||||||
|
|
||||||
|
if (orderResult.error || !orderResult.data?.id) {
|
||||||
|
throw new Error(`Failed to create order, message=${orderResult.error}, data=${JSON.stringify(orderResult)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateOrder({
|
||||||
|
orderId,
|
||||||
|
orderStatus,
|
||||||
|
}: {
|
||||||
|
orderId: number;
|
||||||
|
orderStatus: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status'];
|
||||||
|
}) {
|
||||||
|
const { error } = await getSupabaseServerClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analysis_orders')
|
||||||
|
.update({
|
||||||
|
status: orderStatus,
|
||||||
|
})
|
||||||
|
.eq('id', orderId)
|
||||||
|
.throwOnError();
|
||||||
|
if (error) {
|
||||||
|
throw new Error(`Failed to update order, message=${error}, data=${JSON.stringify(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getOrder({
|
||||||
|
medusaOrderId,
|
||||||
|
}: {
|
||||||
|
medusaOrderId: string;
|
||||||
|
}) {
|
||||||
|
const query = getSupabaseServerAdminClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analysis_orders')
|
||||||
|
.select('*')
|
||||||
|
.eq('medusa_order_id', medusaOrderId)
|
||||||
|
|
||||||
|
const { data: order } = await query.single().throwOnError();
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getOrders({
|
||||||
|
orderStatus,
|
||||||
|
}: {
|
||||||
|
orderStatus?: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status'];
|
||||||
|
} = {}) {
|
||||||
|
const query = getSupabaseServerClient()
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analysis_orders')
|
||||||
|
.select('*')
|
||||||
|
if (orderStatus) {
|
||||||
|
query.eq('status', orderStatus);
|
||||||
|
}
|
||||||
|
const orders = await query.throwOnError();
|
||||||
|
return orders.data;
|
||||||
|
}
|
||||||
@@ -102,7 +102,7 @@ export const getPatient = ({
|
|||||||
<EesNimi>${firstName}</EesNimi>
|
<EesNimi>${firstName}</EesNimi>
|
||||||
<SynniAeg>${format(isikukood.getBirthday(), DATE_FORMAT)}</SynniAeg>
|
<SynniAeg>${format(isikukood.getBirthday(), DATE_FORMAT)}</SynniAeg>
|
||||||
<SuguOID>1.3.6.1.4.1.28284.6.2.3.16.2</SuguOID>
|
<SuguOID>1.3.6.1.4.1.28284.6.2.3.16.2</SuguOID>
|
||||||
<Sugu>${isikukood.getGender()}</Sugu>
|
<Sugu>${isikukood.getGender() === Gender.MALE ? 'M' : 'N'}</Sugu>
|
||||||
</Patsient>`;
|
</Patsient>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
export interface IMedipostResponseXMLBase {
|
||||||
|
'?xml': {
|
||||||
|
'@_version': string;
|
||||||
|
'@_encoding': string;
|
||||||
|
'@_standalone': 'yes' | 'no';
|
||||||
|
};
|
||||||
|
ANSWER?: { CODE: number };
|
||||||
|
}
|
||||||
|
|
||||||
export type Message = {
|
export type Message = {
|
||||||
messageId: string;
|
messageId: string;
|
||||||
messageType: string;
|
messageType: string;
|
||||||
@@ -120,13 +129,7 @@ export type Teostaja = {
|
|||||||
Sisendparameeter?: Sisendparameeter | Sisendparameeter[]; //0...n
|
Sisendparameeter?: Sisendparameeter | Sisendparameeter[]; //0...n
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MedipostPublicMessageResponse = {
|
export type MedipostPublicMessageResponse = IMedipostResponseXMLBase & {
|
||||||
'?xml': {
|
|
||||||
'@_version': string;
|
|
||||||
'@_encoding': string;
|
|
||||||
'@_standalone'?: 'yes' | 'no';
|
|
||||||
};
|
|
||||||
ANSWER?: { CODE: number };
|
|
||||||
Saadetis?: {
|
Saadetis?: {
|
||||||
Pais: {
|
Pais: {
|
||||||
Pakett: { '#text': 'SL' | 'OL' | 'AL' | 'ME' }; // SL - Teenused, OL - Tellimus (meie poolt saadetav saatekiri), AL - Vastus (saatekirja vastus), ME - Teade
|
Pakett: { '#text': 'SL' | 'OL' | 'AL' | 'ME' }; // SL - Teenused, OL - Tellimus (meie poolt saadetav saatekiri), AL - Vastus (saatekirja vastus), ME - Teade
|
||||||
@@ -186,13 +189,7 @@ export type ResponseUuringuGrupp = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// type for UuringuGrupp is correct, but some of this is generated by an LLM and should be checked if data in use
|
// type for UuringuGrupp is correct, but some of this is generated by an LLM and should be checked if data in use
|
||||||
export type MedipostOrderResponse = {
|
export type MedipostOrderResponse = IMedipostResponseXMLBase & {
|
||||||
'?xml': {
|
|
||||||
'@_version': string;
|
|
||||||
'@_encoding': string;
|
|
||||||
'@_standalone': 'yes' | 'no';
|
|
||||||
};
|
|
||||||
ANSWER?: { CODE: number };
|
|
||||||
Saadetis: {
|
Saadetis: {
|
||||||
Pais: {
|
Pais: {
|
||||||
Pakett: {
|
Pakett: {
|
||||||
@@ -206,7 +203,7 @@ export type MedipostOrderResponse = {
|
|||||||
Email: string;
|
Email: string;
|
||||||
};
|
};
|
||||||
Vastus: {
|
Vastus: {
|
||||||
ValisTellimuseId: number;
|
ValisTellimuseId: string;
|
||||||
Asutus: {
|
Asutus: {
|
||||||
'@_tyyp': string; // TEOSTAJA
|
'@_tyyp': string; // TEOSTAJA
|
||||||
'@_jarjenumber': string;
|
'@_jarjenumber': string;
|
||||||
@@ -252,16 +249,16 @@ export type MedipostOrderResponse = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AnalysisOrderStatus: Record<number, string> = {
|
export const AnalysisOrderStatus = {
|
||||||
1: 'QUEUED',
|
1: 'QUEUED',
|
||||||
2: 'ON_HOLD',
|
2: 'ON_HOLD',
|
||||||
3: 'PROCESSING',
|
3: 'PROCESSING',
|
||||||
4: 'COMPLETED',
|
4: 'COMPLETED',
|
||||||
5: 'REJECTED',
|
5: 'REJECTED',
|
||||||
6: 'CANCELLED',
|
6: 'CANCELLED',
|
||||||
};
|
} as const;
|
||||||
export const NormStatus: Record<number, string> = {
|
export const NormStatus: Record<number, string> = {
|
||||||
1: 'NORMAL',
|
1: 'NORMAL',
|
||||||
2: 'WARNING',
|
2: 'WARNING',
|
||||||
3: 'REQUIRES_ATTENTION',
|
3: 'REQUIRES_ATTENTION',
|
||||||
};
|
} as const;
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ export async function getOrSetCart(countryCode: string) {
|
|||||||
return cart;
|
return cart;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateCart(data: HttpTypes.StoreUpdateCart) {
|
export async function updateCart({ id, ...data }: HttpTypes.StoreUpdateCart & { id?: string }) {
|
||||||
const cartId = await getCartId();
|
const cartId = id || (await getCartId());
|
||||||
|
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
Reference in New Issue
Block a user