diff --git a/app/api/job/handler/sync-analysis-groups-store.ts b/app/api/job/handler/sync-analysis-groups-store.ts
index 151d72e..ccf9c0a 100644
--- a/app/api/job/handler/sync-analysis-groups-store.ts
+++ b/app/api/job/handler/sync-analysis-groups-store.ts
@@ -30,8 +30,8 @@ async function createProductCategories({
}: {
medusa: Medusa;
}) {
- const existingProductCategories = await medusa.admin.productCategory.list();
- const parentCategory = existingProductCategories.product_categories.find(({ handle }) => handle === SYNLAB_SERVICES_CATEGORY_HANDLE);
+ const { product_categories: existingProductCategories } = await medusa.admin.productCategory.list();
+ const parentCategory = existingProductCategories.find(({ handle }) => handle === SYNLAB_SERVICES_CATEGORY_HANDLE);
if (!parentCategory) {
throw new Error('Parent category not found');
@@ -46,7 +46,7 @@ async function createProductCategories({
for (const analysisGroup of analysisGroups) {
console.info(`Processing analysis group '${analysisGroup.name}'`);
- const isExisting = existingProductCategories.product_categories.find(({ name }) => name === analysisGroup.name);
+ const isExisting = existingProductCategories.find(({ name }) => name === analysisGroup.name);
const isNewlyCreated = createdCategories.find(({ name }) => name === analysisGroup.name);
if (isExisting || isNewlyCreated) {
console.info(`Analysis group '${analysisGroup.name}' already exists`);
@@ -68,6 +68,28 @@ async function createProductCategories({
}
}
+async function getChildProductCategories({
+ medusa,
+}: {
+ medusa: Medusa;
+}) {
+ const { product_categories: allCategories } = await medusa.admin.productCategory.list();
+ const childCategories = allCategories.filter(({ parent_category_id }) => parent_category_id !== null);
+ return childCategories;
+}
+
+async function deleteProductCategories({
+ medusa,
+ categories,
+}: {
+ medusa: Medusa;
+ categories: AdminProductCategory[];
+}) {
+ for (const category of categories) {
+ await medusa.admin.productCategory.delete(category.id);
+ }
+}
+
/**
* In case a reset is needed
*/
@@ -76,14 +98,12 @@ async function deleteProducts({
}: {
medusa: Medusa;
}) {
- const { product_categories: allCategories } = await medusa.admin.productCategory.list();
const { products: existingProducts } = await medusa.admin.product.list({
- category_id: allCategories.map(({ id }) => id),
+ fields: 'id,collection_id',
+ limit: 1000,
});
- for (const product of existingProducts) {
- await medusa.admin.product.delete(product.id);
- }
+ await Promise.all(existingProducts.filter((a) => !a.collection_id).map(({ id }) => medusa.admin.product.delete(id)));
}
async function getAnalysisPackagesType() {
@@ -145,7 +165,7 @@ async function createProducts({
medusa.admin.product.list({
category_id: allCategories.map(({ id }) => id),
}),
- getAnalysisElements(),
+ getAnalysisElements({}),
getAnalysisPackagesType(),
getProductDefaultFields({ medusa }),
])
@@ -169,7 +189,7 @@ async function createProducts({
continue;
}
- const createResponse = await medusa.admin.product.create({
+ await medusa.admin.product.create({
title: name,
handle: `analysis-element-${analysisElement.id}`,
categories: [{ id: category.id }],
@@ -194,7 +214,6 @@ async function createProducts({
],
type_id: analysisPackagesType.id,
});
- console.info(`Successfully created product, id=${createResponse.product.id}`);
}
}
@@ -204,6 +223,8 @@ export default async function syncAnalysisGroupsStore() {
try {
await createProductCategories({ medusa });
+ // const categories = await getChildProductCategories({ medusa });
+ // await deleteProductCategories({ medusa, categories });
// await deleteProducts({ medusa });
// return;
diff --git a/app/api/order/medipost-test-response/route.ts b/app/api/order/medipost-test-response/route.ts
new file mode 100644
index 0000000..b6bf84d
--- /dev/null
+++ b/app/api/order/medipost-test-response/route.ts
@@ -0,0 +1,52 @@
+import { NextResponse } from "next/server";
+import { getOrder } from "~/lib/services/order.service";
+import { composeOrderTestResponseXML, sendPrivateMessageTestResponse } from "~/lib/services/medipostTest.service";
+import { retrieveOrder } from "@lib/data";
+import { getAccountAdmin } from "~/lib/services/account.service";
+
+export async function POST(request: Request) {
+ const isDev = process.env.NODE_ENV === 'development';
+ if (!isDev) {
+ return NextResponse.json({ error: 'This endpoint is only available in development mode' }, { status: 403 });
+ }
+
+ const { medusaOrderId } = await request.json();
+
+ const medusaOrder = await retrieveOrder(medusaOrderId)
+ const medreportOrder = await getOrder({ medusaOrderId });
+
+ const account = await getAccountAdmin({ primaryOwnerUserId: medreportOrder.user_id });
+
+ const ANALYSIS_ELEMENT_HANDLE_PREFIX = 'analysis-element-';
+ const orderedAnalysisElementsIds = (medusaOrder?.items ?? [])
+ .filter((item) => item.product?.handle?.startsWith(ANALYSIS_ELEMENT_HANDLE_PREFIX))
+ .map((item) => {
+ const id = Number(item.product?.handle?.replace(ANALYSIS_ELEMENT_HANDLE_PREFIX, ''));
+ if (Number.isNaN(id)) {
+ return null;
+ }
+ return id;
+ })
+ .filter(Boolean) as number[];
+
+ const messageXml = await composeOrderTestResponseXML({
+ person: {
+ idCode: account.personal_code!,
+ firstName: account.name ?? '',
+ lastName: account.last_name ?? '',
+ phone: account.phone ?? '',
+ },
+ orderedAnalysisElementsIds,
+ orderedAnalysesIds: [],
+ orderId: medusaOrderId,
+ orderCreatedAt: new Date(medreportOrder.created_at),
+ });
+
+ try {
+ await sendPrivateMessageTestResponse({ messageXml });
+ } catch (error) {
+ console.error("Error sending private message test response: ", error);
+ }
+
+ return NextResponse.json({ success: true });
+}
diff --git a/lib/services/medipostTest.service.ts b/lib/services/medipostTest.service.ts
new file mode 100644
index 0000000..ad2ad39
--- /dev/null
+++ b/lib/services/medipostTest.service.ts
@@ -0,0 +1,177 @@
+'use server';
+
+import {
+ getClientInstitution,
+ getClientPerson,
+ getPais,
+ getPatient,
+ getProviderInstitution,
+} from '@/lib/templates/medipost-order';
+import {
+ MedipostAction,
+} from '@/lib/types/medipost';
+import axios from 'axios';
+import { uniqBy } from 'lodash';
+
+import { Tables } from '@kit/supabase/database';
+import { formatDate } from 'date-fns';
+import { getAnalyses } from './analyses.service';
+import { getAnalysisElements } from './analysis-element.service';
+import { validateMedipostResponse } from './medipost.service';
+
+const BASE_URL = process.env.MEDIPOST_URL!;
+const USER = process.env.MEDIPOST_USER!;
+const PASSWORD = process.env.MEDIPOST_PASSWORD!;
+const RECIPIENT = process.env.MEDIPOST_RECIPIENT!;
+
+export async function sendPrivateMessageTestResponse({
+ messageXml,
+}: {
+ messageXml: string;
+}) {
+ const body = new FormData();
+ body.append('Action', MedipostAction.SendPrivateMessage);
+ body.append('User', USER);
+ body.append('Password', PASSWORD);
+ body.append('Receiver', RECIPIENT);
+ body.append('MessageType', 'Vastus');
+ body.append(
+ 'Message',
+ new Blob([messageXml], {
+ type: 'text/xml; charset=UTF-8',
+ }),
+ );
+
+ const { data } = await axios.post(BASE_URL, body);
+ await validateMedipostResponse(data);
+}
+
+function getRandomInt(min: number, max: number) {
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+export async function composeOrderTestResponseXML({
+ person,
+ orderedAnalysisElementsIds,
+ orderedAnalysesIds,
+ orderId,
+ orderCreatedAt,
+}: {
+ person: {
+ idCode: string;
+ firstName: string;
+ lastName: string;
+ phone: string;
+ };
+ orderedAnalysisElementsIds: number[];
+ orderedAnalysesIds: number[];
+ orderId: string;
+ orderCreatedAt: Date;
+}) {
+ const analysisElements = await getAnalysisElements({ ids: orderedAnalysisElementsIds });
+ const analyses = await getAnalyses({ ids: orderedAnalysesIds });
+
+ const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =
+ uniqBy(
+ (
+ analysisElements?.flatMap(({ analysis_groups }) => analysis_groups) ??
+ []
+ ).concat(
+ analyses?.flatMap(
+ ({ analysis_elements }) => analysis_elements.analysis_groups,
+ ) ?? [],
+ ),
+ 'id',
+ );
+
+ // Tellimuse olek:
+ // 1 – Järjekorras, 2 – Ootel, 3 - Töös, 4 – Lõpetatud,
+ // 5 – Tagasi lükatud, 6 – Tühistatud.
+ const orderStatus = 4;
+ const orderNumber = 'TSU000001200';
+ return `
+
+ ${getPais(USER, RECIPIENT, orderCreatedAt, orderId, "AL")}
+
+ ${orderId}
+ ${getClientInstitution({ index: 1 })}
+ ${getProviderInstitution({ index: 1 })}
+ ${getClientPerson(person)}
+ Siia tuleb tellija poolne märkus
+
+ ${getPatient(person)}
+
+
+ 1.3.6.1.4.1.28284.1.625.2.17
+ 16522314
+ 1.3.6.1.4.1.28284.6.2.1.244.8
+ 119297000
+ Veri
+ 16522314
+ 1
+ 2022-08-19 08:53:00
+ 2022-08-23 15:10:00
+
+
+ ${orderNumber}
+
+ ${orderStatus}
+ ${analysisGroups.map((group) => {
+ let relatedAnalysisElement = analysisElements?.find(
+ (element) => element.analysis_groups.id === group.id,
+ );
+ const relatedAnalyses = analyses?.filter((analysis) => {
+ return analysis.analysis_elements.analysis_groups.id === group.id;
+ });
+
+ 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})`,
+ );
+ }
+
+ const lower = getRandomInt(0, 100);
+ const upper = getRandomInt(lower + 1, 500);
+ const result = getRandomInt(lower, upper);
+ return (`
+
+ ${group.original_id}
+ ${group.name}
+
+
+ ${relatedAnalysisElement.analysis_id_oid}
+ ${relatedAnalysisElement.analysis_id_original}
+ ${relatedAnalysisElement.tehik_short_loinc}
+ ${relatedAnalysisElement.tehik_loinc_name}
+ ${relatedAnalysisElement.analysis_name_lab ?? relatedAnalysisElement.tehik_loinc_name}
+ ${relatedAnalysisElement.id}
+ ${relatedAnalysisElement.id}
+ 4
+ %
+
+ ${result}
+ ${formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss')}
+ ${upper}
+ ${lower}
+ 0
+ 1
+
+
+ 2
+
+
+ `);
+ }).join('')}
+
+`;
+}
diff --git a/lib/templates/medipost-order.ts b/lib/templates/medipost-order.ts
index d54b1f9..6568c22 100644
--- a/lib/templates/medipost-order.ts
+++ b/lib/templates/medipost-order.ts
@@ -1,5 +1,5 @@
import { format } from 'date-fns';
-import Isikukood from 'isikukood';
+import Isikukood, { Gender } from 'isikukood';
import { Tables } from '@/packages/supabase/src/database.types';
import { DATE_FORMAT, DATE_TIME_FORMAT } from '@/lib/constants';
@@ -9,26 +9,27 @@ export const getPais = (
sender: string,
recipient: string,
createdAt: Date,
- messageId: number,
+ orderId: string,
+ packageName = "OL",
) => {
if (isProd) {
// return correct data
}
return `
- OL
+ ${packageName}
${sender}
${recipient}
${format(createdAt, DATE_TIME_FORMAT)}
- ${messageId}
+ ${orderId}
argo@medreport.ee
`;
};
-export const getClientInstitution = () => {
+export const getClientInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
- return `
+ return `
16381793
MedReport OÜ
TSU
@@ -36,11 +37,11 @@ export const getClientInstitution = () => {
`;
};
-export const getProviderInstitution = () => {
+export const getProviderInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
- return `
+ return `
11107913
Synlab HTI Tallinn
SLA
@@ -68,7 +69,7 @@ export const getClientPerson = ({
${idCode}
${lastName}
${firstName}
- ${phone}
+ ${phone ? `${phone.startsWith('+372') ? phone : `+372${phone}`}` : ''}
`;
};