import { createClient as createCustomClient } from '@supabase/supabase-js'; import axios from 'axios'; import { format } from 'date-fns'; import { config } from 'dotenv'; import { XMLParser } from 'fast-xml-parser'; function getLatestMessage(messages) { if (!messages?.length) { return null; } return messages.reduce((prev, current) => Number(prev.messageId) > Number(current.messageId) ? prev : current, ); } export function toArray(input?: T | T[] | null): T[] { if (!input) return []; return Array.isArray(input) ? input : [input]; } async function syncData() { if (process.env.NODE_ENV === 'local') { config({ path: `.env.${process.env.NODE_ENV}` }); } const baseUrl = process.env.MEDIPOST_URL; const user = process.env.MEDIPOST_USER; const password = process.env.MEDIPOST_PASSWORD; const sender = process.env.MEDIPOST_MESSAGE_SENDER; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseServiceRoleKey = process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY; if ( !baseUrl || !supabaseUrl || !supabaseServiceRoleKey || !user || !password || !sender ) { throw new Error('Could not access all necessary environment variables'); } const supabase = createCustomClient(supabaseUrl, supabaseServiceRoleKey, { auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false, }, }); try { // GET LATEST PUBLIC MESSAGE ID const { data: lastChecked } = await supabase .schema('audit') .from('sync_entries') .select('created_at') .eq('status', 'SUCCESS') .order('created_at') .limit(1); const lastCheckedDate = lastChecked?.length ? { LastChecked: format(lastChecked[0].created_at, 'yyyy-MM-dd HH:mm:ss'), } : {}; const { data } = await axios.get(baseUrl, { params: { Action: 'GetPublicMessageList', User: user, Password: password, Sender: sender, ...lastCheckedDate, MessageType: 'Teenus', }, }); if (data.code && data.code !== 0) { throw new Error('Failed to get public message list'); } if (!data.messages.length) { return supabase.schema('audit').from('sync_entries').insert({ operation: 'ANALYSES_SYNC', comment: 'No new data received', status: 'SUCCESS', changed_by_role: 'service_role', }); } const latestMessage = getLatestMessage(data?.messages); // GET PUBLIC MESSAGE WITH GIVEN ID const { data: publicMessageData } = await axios.get(baseUrl, { params: { Action: 'GetPublicMessage', User: user, Password: password, MessageId: latestMessage.messageId, }, headers: { Accept: 'application/xml', }, }); const parser = new XMLParser({ ignoreAttributes: false }); const parsed = parser.parse(publicMessageData); if (parsed.ANSWER?.CODE && parsed.ANSWER?.CODE !== 0) { throw new Error( `Failed to get public message (id: ${latestMessage.messageId})`, ); } // SAVE PUBLIC MESSAGE DATA const providers = toArray(parsed?.Saadetis?.Teenused.Teostaja); const analysisGroups = providers.flatMap((provider) => toArray(provider.UuringuGrupp), ); if (!parsed || !analysisGroups.length) { return supabase.schema('audit').from('sync_entries').insert({ operation: 'ANALYSES_SYNC', comment: 'No data received', status: 'FAIL', changed_by_role: 'service_role', }); } const codes: any[] = []; for (const analysisGroup of analysisGroups) { // SAVE ANALYSIS GROUP const { data: insertedAnalysisGroup, error } = await supabase .schema('medreport') .from('analysis_groups') .upsert( { original_id: analysisGroup.UuringuGruppId, name: analysisGroup.UuringuGruppNimi, order: analysisGroup.UuringuGruppJarjekord, }, { onConflict: 'original_id', ignoreDuplicates: false }, ) .select('id'); if (error || !insertedAnalysisGroup[0]?.id) { throw new Error( `Failed to insert analysis group (id: ${analysisGroup.UuringuGruppId}), error: ${error?.message}`, ); } const analysisGroupId = insertedAnalysisGroup[0].id; const analysisGroupCodes = toArray(analysisGroup.Kood); codes.push( ...analysisGroupCodes.map((kood) => ({ hk_code: kood.HkKood, hk_code_multiplier: kood.HkKoodiKordaja, coefficient: kood.Koefitsient, price: kood.Hind, analysis_group_id: analysisGroupId, analysis_element_id: null, analysis_id: null, })), ); const analysisGroupItems = toArray(analysisGroup.Uuring); for (const item of analysisGroupItems) { const analysisElement = item.UuringuElement; const { data: insertedAnalysisElement, error } = await supabase .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: toArray(item.MaterjalideGrupp), }, { onConflict: 'analysis_id_original', ignoreDuplicates: false }, ) .select('id'); if (error || !insertedAnalysisElement[0]?.id) { throw new Error( `Failed to insert analysis element (id: ${analysisElement.UuringId}), error: ${error?.message}`, ); } const insertedAnalysisElementId = insertedAnalysisElement[0].id; if (analysisElement.Kood) { const analysisElementCodes = toArray(analysisElement.Kood); codes.push( ...analysisElementCodes.map((kood) => ({ hk_code: kood.HkKood, hk_code_multiplier: kood.HkKoodiKordaja, coefficient: kood.Koefitsient, price: kood.Hind, analysis_group_id: null, analysis_element_id: insertedAnalysisElementId, analysis_id: null, })), ); } const analyses = analysisElement.UuringuElement; if (analyses?.length) { for (const analysis of analyses) { const { data: insertedAnalysis, error } = await supabase .schema('medreport') .from('analyses') .upsert( { analysis_id_oid: analysis.UuringIdOID, analysis_id_original: analysis.UuringId, tehik_short_loinc: analysis.TLyhend, tehik_loinc_name: analysis.KNimetus, analysis_name_lab: analysis.UuringNimi, order: analysis.Jarjekord, parent_analysis_element_id: insertedAnalysisElementId, }, { onConflict: 'analysis_id_original', ignoreDuplicates: false }, ) .select('id'); if (error || !insertedAnalysis[0]?.id) { throw new Error( `Failed to insert analysis (id: ${analysis.UuringId}) error: ${error?.message}`, ); } const insertedAnalysisId = insertedAnalysis[0].id; if (analysis.Kood) { const analysisCodes = toArray(analysis.Kood); codes.push( ...analysisCodes.map((kood) => ({ hk_code: kood.HkKood, hk_code_multiplier: kood.HkKoodiKordaja, coefficient: kood.Koefitsient, price: kood.Hind, analysis_group_id: null, analysis_element_id: null, analysis_id: insertedAnalysisId, })), ); } } } } } await supabase.schema('medreport').from('codes').upsert(codes); await supabase.schema('audit').from('sync_entries').insert({ operation: 'ANALYSES_SYNC', status: 'SUCCESS', changed_by_role: 'service_role', }); } catch (e) { await supabase .schema('audit') .from('sync_entries') .insert({ operation: 'ANALYSES_SYNC', status: 'FAIL', comment: JSON.stringify(e), changed_by_role: 'service_role', }); throw new Error( `Failed to sync public message data, error: ${JSON.stringify(e)}`, ); } } syncData();