diff --git a/lib/services/analyses.service.ts b/lib/services/analyses.service.ts index 0127e09..790b201 100644 --- a/lib/services/analyses.service.ts +++ b/lib/services/analyses.service.ts @@ -2,7 +2,7 @@ import type { Tables } from '@/packages/supabase/src/database.types'; import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client'; import type { IUuringElement } from "./medipost.types"; -type AnalysesWithGroupsAndElements = ({ +export type AnalysesWithGroupsAndElements = ({ analysis_elements: Tables<{ schema: 'medreport' }, 'analysis_elements'> & { analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>; }; @@ -105,7 +105,13 @@ export const createMedusaSyncSuccessEntry = async () => { }); } -export async function getAnalyses({ ids, originalIds }: { ids?: number[], originalIds?: string[] }): Promise { +export async function getAnalyses({ + ids, + originalIds, +}: { + ids?: number[]; + originalIds?: string[]; +}): Promise { const query = getSupabaseServerAdminClient() .schema('medreport') .from('analyses') diff --git a/lib/services/medipost.service.ts b/lib/services/medipost.service.ts index b6aec5d..4171977 100644 --- a/lib/services/medipost.service.ts +++ b/lib/services/medipost.service.ts @@ -5,23 +5,11 @@ import { createClient as createCustomClient, } from '@supabase/supabase-js'; -import { - getAnalysisGroup, - getClientInstitution, - getClientPerson, - getConfidentiality, - getOrderEnteredPerson, - getPais, - getPatient, - getProviderInstitution, - getSpecimen, -} from '@/lib/templates/medipost-order'; import { SyncStatus } from '@/lib/types/audit'; import { AnalysisOrderStatus, GetMessageListResponse, IMedipostResponseXMLBase, - MaterjalideGrupp, MedipostAction, MedipostOrderResponse, MedipostPublicMessageResponse, @@ -32,7 +20,6 @@ import { import { toArray } from '@/lib/utils'; import axios from 'axios'; import { XMLParser } from 'fast-xml-parser'; -import { uniqBy } from 'lodash'; import { Tables } from '@kit/supabase/database'; import { createAnalysisGroup } from './analysis-group.service'; @@ -47,6 +34,7 @@ import { listRegions } from '@lib/data/regions'; import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product'; import { MedipostValidationError } from './medipost/MedipostValidationError'; import { logMedipostDispatch } from './audit.service'; +import { composeOrderXML, OrderedAnalysisElement } from './medipostXML.service'; const BASE_URL = process.env.MEDIPOST_URL!; const USER = process.env.MEDIPOST_USER!; @@ -451,122 +439,6 @@ export async function syncPublicMessage( } } -export async function composeOrderXML({ - person, - orderedAnalysisElementsIds, - orderedAnalysesIds, - orderId, - orderCreatedAt, - comment, -}: { - person: { - idCode: string; - firstName: string; - lastName: string; - phone: string; - }; - orderedAnalysisElementsIds: number[]; - orderedAnalysesIds: number[]; - orderId: string; - orderCreatedAt: Date; - comment?: string; -}) { - const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds }); - if (analysisElements.length !== orderedAnalysisElementsIds.length) { - throw new Error(`Got ${analysisElements.length} analysis elements, expected ${orderedAnalysisElementsIds.length}`); - } - - const analyses = await getAnalyses({ ids: orderedAnalysesIds }); - if (analyses.length !== orderedAnalysesIds.length) { - throw new Error(`Got ${analyses.length} analyses, expected ${orderedAnalysesIds.length}`); - } - - const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] = - uniqBy( - ( - analysisElements?.flatMap(({ analysis_groups }) => analysis_groups) ?? - [] - ).concat( - analyses?.flatMap( - ({ analysis_elements }) => analysis_elements.analysis_groups, - ) ?? [], - ), - 'id', - ); - - const specimenSection = []; - const analysisSection = []; - let order = 1; - for (const currentGroup of analysisGroups) { - let relatedAnalysisElement = analysisElements?.find( - (element) => element.analysis_groups.id === currentGroup.id, - ); - const relatedAnalyses = analyses?.filter((analysis) => { - return analysis.analysis_elements.analysis_groups.id === currentGroup.id; - }); - - if (!relatedAnalysisElement) { - relatedAnalysisElement = relatedAnalyses?.find( - (relatedAnalysis) => - relatedAnalysis.analysis_elements.analysis_groups.id === - currentGroup.id, - )?.analysis_elements; - } - - if (!relatedAnalysisElement || !relatedAnalysisElement.material_groups) { - throw new Error( - `Failed to find related analysis element for group ${currentGroup.name} (id: ${currentGroup.id})`, - ); - } - - for (const group of relatedAnalysisElement?.material_groups as MaterjalideGrupp[]) { - const materials = toArray(group.Materjal); - const specimenXml = materials.flatMap( - ({ MaterjaliNimi, MaterjaliTyyp, MaterjaliTyypOID, Konteiner }) => { - return toArray(Konteiner).map((container) => - getSpecimen( - MaterjaliTyypOID, - MaterjaliTyyp, - MaterjaliNimi, - order, - container.ProovinouKoodOID, - container.ProovinouKood, - ), - ); - }, - ); - - specimenSection.push(...specimenXml); - } - - const groupXml = getAnalysisGroup( - currentGroup.original_id, - currentGroup.name, - order, - relatedAnalysisElement, - ); - order++; - analysisSection.push(groupXml); - } - - return ` - - ${getPais(USER, RECIPIENT, orderCreatedAt, orderId)} - - ${orderId} - ${getClientInstitution()} - ${getProviderInstitution()} - ${getClientPerson()} - ${getOrderEnteredPerson()} - ${comment ?? ''} - ${getPatient(person)} - ${getConfidentiality()} - ${specimenSection.join('')} - ${analysisSection?.join('')} - -`; -} - function getLatestMessage({ messages, excludedMessageIds, @@ -714,20 +586,36 @@ export async function sendOrderToMedipost({ orderedAnalysisElements, }: { medusaOrderId: string; - orderedAnalysisElements: { analysisElementId?: number; analysisId?: number }[]; + orderedAnalysisElements: OrderedAnalysisElement[]; }) { const medreportOrder = await getOrder({ medusaOrderId }); const account = await getAccountAdmin({ primaryOwnerUserId: medreportOrder.user_id }); + const orderedAnalysesIds = orderedAnalysisElements + .map(({ analysisId }) => analysisId) + .filter(Boolean) as number[]; + const orderedAnalysisElementsIds = orderedAnalysisElements + .map(({ analysisElementId }) => analysisElementId) + .filter(Boolean) as number[]; + + const analyses = await getAnalyses({ ids: orderedAnalysesIds }); + if (analyses.length !== orderedAnalysesIds.length) { + throw new Error(`Got ${analyses.length} analyses, expected ${orderedAnalysesIds.length}`); + } + const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds }); + if (analysisElements.length !== orderedAnalysisElementsIds.length) { + throw new Error(`Got ${analysisElements.length} analysis elements, expected ${orderedAnalysisElementsIds.length}`); + } + const orderXml = await composeOrderXML({ + analyses, + analysisElements, person: { idCode: account.personal_code!, firstName: account.name ?? '', lastName: account.last_name ?? '', phone: account.phone ?? '', }, - orderedAnalysisElementsIds: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId).filter(Boolean) as number[], - orderedAnalysesIds: orderedAnalysisElements.map(({ analysisId }) => analysisId).filter(Boolean) as number[], orderId: medusaOrderId, orderCreatedAt: new Date(medreportOrder.created_at), comment: '', diff --git a/lib/services/medipostXML.service.ts b/lib/services/medipostXML.service.ts new file mode 100644 index 0000000..ad6fb04 --- /dev/null +++ b/lib/services/medipostXML.service.ts @@ -0,0 +1,136 @@ +'use server'; + +import { + getAnalysisGroup, + getClientInstitution, + getClientPerson, + getConfidentiality, + getOrderEnteredPerson, + getPais, + getPatient, + getProviderInstitution, + getSpecimen, +} from '@/lib/templates/medipost-order'; +import { + MaterjalideGrupp, +} from '@/lib/types/medipost'; +import { toArray } from '@/lib/utils'; +import { uniqBy } from 'lodash'; + +import { Tables } from '@kit/supabase/database'; +import { AnalysisElement } from './analysis-element.service'; +import { AnalysesWithGroupsAndElements } from './analyses.service'; + +const USER = process.env.MEDIPOST_USER!; +const RECIPIENT = process.env.MEDIPOST_RECIPIENT!; + +export type OrderedAnalysisElement = { + analysisElementId?: number; + analysisId?: number; +} + +export async function composeOrderXML({ + analyses, + analysisElements, + person, + orderId, + orderCreatedAt, + comment, +}: { + analyses: AnalysesWithGroupsAndElements; + analysisElements: AnalysisElement[]; + person: { + idCode: string; + firstName: string; + lastName: string; + phone: string; + }; + orderId: string; + orderCreatedAt: Date; + comment?: string; +}) { + const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] = + uniqBy( + ( + analysisElements?.flatMap(({ analysis_groups }) => analysis_groups) ?? + [] + ).concat( + analyses?.flatMap( + ({ analysis_elements }) => analysis_elements.analysis_groups, + ) ?? [], + ), + 'id', + ); + + const specimenSection = []; + const analysisSection = []; + let order = 1; + for (const currentGroup of analysisGroups) { + let relatedAnalysisElement = analysisElements?.find( + (element) => element.analysis_groups.id === currentGroup.id, + ); + const relatedAnalyses = analyses?.filter((analysis) => { + return analysis.analysis_elements.analysis_groups.id === currentGroup.id; + }); + + if (!relatedAnalysisElement) { + relatedAnalysisElement = relatedAnalyses?.find( + (relatedAnalysis) => + relatedAnalysis.analysis_elements.analysis_groups.id === + currentGroup.id, + )?.analysis_elements; + } + + if (!relatedAnalysisElement || !relatedAnalysisElement.material_groups) { + throw new Error( + `Failed to find related analysis element for group ${currentGroup.name} (id: ${currentGroup.id})`, + ); + } + + for (const group of relatedAnalysisElement?.material_groups as MaterjalideGrupp[]) { + const materials = toArray(group.Materjal); + const specimenXml = materials.flatMap( + ({ MaterjaliNimi, MaterjaliTyyp, MaterjaliTyypOID, Konteiner }) => { + return toArray(Konteiner).map((container) => + getSpecimen( + MaterjaliTyypOID, + MaterjaliTyyp, + MaterjaliNimi, + order, + container.ProovinouKoodOID, + container.ProovinouKood, + ), + ); + }, + ); + + specimenSection.push(...specimenXml); + } + + const groupXml = getAnalysisGroup( + currentGroup.original_id, + currentGroup.name, + order, + relatedAnalysisElement, + ); + order++; + analysisSection.push(groupXml); + } + + return ` + + ${getPais(USER, RECIPIENT, orderCreatedAt, orderId)} + + ${orderId} + ${getClientInstitution()} + ${getProviderInstitution()} + ${getClientPerson()} + ${getOrderEnteredPerson()} + ${comment ?? ''} + ${getPatient(person)} + ${getConfidentiality()} + ${specimenSection.join('')} + ${analysisSection?.join('')} + +`; +}