Files
medreport_mrb2b/app/api/job/handler/sync-analysis-groups.ts
2025-09-05 01:39:06 +03:00

190 lines
6.9 KiB
TypeScript

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, IUuringElement } from '~/lib/services/medipost.types';
import { createAnalysis, createNoDataReceivedEntry, createNoNewDataReceivedEntry, createSyncFailEntry, createSyncSuccessEntry } from '~/lib/services/analyses.service';
import { getLastCheckedDate } from '~/lib/services/sync-entries.service';
import { createAnalysisElement, getAnalysisElements } from '~/lib/services/analysis-element.service';
import { createCodes } from '~/lib/services/codes.service';
import { getLatestPublicMessageListItem } from '~/lib/services/medipost.service';
import type { ICode } from '~/lib/types/code';
function toArray<T>(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[] = [];
const analysesToCreate: { analysisGroupId: number, analyses: IUuringElement[], analysisElementId: number }[] = [];
for (const analysisGroup of analysisGroups) {
let analysisGroupId: number | undefined;
const existingAnalysisGroup = existingAnalysisGroups?.find(({ original_id }) => original_id === analysisGroup.UuringuGruppId);
if (existingAnalysisGroup) {
console.info(`Analysis group '${analysisGroup.UuringuGruppNimi}' already exists`);
analysisGroupId = existingAnalysisGroup.id;
} else {
// SAVE ANALYSIS GROUP
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;
let insertedAnalysisElementId: number | undefined;
const existingAnalysisElement = (await getAnalysisElements({ originalIds: [analysisElement.UuringId] }))?.[0];
if (existingAnalysisElement) {
console.info(`Analysis element '${analysisElement.UuringNimi}' already exists`);
insertedAnalysisElementId = existingAnalysisElement.id;
} else {
insertedAnalysisElementId = await createAnalysisElement({
analysisElement,
analysisGroupId: 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 = toArray(analysisElement.UuringuElement);
if (analyses?.length && insertedAnalysisElementId) {
analysesToCreate.push({ analysisGroupId: analysisGroupId!, analyses, analysisElementId: insertedAnalysisElementId });
}
}
}
for (const { analysisGroupId, analyses, analysisElementId } of analysesToCreate) {
for (const analysis of analyses) {
const insertedAnalysisId = await createAnalysis(analysis, analysisElementId);
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}`,
);
}
}