feat(MED-131): update analyses on package logic

This commit is contained in:
2025-08-04 11:55:23 +03:00
parent c02cb046a5
commit 7c3aa45ec7
9 changed files with 88 additions and 51 deletions

View File

@@ -1,7 +1,7 @@
import axios from 'axios'; import axios from 'axios';
import { XMLParser } from 'fast-xml-parser'; import { XMLParser } from 'fast-xml-parser';
import fs from 'fs'; import fs from 'fs';
import { createAnalysisGroup } from '~/lib/services/analysis-group.service'; import { createAnalysisGroup, getAnalysisGroups } from '~/lib/services/analysis-group.service';
import { IMedipostPublicMessageDataParsed } from '~/lib/services/medipost.types'; import { IMedipostPublicMessageDataParsed } from '~/lib/services/medipost.types';
import { createAnalysis, createNoDataReceivedEntry, createNoNewDataReceivedEntry, createSyncFailEntry, createSyncSuccessEntry } from '~/lib/services/analyses.service'; import { createAnalysis, createNoDataReceivedEntry, createNoNewDataReceivedEntry, createSyncFailEntry, createSyncSuccessEntry } from '~/lib/services/analyses.service';
import { getLastCheckedDate } from '~/lib/services/sync-entries.service'; import { getLastCheckedDate } from '~/lib/services/sync-entries.service';
@@ -64,6 +64,8 @@ export default async function syncAnalysisGroups() {
); );
} }
const existingAnalysisGroups = await getAnalysisGroups();
// SAVE PUBLIC MESSAGE DATA // SAVE PUBLIC MESSAGE DATA
const providers = toArray(parsed?.Saadetis?.Teenused.Teostaja); const providers = toArray(parsed?.Saadetis?.Teenused.Teostaja);
@@ -79,6 +81,12 @@ export default async function syncAnalysisGroups() {
const codes: ICode[] = []; const codes: ICode[] = [];
for (const analysisGroup of analysisGroups) { for (const analysisGroup of analysisGroups) {
const existingAnalysisGroup = existingAnalysisGroups?.find(({ original_id }) => original_id === analysisGroup.UuringuGruppId);
if (existingAnalysisGroup) {
console.info(`Analysis group '${analysisGroup.UuringuGruppNimi}' already exists`);
continue;
}
// SAVE ANALYSIS GROUP // SAVE ANALYSIS GROUP
const analysisGroupId = await createAnalysisGroup({ const analysisGroupId = await createAnalysisGroup({
id: analysisGroup.UuringuGruppId, id: analysisGroup.UuringuGruppId,

View File

@@ -24,7 +24,7 @@ import { PackageHeader } from '@/components/package-header';
import { InfoTooltip } from '@/components/ui/info-tooltip'; import { InfoTooltip } from '@/components/ui/info-tooltip';
import { StoreProduct } from '@medusajs/types'; import { StoreProduct } from '@medusajs/types';
import type { AnalysisElement } from '~/lib/services/analysis-element.service'; import type { AnalysisElement } from '~/lib/services/analysis-element.service';
import { getAnalysisElementOriginalIds } from '@lib/data/products'; import { getAnalysisElementOriginalIds } from '@/utils/medusa-product';
const CheckWithBackground = () => { const CheckWithBackground = () => {
return ( return (
@@ -34,6 +34,24 @@ const CheckWithBackground = () => {
); );
}; };
const PackageTableHead = async ({ product, nrOfAnalyses }: { product: StoreProduct, nrOfAnalyses: number }) => {
const { t, language } = await createI18nServerInstance();
const variant = product.variants?.[0];
const titleKey = product.title;
const price = variant?.calculated_price?.calculated_amount ?? 0;
return (
<TableHead className="py-2">
<PackageHeader
title={t(titleKey)}
tagColor='bg-cyan'
analysesNr={t('product:nrOfAnalyses', { nr: nrOfAnalyses })}
language={language}
price={price}
/>
</TableHead>
)
}
const ComparePackagesModal = async ({ const ComparePackagesModal = async ({
analysisElements, analysisElements,
analysisPackages, analysisPackages,
@@ -43,7 +61,7 @@ const ComparePackagesModal = async ({
analysisPackages: StoreProduct[]; analysisPackages: StoreProduct[];
triggerElement: JSX.Element; triggerElement: JSX.Element;
}) => { }) => {
const { t, language } = await createI18nServerInstance(); const { t } = await createI18nServerInstance();
const standardPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard')!; const standardPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard')!;
const standardPlusPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard-plus')!; const standardPlusPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard-plus')!;
@@ -53,9 +71,9 @@ const ComparePackagesModal = async ({
return null; return null;
} }
const standardPackageAnalyses = await getAnalysisElementOriginalIds([standardPackage]); const standardPackageAnalyses = getAnalysisElementOriginalIds([standardPackage]);
const standardPlusPackageAnalyses = await getAnalysisElementOriginalIds([standardPlusPackage]); const standardPlusPackageAnalyses = getAnalysisElementOriginalIds([standardPlusPackage]);
const premiumPackageAnalyses = await getAnalysisElementOriginalIds([premiumPackage]); const premiumPackageAnalyses = getAnalysisElementOriginalIds([premiumPackage]);
return ( return (
<Dialog> <Dialog>
@@ -86,25 +104,9 @@ const ComparePackagesModal = async ({
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead></TableHead> <TableHead></TableHead>
{analysisPackages.map( <PackageTableHead product={standardPackage} nrOfAnalyses={standardPackageAnalyses.length} />
(product) => { <PackageTableHead product={standardPlusPackage} nrOfAnalyses={standardPlusPackageAnalyses.length} />
const variant = product.variants?.[0]; <PackageTableHead product={premiumPackage} nrOfAnalyses={premiumPackageAnalyses.length} />
const titleKey = product.title;
const price = variant?.calculated_price?.calculated_amount ?? 0;
return (
<TableHead key={titleKey} className="py-2">
<PackageHeader
title={t(titleKey)}
tagColor='bg-cyan'
analysesNr={t('product:nrOfAnalyses', {
nr: product?.metadata?.nrOfAnalyses ?? 0,
})}
language={language}
price={price}
/>
</TableHead>
)
})}
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>

View File

@@ -1,8 +1,9 @@
import { cache } from 'react'; import { cache } from 'react';
import { getAnalysisElementOriginalIds, listProductTypes, listProducts } from "@lib/data/products"; import { listProductTypes, listProducts } from "@lib/data/products";
import { listRegions } from '@lib/data/regions'; import { listRegions } from '@lib/data/regions';
import { AnalysisElement, getAnalysisElements } from '~/lib/services/analysis-element.service'; import { AnalysisElement, getAnalysisElements } from '~/lib/services/analysis-element.service';
import { getAnalysisElementOriginalIds } from '@/utils/medusa-product';
async function countryCodesLoader() { async function countryCodesLoader() {
const countryCodes = await listRegions().then((regions) => const countryCodes = await listRegions().then((regions) =>
@@ -33,7 +34,7 @@ async function analysisPackagesLoader() {
}); });
const analysisPackages = response.products; const analysisPackages = response.products;
let analysisElements: AnalysisElement[] = []; let analysisElements: AnalysisElement[] = [];
const analysisElementOriginalIds = await getAnalysisElementOriginalIds(analysisPackages); const analysisElementOriginalIds = getAnalysisElementOriginalIds(analysisPackages);
if (analysisElementOriginalIds.length) { if (analysisElementOriginalIds.length) {
analysisElements = await getAnalysisElements({ originalIds: analysisElementOriginalIds }); analysisElements = await getAnalysisElements({ originalIds: analysisElementOriginalIds });

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState } from 'react'; import { use, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Image from 'next/image'; import Image from 'next/image';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
@@ -19,11 +19,11 @@ import { handleAddToCart } from '@/lib/services/medusaCart.service';
import { PackageHeader } from './package-header'; import { PackageHeader } from './package-header';
import { ButtonTooltip } from './ui/button-tooltip'; import { ButtonTooltip } from './ui/button-tooltip';
import { getAnalysisElementOriginalIds } from '@/utils/medusa-product';
export interface IAnalysisPackage { export interface IAnalysisPackage {
titleKey: string; titleKey: string;
price: number; price: number;
nrOfAnalyses: number | string;
tagColor: string; tagColor: string;
descriptionKey: string; descriptionKey: string;
} }
@@ -52,7 +52,8 @@ export default function SelectAnalysisPackage({
} }
const titleKey = analysisPackage.title; const titleKey = analysisPackage.title;
const nrOfAnalyses = analysisPackage?.metadata?.nrOfAnalyses ?? 0; const analysisElementOriginalIds = getAnalysisElementOriginalIds([analysisPackage]);
const nrOfAnalyses = analysisElementOriginalIds.length;
const description = analysisPackage.description ?? ''; const description = analysisPackage.description ?? '';
const subtitle = analysisPackage.subtitle ?? ''; const subtitle = analysisPackage.subtitle ?? '';
const variant = analysisPackage.variants?.[0]; const variant = analysisPackage.variants?.[0];

View File

@@ -9,10 +9,8 @@ export type AnalysisElement = Tables<{ schema: 'medreport' }, 'analysis_elements
export async function getAnalysisElements({ export async function getAnalysisElements({
originalIds, originalIds,
ids,
}: { }: {
originalIds?: string[]; originalIds?: string[];
ids?: number[];
}): Promise<AnalysisElement[]> { }): Promise<AnalysisElement[]> {
const query = getSupabaseServerClient() const query = getSupabaseServerClient()
.schema('medreport') .schema('medreport')
@@ -24,11 +22,35 @@ export async function getAnalysisElements({
query.in('analysis_id_original', [...new Set(originalIds)]); query.in('analysis_id_original', [...new Set(originalIds)]);
} }
const { data: analysisElements, error } = await query;
if (error) {
throw new Error(`Failed to get analysis elements: ${error.message}`);
}
return analysisElements ?? [];
}
export async function getAnalysisElementsAdmin({
ids,
}: {
ids?: number[];
} = {}): Promise<AnalysisElement[]> {
const query = getSupabaseServerAdminClient()
.schema('medreport')
.from('analysis_elements')
.select(`*, analysis_groups(*)`)
.order('order', { ascending: true });
if (Array.isArray(ids)) { if (Array.isArray(ids)) {
query.in('id', ids); query.in('id', ids);
} }
const { data: analysisElements } = await query; const { data: analysisElements, error } = await query;
if (error) {
throw new Error(`Failed to get analysis elements: ${error.message}`);
}
return analysisElements ?? []; return analysisElements ?? [];
} }

View File

@@ -37,7 +37,7 @@ import { Tables } from '@kit/supabase/database';
import { createAnalysisGroup } from './analysis-group.service'; import { createAnalysisGroup } from './analysis-group.service';
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client'; import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
import { getOrder } from './order.service'; import { getOrder } from './order.service';
import { getAnalysisElements } from './analysis-element.service'; import { getAnalysisElementsAdmin } from './analysis-element.service';
import { getAnalyses } from './analyses.service'; import { getAnalyses } from './analyses.service';
const BASE_URL = process.env.MEDIPOST_URL!; const BASE_URL = process.env.MEDIPOST_URL!;
@@ -407,7 +407,7 @@ export async function composeOrderXML({
orderCreatedAt: Date; orderCreatedAt: Date;
comment?: string; comment?: string;
}) { }) {
const analysisElements = await getAnalysisElements({ ids: orderedAnalysisElementsIds }); const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds });
const analyses = await getAnalyses({ ids: orderedAnalysesIds }); const analyses = await getAnalyses({ ids: orderedAnalysesIds });
const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] = const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =

View File

@@ -16,7 +16,7 @@ import { uniqBy } from 'lodash';
import { Tables } from '@kit/supabase/database'; import { Tables } from '@kit/supabase/database';
import { formatDate } from 'date-fns'; import { formatDate } from 'date-fns';
import { getAnalyses } from './analyses.service'; import { getAnalyses } from './analyses.service';
import { getAnalysisElements } from './analysis-element.service'; import { getAnalysisElementsAdmin } from './analysis-element.service';
import { validateMedipostResponse } from './medipost.service'; import { validateMedipostResponse } from './medipost.service';
const BASE_URL = process.env.MEDIPOST_URL!; const BASE_URL = process.env.MEDIPOST_URL!;
@@ -70,7 +70,7 @@ export async function composeOrderTestResponseXML({
orderId: string; orderId: string;
orderCreatedAt: Date; orderCreatedAt: Date;
}) { }) {
const analysisElements = await getAnalysisElements({ ids: orderedAnalysisElementsIds }); const analysisElements = await getAnalysisElementsAdmin({ ids: orderedAnalysisElementsIds });
const analyses = await getAnalyses({ ids: orderedAnalysesIds }); const analyses = await getAnalyses({ ids: orderedAnalysesIds });
const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] = const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] =

View File

@@ -85,20 +85,6 @@ export const listProducts = async ({
}) })
} }
export const getAnalysisElementOriginalIds = async (products: HttpTypes.StoreProduct[]) => {
return products
.flatMap(({ metadata }) => {
const value = metadata?.analysisElementOriginalIds;
try {
return JSON.parse(value as string);
} catch (e) {
console.error("Failed to parse analysisElementOriginalIds from analysis package, possibly invalid format", e);
return [];
}
})
.filter(Boolean) as string[];
}
/** /**
* This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter. * This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
* It will then return the paginated products based on the page and limit parameters. * It will then return the paginated products based on the page and limit parameters.

17
utils/medusa-product.ts Normal file
View File

@@ -0,0 +1,17 @@
export const getAnalysisElementOriginalIds = (products: ({ metadata?: { analysisElementOriginalIds?: string } | null } | null)[]) => {
if (!products) {
return [];
}
return products
.flatMap((product) => {
const value = product?.metadata?.analysisElementOriginalIds;
try {
return JSON.parse(value as string);
} catch (e) {
console.error("Failed to parse analysisElementOriginalIds from analysis package, possibly invalid format", e);
return [];
}
})
.filter(Boolean) as string[];
}