prettier fix
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import type { Tables } from '@/packages/supabase/src/database.types';
|
||||
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
import type { IUuringElement } from "./medipost/medipost.types";
|
||||
|
||||
import type { IUuringElement } from './medipost/medipost.types';
|
||||
|
||||
export type AnalysesWithGroupsAndElements = ({
|
||||
analysis_elements: Tables<{ schema: 'medreport' }, 'analysis_elements'> & {
|
||||
@@ -37,7 +39,7 @@ export const createAnalysis = async (
|
||||
}
|
||||
|
||||
return insertedAnalysisId;
|
||||
}
|
||||
};
|
||||
|
||||
const createSyncEntry = async ({
|
||||
operation,
|
||||
@@ -49,14 +51,15 @@ const createSyncEntry = async ({
|
||||
comment?: string;
|
||||
}) => {
|
||||
await getSupabaseServerAdminClient()
|
||||
.schema('audit').from('sync_entries')
|
||||
.schema('audit')
|
||||
.from('sync_entries')
|
||||
.insert({
|
||||
operation,
|
||||
status,
|
||||
changed_by_role: 'service_role',
|
||||
comment,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createNoNewDataReceivedEntry = async () => {
|
||||
await createSyncEntry({
|
||||
@@ -64,7 +67,7 @@ export const createNoNewDataReceivedEntry = async () => {
|
||||
status: 'SUCCESS',
|
||||
comment: 'No new data received',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createNoDataReceivedEntry = async () => {
|
||||
await createSyncEntry({
|
||||
@@ -72,7 +75,7 @@ export const createNoDataReceivedEntry = async () => {
|
||||
status: 'SUCCESS',
|
||||
comment: 'No data received',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createSyncFailEntry = async (error: string) => {
|
||||
await createSyncEntry({
|
||||
@@ -80,14 +83,14 @@ export const createSyncFailEntry = async (error: string) => {
|
||||
status: 'FAIL',
|
||||
comment: error,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createSyncSuccessEntry = async () => {
|
||||
await createSyncEntry({
|
||||
operation: 'ANALYSES_SYNC',
|
||||
status: 'SUCCESS',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createMedusaSyncFailEntry = async (error: string) => {
|
||||
await createSyncEntry({
|
||||
@@ -95,15 +98,14 @@ export const createMedusaSyncFailEntry = async (error: string) => {
|
||||
status: 'FAIL',
|
||||
comment: error,
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const createMedusaSyncSuccessEntry = async () => {
|
||||
await createSyncEntry({
|
||||
operation: 'ANALYSES_MEDUSA_SYNC',
|
||||
status: 'SUCCESS',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function getAnalyses({
|
||||
ids,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Json, Tables } from '@kit/supabase/database';
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
|
||||
import type { IMaterialGroup, IUuringElement } from './medipost/medipost.types';
|
||||
|
||||
export type AnalysisElement = Tables<{ schema: 'medreport' }, 'analysis_elements'> & {
|
||||
export type AnalysisElement = Tables<
|
||||
{ schema: 'medreport' },
|
||||
'analysis_elements'
|
||||
> & {
|
||||
analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>;
|
||||
};
|
||||
|
||||
@@ -27,8 +31,15 @@ export async function getAnalysisElements({
|
||||
const hasIdsFilter = Array.isArray(ids);
|
||||
const hasAnalysisGroupIdFilter = typeof analysisGroupId === 'number';
|
||||
|
||||
if (!hasOriginalIdsFilter && !hasIdsFilter && !hasAnalysisGroupIdFilter && getAll !== true) {
|
||||
throw new Error('Either originalIds, ids, or analysisGroupId must be provided');
|
||||
if (
|
||||
!hasOriginalIdsFilter &&
|
||||
!hasIdsFilter &&
|
||||
!hasAnalysisGroupIdFilter &&
|
||||
getAll !== true
|
||||
) {
|
||||
throw new Error(
|
||||
'Either originalIds, ids, or analysisGroupId must be provided',
|
||||
);
|
||||
}
|
||||
|
||||
if (hasOriginalIdsFilter) {
|
||||
@@ -85,23 +96,24 @@ export async function createAnalysisElement({
|
||||
analysisGroupId: number;
|
||||
materialGroups: IMaterialGroup[];
|
||||
}) {
|
||||
const { data: insertedAnalysisElement, error } = await getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_elements')
|
||||
.upsert(
|
||||
{
|
||||
analysis_id_oid: analysisElement.UuringIdOID,
|
||||
analysis_id_original: analysisElement.UuringId,
|
||||
tehik_short_loinc: analysisElement.TLyhend,
|
||||
tehik_loinc_name: analysisElement.KNimetus,
|
||||
analysis_name_lab: analysisElement.UuringNimi,
|
||||
order: analysisElement.Jarjekord,
|
||||
parent_analysis_group_id: analysisGroupId,
|
||||
material_groups: materialGroups as unknown as Json[],
|
||||
},
|
||||
{ onConflict: 'analysis_id_original', ignoreDuplicates: false },
|
||||
)
|
||||
.select('id');
|
||||
const { data: insertedAnalysisElement, error } =
|
||||
await getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_elements')
|
||||
.upsert(
|
||||
{
|
||||
analysis_id_oid: analysisElement.UuringIdOID,
|
||||
analysis_id_original: analysisElement.UuringId,
|
||||
tehik_short_loinc: analysisElement.TLyhend,
|
||||
tehik_loinc_name: analysisElement.KNimetus,
|
||||
analysis_name_lab: analysisElement.UuringNimi,
|
||||
order: analysisElement.Jarjekord,
|
||||
parent_analysis_group_id: analysisGroupId,
|
||||
material_groups: materialGroups as unknown as Json[],
|
||||
},
|
||||
{ onConflict: 'analysis_id_original', ignoreDuplicates: false },
|
||||
)
|
||||
.select('id');
|
||||
|
||||
const id = insertedAnalysisElement?.[0]?.id;
|
||||
if (error || !id) {
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import { getSupabaseServerAdminClient } from "@kit/supabase/server-admin-client";
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
|
||||
export const createAnalysisGroup = async (
|
||||
analysisGroup: {
|
||||
id: string;
|
||||
name: string;
|
||||
order: number;
|
||||
}
|
||||
) => {
|
||||
const { data: insertedAnalysisGroup, error } = await getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_groups')
|
||||
.upsert(
|
||||
{
|
||||
original_id: analysisGroup.id,
|
||||
name: analysisGroup.name,
|
||||
order: analysisGroup.order,
|
||||
},
|
||||
{ onConflict: 'original_id', ignoreDuplicates: false },
|
||||
)
|
||||
.select('id');
|
||||
export const createAnalysisGroup = async (analysisGroup: {
|
||||
id: string;
|
||||
name: string;
|
||||
order: number;
|
||||
}) => {
|
||||
const { data: insertedAnalysisGroup, error } =
|
||||
await getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_groups')
|
||||
.upsert(
|
||||
{
|
||||
original_id: analysisGroup.id,
|
||||
name: analysisGroup.name,
|
||||
order: analysisGroup.order,
|
||||
},
|
||||
{ onConflict: 'original_id', ignoreDuplicates: false },
|
||||
)
|
||||
.select('id');
|
||||
const analysisGroupId = insertedAnalysisGroup?.[0]?.id as number;
|
||||
|
||||
if (error || !analysisGroupId) {
|
||||
@@ -28,7 +27,7 @@ export const createAnalysisGroup = async (
|
||||
}
|
||||
|
||||
return analysisGroupId;
|
||||
}
|
||||
};
|
||||
|
||||
export const getAnalysisGroups = async () => {
|
||||
const { data: analysisGroups } = await getSupabaseServerAdminClient()
|
||||
@@ -37,4 +36,4 @@ export const getAnalysisGroups = async () => {
|
||||
.select('*');
|
||||
|
||||
return analysisGroups;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getSupabaseServerAdminClient } from "@/packages/supabase/src/clients/server-admin-client";
|
||||
import { AnalysisOrderStatus } from '@/packages/shared/src/types/medipost-analysis';
|
||||
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||
|
||||
import type { AnalysisResponseElement } from "../types/analysis-response-element";
|
||||
import type { AnalysisResponseElement } from '../types/analysis-response-element';
|
||||
|
||||
export async function getExistingAnalysisResponseElements({
|
||||
analysisResponseId,
|
||||
@@ -26,20 +26,17 @@ export async function upsertAnalysisResponseElement({
|
||||
const { data } = await getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_response_elements')
|
||||
.upsert(
|
||||
element,
|
||||
{
|
||||
onConflict: 'analysis_response_id,analysis_element_original_id',
|
||||
ignoreDuplicates: false
|
||||
}
|
||||
)
|
||||
.upsert(element, {
|
||||
onConflict: 'analysis_response_id,analysis_element_original_id',
|
||||
ignoreDuplicates: false,
|
||||
})
|
||||
.select('id')
|
||||
.throwOnError();
|
||||
|
||||
const analysisResponseElementId = data?.[0]?.id;
|
||||
if (!analysisResponseElementId) {
|
||||
throw new Error(
|
||||
`Failed to insert or update analysis response element (response id: ${element.analysis_response_id}, element id: ${element.analysis_element_original_id})`
|
||||
`Failed to insert or update analysis response element (response id: ${element.analysis_response_id}, element id: ${element.analysis_element_original_id})`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,7 +51,7 @@ export async function upsertAnalysisResponse({
|
||||
}: {
|
||||
analysisOrderId: number;
|
||||
orderNumber: string;
|
||||
orderStatus: typeof AnalysisOrderStatus[keyof typeof AnalysisOrderStatus];
|
||||
orderStatus: (typeof AnalysisOrderStatus)[keyof typeof AnalysisOrderStatus];
|
||||
userId: string;
|
||||
}) {
|
||||
const { data: analysisResponse } = await getSupabaseServerAdminClient()
|
||||
@@ -72,7 +69,6 @@ export async function upsertAnalysisResponse({
|
||||
.select('id')
|
||||
.throwOnError();
|
||||
|
||||
|
||||
const analysisResponseId = analysisResponse?.[0]?.id;
|
||||
if (!analysisResponseId) {
|
||||
throw new Error(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use server'
|
||||
|
||||
'use server';
|
||||
|
||||
import { RequestStatus } from '@/lib/types/audit';
|
||||
import { ConnectedOnlineMethodName } from '@/lib/types/connected-online';
|
||||
import { ExternalApi } from '@/lib/types/external';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { getSupabaseServerAdminClient } from "@kit/supabase/server-admin-client";
|
||||
import type { ICode } from "~/lib/types/code";
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
|
||||
import type { ICode } from '~/lib/types/code';
|
||||
|
||||
export const createCodes = async (codes: ICode[]) => {
|
||||
await getSupabaseServerAdminClient()
|
||||
.schema('medreport').from('codes')
|
||||
.schema('medreport')
|
||||
.from('codes')
|
||||
.upsert(codes);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import type { Message } from '@/lib/types/medipost';
|
||||
|
||||
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||
|
||||
export async function getLatestMessage({
|
||||
@@ -15,14 +14,17 @@ export async function getLatestMessage({
|
||||
return null;
|
||||
}
|
||||
|
||||
const filtered = messages.filter(({ messageId }) => !excludedMessageIds?.includes(messageId));
|
||||
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,
|
||||
return filtered.reduce(
|
||||
(prev, current) =>
|
||||
Number(prev.messageId) > Number(current.messageId) ? prev : current,
|
||||
{ messageId: '' } as Message,
|
||||
);
|
||||
}
|
||||
@@ -38,9 +40,9 @@ export async function upsertMedipostActionLog({
|
||||
medipostPrivateMessageId,
|
||||
}: {
|
||||
action:
|
||||
| 'send_order_to_medipost'
|
||||
| 'sync_analysis_results_from_medipost'
|
||||
| 'send_fake_analysis_results_to_medipost';
|
||||
| 'send_order_to_medipost'
|
||||
| 'sync_analysis_results_from_medipost'
|
||||
| 'send_fake_analysis_results_to_medipost';
|
||||
xml: string;
|
||||
hasAnalysisResults?: boolean;
|
||||
medusaOrderId?: string | null;
|
||||
@@ -63,10 +65,10 @@ export async function upsertMedipostActionLog({
|
||||
medipost_external_order_id: medipostExternalOrderId,
|
||||
medipost_private_message_id: medipostPrivateMessageId,
|
||||
},
|
||||
{
|
||||
onConflict: 'medipost_private_message_id',
|
||||
ignoreDuplicates: false
|
||||
}
|
||||
{
|
||||
onConflict: 'medipost_private_message_id',
|
||||
ignoreDuplicates: false,
|
||||
},
|
||||
)
|
||||
.select('id')
|
||||
.throwOnError();
|
||||
@@ -74,7 +76,7 @@ export async function upsertMedipostActionLog({
|
||||
const medipostActionId = data?.[0]?.id;
|
||||
if (!medipostActionId) {
|
||||
throw new Error(
|
||||
`Failed to insert or update medipost action (private message id: ${medipostPrivateMessageId})`
|
||||
`Failed to insert or update medipost action (private message id: ${medipostPrivateMessageId})`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { AnalysisResponseElement } from "~/lib/types/analysis-response-element";
|
||||
import { canCreateAnalysisResponseElement, getAnalysisResponseElementsForGroup } from "./medipostPrivateMessage.service";
|
||||
import { ResponseUuring } from "@/packages/shared/src/types/medipost-analysis";
|
||||
import { ResponseUuring } from '@/packages/shared/src/types/medipost-analysis';
|
||||
|
||||
type TestExistingElement = Pick<AnalysisResponseElement, 'analysis_element_original_id' | 'status' | 'response_value'>;
|
||||
import { AnalysisResponseElement } from '~/lib/types/analysis-response-element';
|
||||
|
||||
import {
|
||||
canCreateAnalysisResponseElement,
|
||||
getAnalysisResponseElementsForGroup,
|
||||
} from './medipostPrivateMessage.service';
|
||||
|
||||
type TestExistingElement = Pick<
|
||||
AnalysisResponseElement,
|
||||
'analysis_element_original_id' | 'status' | 'response_value'
|
||||
>;
|
||||
|
||||
describe('medipostPrivateMessage.service', () => {
|
||||
describe('canCreateAnalysisResponseElement', () => {
|
||||
@@ -16,11 +24,20 @@ describe('medipostPrivateMessage.service', () => {
|
||||
} as const;
|
||||
const responseValue = 1;
|
||||
const log = jest.fn();
|
||||
expect(await canCreateAnalysisResponseElement({ existingElements, groupUuring, responseValue, log })).toBe(true);
|
||||
expect(
|
||||
await canCreateAnalysisResponseElement({
|
||||
existingElements,
|
||||
groupUuring,
|
||||
responseValue,
|
||||
log,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the analysis response element exists and the status is higher', async () => {
|
||||
const existingElements = [{ analysis_element_original_id: '1', status: '2', response_value: 1 }] as TestExistingElement[];
|
||||
const existingElements = [
|
||||
{ analysis_element_original_id: '1', status: '2', response_value: 1 },
|
||||
] as TestExistingElement[];
|
||||
const groupUuring = {
|
||||
UuringuElement: {
|
||||
UuringOlek: 1,
|
||||
@@ -29,7 +46,14 @@ describe('medipostPrivateMessage.service', () => {
|
||||
} as const;
|
||||
const responseValue = 1;
|
||||
const log = jest.fn();
|
||||
expect(await canCreateAnalysisResponseElement({ existingElements, groupUuring, responseValue, log })).toBe(false);
|
||||
expect(
|
||||
await canCreateAnalysisResponseElement({
|
||||
existingElements,
|
||||
groupUuring,
|
||||
responseValue,
|
||||
log,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,8 +73,14 @@ describe('medipostPrivateMessage.service', () => {
|
||||
} as const;
|
||||
const existingElements = [] as TestExistingElement[];
|
||||
const log = jest.fn();
|
||||
expect(await getAnalysisResponseElementsForGroup({ analysisGroup, existingElements, log }))
|
||||
.toEqual([{
|
||||
expect(
|
||||
await getAnalysisResponseElementsForGroup({
|
||||
analysisGroup,
|
||||
existingElements,
|
||||
log,
|
||||
}),
|
||||
).toEqual([
|
||||
{
|
||||
analysis_element_original_id: '1',
|
||||
analysis_name: undefined,
|
||||
comment: null,
|
||||
@@ -68,7 +98,8 @@ describe('medipostPrivateMessage.service', () => {
|
||||
UuringuVastus: [{ VastuseVaartus: '1' }],
|
||||
},
|
||||
status: '1',
|
||||
}]);
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return no new element if element already exists in higher status', async () => {
|
||||
@@ -84,10 +115,17 @@ describe('medipostPrivateMessage.service', () => {
|
||||
},
|
||||
] as unknown as ResponseUuring[],
|
||||
} as const;
|
||||
const existingElements = [{ analysis_element_original_id: '1', status: '2', response_value: 1 }] as TestExistingElement[];
|
||||
const existingElements = [
|
||||
{ analysis_element_original_id: '1', status: '2', response_value: 1 },
|
||||
] as TestExistingElement[];
|
||||
const log = jest.fn();
|
||||
expect(await getAnalysisResponseElementsForGroup({ analysisGroup, existingElements, log }))
|
||||
.toEqual([]);
|
||||
expect(
|
||||
await getAnalysisResponseElementsForGroup({
|
||||
analysisGroup,
|
||||
existingElements,
|
||||
log,
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return no new element if element already exists with response value', async () => {
|
||||
@@ -103,10 +141,17 @@ describe('medipostPrivateMessage.service', () => {
|
||||
},
|
||||
] as unknown as ResponseUuring[],
|
||||
} as const;
|
||||
const existingElements = [{ analysis_element_original_id: '1', status: '1', response_value: 1 }] as TestExistingElement[];
|
||||
const existingElements = [
|
||||
{ analysis_element_original_id: '1', status: '1', response_value: 1 },
|
||||
] as TestExistingElement[];
|
||||
const log = jest.fn();
|
||||
expect(await getAnalysisResponseElementsForGroup({ analysisGroup, existingElements, log }))
|
||||
.toEqual([]);
|
||||
expect(
|
||||
await getAnalysisResponseElementsForGroup({
|
||||
analysisGroup,
|
||||
existingElements,
|
||||
log,
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import {
|
||||
GetMessageListResponse,
|
||||
MedipostAction,
|
||||
} from '@/lib/types/medipost';
|
||||
import { GetMessageListResponse, MedipostAction } from '@/lib/types/medipost';
|
||||
import axios from 'axios';
|
||||
|
||||
import { getLatestMessage } from './medipostMessageBase.service';
|
||||
|
||||
@@ -8,14 +8,13 @@ import {
|
||||
getPatient,
|
||||
getProviderInstitution,
|
||||
} from '@/lib/templates/medipost-order';
|
||||
import {
|
||||
MedipostAction,
|
||||
} from '@/lib/types/medipost';
|
||||
import { MedipostAction } from '@/lib/types/medipost';
|
||||
import axios from 'axios';
|
||||
import { formatDate } from 'date-fns';
|
||||
import { uniqBy } from 'lodash';
|
||||
|
||||
import { Tables } from '@kit/supabase/database';
|
||||
import { formatDate } from 'date-fns';
|
||||
|
||||
import { getAnalyses } from '../analyses.service';
|
||||
import { getAnalysisElementsAdmin } from '../analysis-element.service';
|
||||
import { validateMedipostResponse } from './medipostValidate.service';
|
||||
@@ -71,7 +70,9 @@ export async function composeOrderTestResponseXML({
|
||||
orderId: number;
|
||||
orderCreatedAt: Date;
|
||||
}) {
|
||||
const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds });
|
||||
const analysisElements = await getAnalysisElementsAdmin({
|
||||
ids: orderedAnalysisElementsIds,
|
||||
});
|
||||
const analyses = await getAnalyses({ ids: orderedAnalysesIds });
|
||||
|
||||
const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =
|
||||
@@ -94,13 +95,15 @@ export async function composeOrderTestResponseXML({
|
||||
const orderNumber = orderId;
|
||||
|
||||
const allAnalysisElementsForGroups = analysisElements?.filter((element) => {
|
||||
return analysisGroups.some((group) => group.id === element.analysis_groups.id);
|
||||
return analysisGroups.some(
|
||||
(group) => group.id === element.analysis_groups.id,
|
||||
);
|
||||
});
|
||||
const addedIds = new Set<number>();
|
||||
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Saadetis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="TellimusLOINC.xsd">
|
||||
${getPais(USER, RECIPIENT, orderId, "AL")}
|
||||
${getPais(USER, RECIPIENT, orderId, 'AL')}
|
||||
<Vastus>
|
||||
<ValisTellimuseId>${orderId}</ValisTellimuseId>
|
||||
${getClientInstitution({ index: 1 })}
|
||||
@@ -126,38 +129,54 @@ export async function composeOrderTestResponseXML({
|
||||
<TellimuseNumber>${orderNumber}</TellimuseNumber>
|
||||
|
||||
<TellimuseOlek>${orderStatus}</TellimuseOlek>
|
||||
${allAnalysisElementsForGroups.map((analysisElement) => {
|
||||
const group = analysisGroups.find((group) => group.id === analysisElement.analysis_groups.id);
|
||||
if (!group) {
|
||||
throw new Error(`Failed to find group for analysis element ${analysisElement.id}`);
|
||||
}
|
||||
${allAnalysisElementsForGroups
|
||||
.map((analysisElement) => {
|
||||
const group = analysisGroups.find(
|
||||
(group) => group.id === analysisElement.analysis_groups.id,
|
||||
);
|
||||
if (!group) {
|
||||
throw new Error(
|
||||
`Failed to find group for analysis element ${analysisElement.id}`,
|
||||
);
|
||||
}
|
||||
|
||||
let relatedAnalysisElement = analysisElements?.find(
|
||||
(element) => element.analysis_groups.id === group.id && !addedIds.has(element.id),
|
||||
);
|
||||
const relatedAnalyses = analyses?.filter((analysis) => {
|
||||
return analysis.analysis_elements.analysis_groups.id === group.id && !addedIds.has(analysis.analysis_elements.id);
|
||||
});
|
||||
let relatedAnalysisElement = analysisElements?.find(
|
||||
(element) =>
|
||||
element.analysis_groups.id === group.id &&
|
||||
!addedIds.has(element.id),
|
||||
);
|
||||
const relatedAnalyses = analyses?.filter((analysis) => {
|
||||
return (
|
||||
analysis.analysis_elements.analysis_groups.id === group.id &&
|
||||
!addedIds.has(analysis.analysis_elements.id)
|
||||
);
|
||||
});
|
||||
|
||||
if (!relatedAnalysisElement) {
|
||||
relatedAnalysisElement = relatedAnalyses?.find(
|
||||
(relatedAnalysis) =>
|
||||
relatedAnalysis.analysis_elements.analysis_groups.id ===
|
||||
group.id,
|
||||
)?.analysis_elements;
|
||||
}
|
||||
if (!relatedAnalysisElement) {
|
||||
relatedAnalysisElement = relatedAnalyses?.find(
|
||||
(relatedAnalysis) =>
|
||||
relatedAnalysis.analysis_elements.analysis_groups.id ===
|
||||
group.id,
|
||||
)?.analysis_elements;
|
||||
}
|
||||
|
||||
if (!relatedAnalysisElement || !relatedAnalysisElement.material_groups) {
|
||||
throw new Error(
|
||||
`Failed to find related analysis element for group ${group.name} (id: ${group.id})`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
!relatedAnalysisElement ||
|
||||
!relatedAnalysisElement.material_groups
|
||||
) {
|
||||
throw new Error(
|
||||
`Failed to find related analysis element for group ${group.name} (id: ${group.id})`,
|
||||
);
|
||||
}
|
||||
|
||||
const lower = getRandomInt(0, 100);
|
||||
const upper = getRandomInt(lower + 1, 500);
|
||||
const result = getRandomInt(lower - Math.floor(lower * 0.1), upper + Math.floor(upper * 0.1));
|
||||
addedIds.add(relatedAnalysisElement.id);
|
||||
return (`
|
||||
const lower = getRandomInt(0, 100);
|
||||
const upper = getRandomInt(lower + 1, 500);
|
||||
const result = getRandomInt(
|
||||
lower - Math.floor(lower * 0.1),
|
||||
upper + Math.floor(upper * 0.1),
|
||||
);
|
||||
addedIds.add(relatedAnalysisElement.id);
|
||||
return `
|
||||
<UuringuGrupp>
|
||||
<UuringuGruppId>${group.original_id}</UuringuGruppId>
|
||||
<UuringuGruppNimi>${group.name}</UuringuGruppNimi>
|
||||
@@ -177,15 +196,16 @@ export async function composeOrderTestResponseXML({
|
||||
<VastuseAeg>${formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss')}</VastuseAeg>
|
||||
<NormYlem kaasaarvatud=\"EI\">${upper}</NormYlem>
|
||||
<NormAlum kaasaarvatud=\"EI\">${lower}</NormAlum>
|
||||
<NormiStaatus>${result < lower ? 1 : (result > upper ? 1 : 0)}</NormiStaatus>
|
||||
<NormiStaatus>${result < lower ? 1 : result > upper ? 1 : 0}</NormiStaatus>
|
||||
<ProoviJarjenumber>1</ProoviJarjenumber>
|
||||
</UuringuVastus>
|
||||
</UuringuElement>
|
||||
<UuringuTaitjaAsutuseJnr>2</UuringuTaitjaAsutuseJnr>
|
||||
</Uuring>
|
||||
</UuringuGrupp>
|
||||
`);
|
||||
}).join('')}
|
||||
`;
|
||||
})
|
||||
.join('')}
|
||||
</Vastus>
|
||||
</Saadetis>`;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
'use server';
|
||||
|
||||
import type {
|
||||
IMedipostResponseXMLBase,
|
||||
} from '@/packages/shared/src/types/medipost-analysis';
|
||||
import type { IMedipostResponseXMLBase } from '@/packages/shared/src/types/medipost-analysis';
|
||||
|
||||
import { MedipostValidationError } from './MedipostValidationError';
|
||||
import { parseXML } from '../util/xml.service';
|
||||
import { MedipostValidationError } from './MedipostValidationError';
|
||||
|
||||
export async function validateMedipostResponse(response: string, { canHaveEmptyCode = false }: { canHaveEmptyCode?: boolean } = {}) {
|
||||
export async function validateMedipostResponse(
|
||||
response: string,
|
||||
{ canHaveEmptyCode = false }: { canHaveEmptyCode?: boolean } = {},
|
||||
) {
|
||||
const parsed: IMedipostResponseXMLBase = await parseXML(response);
|
||||
const code = parsed.ANSWER?.CODE;
|
||||
if (canHaveEmptyCode) {
|
||||
if (code && code !== 0) {
|
||||
console.error("Bad response", response);
|
||||
console.error('Bad response', response);
|
||||
throw new MedipostValidationError(response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof code !== 'number' || (code !== 0 && !canHaveEmptyCode)) {
|
||||
console.error("Bad response", response);
|
||||
console.error('Bad response', response);
|
||||
throw new MedipostValidationError(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,14 @@ import {
|
||||
getProviderInstitution,
|
||||
getSpecimen,
|
||||
} from '@/lib/templates/medipost-order';
|
||||
import {
|
||||
MaterjalideGrupp,
|
||||
} from '@/lib/types/medipost';
|
||||
import { toArray } from '@kit/shared/utils';
|
||||
import { MaterjalideGrupp } from '@/lib/types/medipost';
|
||||
import { uniqBy } from 'lodash';
|
||||
|
||||
import { toArray } from '@kit/shared/utils';
|
||||
import { Tables } from '@kit/supabase/database';
|
||||
import { AnalysisElement } from '../analysis-element.service';
|
||||
|
||||
import { AnalysesWithGroupsAndElements } from '../analyses.service';
|
||||
import { AnalysisElement } from '../analysis-element.service';
|
||||
|
||||
const USER = process.env.MEDIPOST_USER!;
|
||||
const RECIPIENT = process.env.MEDIPOST_RECIPIENT!;
|
||||
@@ -27,7 +26,7 @@ const RECIPIENT = process.env.MEDIPOST_RECIPIENT!;
|
||||
export type OrderedAnalysisElement = {
|
||||
analysisElementId?: number;
|
||||
analysisId?: number;
|
||||
}
|
||||
};
|
||||
|
||||
export async function composeOrderXML({
|
||||
analyses,
|
||||
@@ -63,24 +62,32 @@ export async function composeOrderXML({
|
||||
);
|
||||
|
||||
// First, collect all unique materials across all analysis groups
|
||||
const uniqueMaterials = new Map<string, {
|
||||
MaterjaliTyypOID: string;
|
||||
MaterjaliTyyp: string;
|
||||
MaterjaliNimi: string;
|
||||
ProovinouKoodOID?: string;
|
||||
ProovinouKood?: string;
|
||||
order: number;
|
||||
}>();
|
||||
const uniqueMaterials = new Map<
|
||||
string,
|
||||
{
|
||||
MaterjaliTyypOID: string;
|
||||
MaterjaliTyyp: string;
|
||||
MaterjaliNimi: string;
|
||||
ProovinouKoodOID?: string;
|
||||
ProovinouKood?: string;
|
||||
order: number;
|
||||
}
|
||||
>();
|
||||
|
||||
let specimenOrder = 1;
|
||||
|
||||
// Collect all materials from all analysis groups
|
||||
for (const currentGroup of analysisGroups) {
|
||||
let relatedAnalysisElements = analysisElements?.filter(({ analysis_groups }) => analysis_groups.id === currentGroup.id);
|
||||
let relatedAnalysisElements = analysisElements?.filter(
|
||||
({ analysis_groups }) => analysis_groups.id === currentGroup.id,
|
||||
);
|
||||
|
||||
if (!relatedAnalysisElements || relatedAnalysisElements.length === 0) {
|
||||
relatedAnalysisElements = analyses
|
||||
.filter(({ analysis_elements }) => analysis_elements.analysis_groups.id === currentGroup.id)
|
||||
.filter(
|
||||
({ analysis_elements }) =>
|
||||
analysis_elements.analysis_groups.id === currentGroup.id,
|
||||
)
|
||||
.flatMap(({ analysis_elements }) => analysis_elements);
|
||||
}
|
||||
|
||||
@@ -91,7 +98,9 @@ export async function composeOrderXML({
|
||||
}
|
||||
|
||||
for (const analysisElement of relatedAnalysisElements) {
|
||||
for (const { Materjal } of analysisElement.material_groups as MaterjalideGrupp[]) {
|
||||
for (const {
|
||||
Materjal,
|
||||
} of analysisElement.material_groups as MaterjalideGrupp[]) {
|
||||
for (const material of toArray(Materjal)) {
|
||||
const { MaterjaliTyyp } = material;
|
||||
|
||||
@@ -115,7 +124,7 @@ export async function composeOrderXML({
|
||||
}
|
||||
|
||||
// Generate specimen section from unique materials
|
||||
const specimenSection = Array.from(uniqueMaterials.values()).map(material =>
|
||||
const specimenSection = Array.from(uniqueMaterials.values()).map((material) =>
|
||||
getSpecimen(
|
||||
material.MaterjaliTyypOID,
|
||||
material.MaterjaliTyyp,
|
||||
@@ -123,7 +132,7 @@ export async function composeOrderXML({
|
||||
material.order,
|
||||
material.ProovinouKoodOID,
|
||||
material.ProovinouKood,
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
// Generate analysis section with correct specimen references
|
||||
@@ -135,7 +144,10 @@ export async function composeOrderXML({
|
||||
|
||||
if (!relatedAnalysisElements) {
|
||||
relatedAnalysisElements = analyses
|
||||
.filter(({ analysis_elements }) => analysis_elements.analysis_groups.id === currentGroup.id)
|
||||
.filter(
|
||||
({ analysis_elements }) =>
|
||||
analysis_elements.analysis_groups.id === currentGroup.id,
|
||||
)
|
||||
.flatMap(({ analysis_elements }) => analysis_elements);
|
||||
}
|
||||
|
||||
@@ -146,8 +158,8 @@ export async function composeOrderXML({
|
||||
}
|
||||
|
||||
const uuringElementInputs: {
|
||||
analysisElement: Tables<{ schema: 'medreport' }, 'analysis_elements'>,
|
||||
specimenOrderNr: number,
|
||||
analysisElement: Tables<{ schema: 'medreport' }, 'analysis_elements'>;
|
||||
specimenOrderNr: number;
|
||||
}[] = [];
|
||||
for (const analysisElement of relatedAnalysisElements) {
|
||||
for (const group of analysisElement.material_groups as MaterjalideGrupp[]) {
|
||||
@@ -155,7 +167,9 @@ export async function composeOrderXML({
|
||||
for (const material of materials) {
|
||||
const uniqueMaterial = uniqueMaterials.get(material.MaterjaliTyyp);
|
||||
if (!uniqueMaterial) {
|
||||
console.info(`Unique material not found for material: ${material.MaterjaliTyyp}, analysis element: ${analysisElement.id} ${analysisElement.analysis_id_original} ${analysisElement.analysis_name_lab}`);
|
||||
console.info(
|
||||
`Unique material not found for material: ${material.MaterjaliTyyp}, analysis element: ${analysisElement.id} ${analysisElement.analysis_id_original} ${analysisElement.analysis_name_lab}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
uuringElementInputs.push({
|
||||
@@ -177,7 +191,7 @@ export async function composeOrderXML({
|
||||
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Saadetis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="TellimusLOINC.xsd">
|
||||
${getPais(USER, RECIPIENT, orderId, "OL")}
|
||||
${getPais(USER, RECIPIENT, orderId, 'OL')}
|
||||
<Tellimus cito="EI">
|
||||
<ValisTellimuseId>${orderId}</ValisTellimuseId>
|
||||
${getClientInstitution()}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
'use server';
|
||||
|
||||
import { getAnalysisElements } from './analysis-element.service';
|
||||
import { getAnalyses } from './analyses.service';
|
||||
import { StoreOrder } from '@medusajs/types';
|
||||
import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product';
|
||||
import { listProducts } from '@lib/data/products';
|
||||
import { listRegions } from '@lib/data/regions';
|
||||
import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product';
|
||||
import { StoreOrder } from '@medusajs/types';
|
||||
|
||||
import { getAnalyses } from './analyses.service';
|
||||
import { getAnalysisElements } from './analysis-element.service';
|
||||
|
||||
const ANALYSIS_PACKAGE_HANDLE_PREFIX = 'analysis-package-';
|
||||
|
||||
@@ -13,10 +14,12 @@ export async function getOrderedAnalysisIds({
|
||||
medusaOrder,
|
||||
}: {
|
||||
medusaOrder: StoreOrder;
|
||||
}): Promise<{
|
||||
analysisElementId?: number;
|
||||
analysisId?: number;
|
||||
}[]> {
|
||||
}): Promise<
|
||||
{
|
||||
analysisElementId?: number;
|
||||
analysisId?: number;
|
||||
}[]
|
||||
> {
|
||||
const countryCodes = await listRegions();
|
||||
const countryCode = countryCodes[0]!.countries![0]!.iso_2!;
|
||||
|
||||
@@ -37,54 +40,76 @@ export async function getOrderedAnalysisIds({
|
||||
}
|
||||
|
||||
async function getOrderedAnalysisPackages(medusaOrder: StoreOrder) {
|
||||
const orderedPackages = (medusaOrder?.items ?? []).filter(({ product }) => product?.handle.startsWith(ANALYSIS_PACKAGE_HANDLE_PREFIX));
|
||||
const orderedPackageIds = orderedPackages.map(({ product }) => product?.id).filter(Boolean) as string[];
|
||||
const orderedPackages = (medusaOrder?.items ?? []).filter(({ product }) =>
|
||||
product?.handle.startsWith(ANALYSIS_PACKAGE_HANDLE_PREFIX),
|
||||
);
|
||||
const orderedPackageIds = orderedPackages
|
||||
.map(({ product }) => product?.id)
|
||||
.filter(Boolean) as string[];
|
||||
if (orderedPackageIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
console.info(`Order has ${orderedPackageIds.length} packages`);
|
||||
const { response: { products: orderedPackagesProducts } } = await listProducts({
|
||||
const {
|
||||
response: { products: orderedPackagesProducts },
|
||||
} = await listProducts({
|
||||
countryCode,
|
||||
queryParams: { limit: 100, id: orderedPackageIds },
|
||||
});
|
||||
console.info(`Order has ${orderedPackagesProducts.length} packages = ${JSON.stringify(orderedPackageIds, null, 2)}`);
|
||||
console.info(
|
||||
`Order has ${orderedPackagesProducts.length} packages = ${JSON.stringify(orderedPackageIds, null, 2)}`,
|
||||
);
|
||||
if (orderedPackagesProducts.length !== orderedPackageIds.length) {
|
||||
throw new Error(`Got ${orderedPackagesProducts.length} ordered packages products, expected ${orderedPackageIds.length}`);
|
||||
throw new Error(
|
||||
`Got ${orderedPackagesProducts.length} ordered packages products, expected ${orderedPackageIds.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
const ids = getAnalysisElementMedusaProductIds(
|
||||
orderedPackagesProducts.map(({ id, metadata }) => ({
|
||||
metadata,
|
||||
variant: orderedPackages.find(({ product }) => product?.id === id)?.variant,
|
||||
variant: orderedPackages.find(({ product }) => product?.id === id)
|
||||
?.variant,
|
||||
})),
|
||||
);
|
||||
if (ids.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const { response: { products: analysisPackagesProducts } } = await listProducts({
|
||||
const {
|
||||
response: { products: analysisPackagesProducts },
|
||||
} = await listProducts({
|
||||
countryCode,
|
||||
queryParams: { limit: 100, id: ids },
|
||||
});
|
||||
if (analysisPackagesProducts.length !== ids.length) {
|
||||
throw new Error(`Got ${analysisPackagesProducts.length} analysis packages products, expected ${ids.length}`);
|
||||
throw new Error(
|
||||
`Got ${analysisPackagesProducts.length} analysis packages products, expected ${ids.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
const originalIds = analysisPackagesProducts
|
||||
.map(({ metadata }) => metadata?.analysisIdOriginal)
|
||||
.filter((id) => typeof id === 'string');
|
||||
if (originalIds.length !== ids.length) {
|
||||
throw new Error(`Got ${originalIds.length} analysis packages products with analysisIdOriginal, expected ${ids.length}`);
|
||||
throw new Error(
|
||||
`Got ${originalIds.length} analysis packages products with analysisIdOriginal, expected ${ids.length}`,
|
||||
);
|
||||
}
|
||||
const analysisElements = await getAnalysisElements({ originalIds });
|
||||
|
||||
return analysisElements.map(({ id }) => ({ analysisElementId: id }));
|
||||
}
|
||||
|
||||
const [analysisPackageElements, orderedAnalysisElements, orderedAnalyses] = await Promise.all([
|
||||
getOrderedAnalysisPackages(medusaOrder),
|
||||
getOrderedAnalysisElements(medusaOrder),
|
||||
getOrderedAnalyses(medusaOrder),
|
||||
]);
|
||||
const [analysisPackageElements, orderedAnalysisElements, orderedAnalyses] =
|
||||
await Promise.all([
|
||||
getOrderedAnalysisPackages(medusaOrder),
|
||||
getOrderedAnalysisElements(medusaOrder),
|
||||
getOrderedAnalyses(medusaOrder),
|
||||
]);
|
||||
|
||||
return [...analysisPackageElements, ...orderedAnalysisElements, ...orderedAnalyses];
|
||||
return [
|
||||
...analysisPackageElements,
|
||||
...orderedAnalysisElements,
|
||||
...orderedAnalyses,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
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';
|
||||
|
||||
import type { Tables } from '@kit/supabase/database';
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
|
||||
import type { AnalysisOrder } from '../types/analysis-order';
|
||||
|
||||
export async function createAnalysisOrder({
|
||||
@@ -9,19 +11,29 @@ export async function createAnalysisOrder({
|
||||
orderedAnalysisElements,
|
||||
}: {
|
||||
medusaOrder: StoreOrder;
|
||||
orderedAnalysisElements: { analysisElementId?: number; analysisId?: number }[];
|
||||
orderedAnalysisElements: {
|
||||
analysisElementId?: number;
|
||||
analysisId?: number;
|
||||
}[];
|
||||
}) {
|
||||
const supabase = getSupabaseServerClient();
|
||||
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
const orderResult = await supabase.schema('medreport')
|
||||
const orderResult = await supabase
|
||||
.schema('medreport')
|
||||
.from('analysis_orders')
|
||||
.insert({
|
||||
analysis_element_ids: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId).filter(Boolean) as number[],
|
||||
analysis_ids: orderedAnalysisElements.map(({ analysisId }) => analysisId).filter(Boolean) as number[],
|
||||
analysis_element_ids: orderedAnalysisElements
|
||||
.map(({ analysisElementId }) => analysisElementId)
|
||||
.filter(Boolean) as number[],
|
||||
analysis_ids: orderedAnalysisElements
|
||||
.map(({ analysisId }) => analysisId)
|
||||
.filter(Boolean) as number[],
|
||||
status: 'QUEUED',
|
||||
user_id: user.id,
|
||||
medusa_order_id: medusaOrder.id,
|
||||
@@ -31,7 +43,9 @@ export async function createAnalysisOrder({
|
||||
.throwOnError();
|
||||
|
||||
if (orderResult.error || !orderResult.data?.id) {
|
||||
throw new Error(`Failed to create order, message=${orderResult.error}, data=${JSON.stringify(orderResult)}`);
|
||||
throw new Error(
|
||||
`Failed to create order, message=${orderResult.error}, data=${JSON.stringify(orderResult)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return orderResult.data.id;
|
||||
@@ -89,7 +103,7 @@ export async function getAnalysisOrder({
|
||||
const query = getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_orders')
|
||||
.select('*')
|
||||
.select('*');
|
||||
if (medusaOrderId) {
|
||||
query.eq('medusa_order_id', medusaOrderId);
|
||||
} else if (analysisOrderId) {
|
||||
@@ -100,7 +114,9 @@ export async function getAnalysisOrder({
|
||||
|
||||
const { data: order, error } = await query.single();
|
||||
if (error) {
|
||||
throw new Error(`Failed to get order by medusaOrderId=${medusaOrderId} or analysisOrderId=${analysisOrderId}, message=${error.message}, data=${JSON.stringify(order)}`);
|
||||
throw new Error(
|
||||
`Failed to get order by medusaOrderId=${medusaOrderId} or analysisOrderId=${analysisOrderId}, message=${error.message}, data=${JSON.stringify(order)}`,
|
||||
);
|
||||
}
|
||||
return order as AnalysisOrder;
|
||||
}
|
||||
@@ -111,7 +127,7 @@ export async function getAnalysisOrders({
|
||||
orderStatus?: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status'];
|
||||
} = {}) {
|
||||
const client = getSupabaseServerClient();
|
||||
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await client.auth.getUser();
|
||||
@@ -123,11 +139,13 @@ export async function getAnalysisOrders({
|
||||
.schema('medreport')
|
||||
.from('analysis_orders')
|
||||
.select('*')
|
||||
.eq("user_id", user.id)
|
||||
.eq('user_id', user.id);
|
||||
if (orderStatus) {
|
||||
query.eq('status', orderStatus);
|
||||
}
|
||||
const orders = await query.order('created_at', { ascending: false }).throwOnError();
|
||||
const orders = await query
|
||||
.order('created_at', { ascending: false })
|
||||
.throwOnError();
|
||||
return orders.data;
|
||||
}
|
||||
|
||||
@@ -141,13 +159,15 @@ export async function getAnalysisOrdersAdmin({
|
||||
const query = getSupabaseServerAdminClient()
|
||||
.schema('medreport')
|
||||
.from('analysis_orders')
|
||||
.select('*')
|
||||
.select('*');
|
||||
if (orderStatus) {
|
||||
query.eq('status', orderStatus);
|
||||
}
|
||||
if (medusaOrderId) {
|
||||
query.eq('medusa_order_id', medusaOrderId);
|
||||
}
|
||||
const orders = await query.order('created_at', { ascending: false }).throwOnError();
|
||||
const orders = await query
|
||||
.order('created_at', { ascending: false })
|
||||
.throwOnError();
|
||||
return orders.data;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
|
||||
export const getLastCheckedDate = async () => {
|
||||
@@ -15,4 +16,4 @@ export const getLastCheckedDate = async () => {
|
||||
: null;
|
||||
|
||||
return lastCheckedDate;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user