import axios from 'axios'; import { XMLParser } from 'fast-xml-parser'; import fs from 'fs'; import { createAnalysisGroup, getAnalysisGroups } from '~/lib/services/analysis-group.service'; import { IMedipostPublicMessageDataParsed } from '~/lib/services/medipost/medipost.types'; import { createAnalysis, createNoDataReceivedEntry, createNoNewDataReceivedEntry, createSyncFailEntry, createSyncSuccessEntry, getAnalyses } from '~/lib/services/analyses.service'; import { getLastCheckedDate } from '~/lib/services/sync-entries.service'; import { AnalysisElement, createAnalysisElement, getAnalysisElements } from '~/lib/services/analysis-element.service'; import { createCodes } from '~/lib/services/codes.service'; import { getLatestPublicMessageListItem } from '~/lib/services/medipost/medipostPublicMessage.service'; import type { ICode } from '~/lib/types/code'; function toArray(input?: T | T[] | null): T[] { if (!input) return []; return Array.isArray(input) ? input : [input]; } const WRITE_XML_TO_FILE = false as boolean; export default async function syncAnalysisGroups() { 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; if (!baseUrl || !user || !password || !sender) { throw new Error('Could not access all necessary environment variables'); } try { console.info('Getting latest public message id'); const lastCheckedDate = await getLastCheckedDate(); const latestMessage = await getLatestPublicMessageListItem(); if (!latestMessage) { console.info('No new data received'); await createNoNewDataReceivedEntry(); return; } console.info('Getting public message with id: ', latestMessage.messageId); const { data: publicMessageData } = await axios.get(baseUrl, { params: { Action: 'GetPublicMessage', User: user, Password: password, MessageId: latestMessage.messageId, }, headers: { Accept: 'application/xml', }, }); if (WRITE_XML_TO_FILE) { fs.writeFileSync('public-messages-list-response.xml', publicMessageData); } const parser = new XMLParser({ ignoreAttributes: false }); const parsed: IMedipostPublicMessageDataParsed = parser.parse(publicMessageData); if (parsed.ANSWER?.CODE && parsed.ANSWER?.CODE !== 0) { throw new Error( `Failed to get public message (id: ${latestMessage.messageId})`, ); } const existingAnalysisGroups = await getAnalysisGroups(); // SAVE PUBLIC MESSAGE DATA const providers = toArray(parsed?.Saadetis?.Teenused.Teostaja); const analysisGroups = providers.flatMap((provider) => toArray(provider.UuringuGrupp), ); if (!parsed || !analysisGroups.length) { console.info('No analysis groups data received'); await createNoDataReceivedEntry(); return; } const codes: ICode[] = []; for (const analysisGroup of analysisGroups) { const existingAnalysisGroup = existingAnalysisGroups?.find(({ original_id }) => original_id === analysisGroup.UuringuGruppId); let groupExistingAnalysisElements: AnalysisElement[] = []; let analysisGroupId: number; if (existingAnalysisGroup) { console.info(`Analysis group '${analysisGroup.UuringuGruppNimi}' already exists, only creating new analysis elements`); groupExistingAnalysisElements = await getAnalysisElements({ analysisGroupId: existingAnalysisGroup.id }); analysisGroupId = existingAnalysisGroup.id; } else { analysisGroupId = await createAnalysisGroup({ id: analysisGroup.UuringuGruppId, name: analysisGroup.UuringuGruppNimi, order: analysisGroup.UuringuGruppJarjekord, }); 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 isExistingAnalysisElement = groupExistingAnalysisElements .find(({ analysis_id_original }) => analysis_id_original === analysisElement.UuringId); if (isExistingAnalysisElement) { console.info(`Analysis element '${analysisElement.UuringNimi}' already exists`); continue; } const insertedAnalysisElementId = await createAnalysisElement({ analysisElement: analysisElement!, analysisGroupId, materialGroups: toArray(item.MaterjalideGrupp), }); if (Array.isArray(analysisElement.UuringuElement)) { for (const nestedAnalysisElement of analysisElement.UuringuElement) { await createAnalysisElement({ analysisElement: nestedAnalysisElement, analysisGroupId, materialGroups: toArray(item.MaterjalideGrupp), }); } } 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) { const existingAnalyses = await getAnalyses({ originalIds: analyses.map(({ UuringId }) => UuringId) }); for (const analysis of analyses) { const isExistingAnalysis = existingAnalyses.find(({ analysis_id_original }) => analysis_id_original === analysis.UuringId); if (isExistingAnalysis) { console.info(`Analysis '${analysis.UuringNimi}' already exists`); continue; } const insertedAnalysisId = await createAnalysis(analysis, analysisGroupId); 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, })), ); } } } } } console.info('Inserting codes'); await createCodes(codes); console.info('Inserting sync entry'); await createSyncSuccessEntry(); } catch (e) { const errorMessage = e instanceof Error ? e.message : String(e); await createSyncFailEntry(JSON.stringify({ message: errorMessage, stack: e instanceof Error ? e.stack : undefined, name: e instanceof Error ? e.name : 'Unknown', }, null, 2)); console.error('Sync failed:', e); throw new Error( `Failed to sync public message data, error: ${errorMessage}`, ); } }