Merge branch 'develop' of https://github.com/MR-medreport/MRB2B into MED-103

This commit is contained in:
Helena
2025-09-08 09:36:46 +03:00
106 changed files with 4793 additions and 4083 deletions

View File

@@ -41,6 +41,7 @@ export const defaultI18nNamespaces = [
'orders',
'analysis-results',
'doctor',
'error',
];
/**

View File

@@ -1,8 +1,14 @@
import type { Tables } from '@/packages/supabase/src/database.types';
import { AccountWithParams } from '@kit/accounts/api';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { AccountSettings } from '~/home/(user)/settings/_lib/account-settings.schema';
import { AccountPreferences } from '../../app/home/(user)/settings/_lib/account-preferences.schema';
import { updateCustomer } from '../../packages/features/medusa-storefront/src/lib/data';
type Account = Tables<{ schema: 'medreport' }, 'accounts'>;
type Membership = Tables<{ schema: 'medreport' }, 'accounts_memberships'>;
@@ -61,7 +67,9 @@ export async function getDoctorAccounts() {
}
export async function getAssignedDoctorAccount(analysisOrderId: number) {
const { data: doctorUser } = await getSupabaseServerAdminClient()
const supabase = getSupabaseServerAdminClient();
const { data: doctorUser } = await supabase
.schema('medreport')
.from('doctor_analysis_feedback')
.select('doctor_user_id')
@@ -73,7 +81,7 @@ export async function getAssignedDoctorAccount(analysisOrderId: number) {
return null;
}
const { data } = await getSupabaseServerAdminClient()
const { data } = await supabase
.schema('medreport')
.from('accounts')
.select('email')
@@ -81,3 +89,58 @@ export async function getAssignedDoctorAccount(analysisOrderId: number) {
return { email: data?.[0]?.email };
}
export async function updatePersonalAccount(
accountId: string,
account: AccountSettings,
) {
const supabase = getSupabaseServerClient();
return Promise.all([
supabase
.schema('medreport')
.from('accounts')
.update({
name: account.firstName,
last_name: account.lastName,
email: account.email,
phone: account.phone,
})
.eq('id', accountId)
.throwOnError(),
supabase
.schema('medreport')
.from('account_params')
.upsert(
{
height: account.accountParams.height,
weight: account.accountParams.weight,
is_smoker: account.accountParams.isSmoker,
},
{ onConflict: 'account_id' },
)
.throwOnError(),
updateCustomer({
first_name: account.firstName,
last_name: account.lastName,
phone: account.phone,
}),
]);
}
export async function updatePersonalAccountPreferences(
accountId: string,
preferences: AccountPreferences,
) {
const supabase = getSupabaseServerClient();
return supabase
.schema('medreport')
.from('accounts')
.update({
preferred_locale: preferences.preferredLanguage,
has_consent_anonymized_company_statistics:
preferences.isConsentToAnonymizedCompanyStatistics,
})
.eq('id', accountId)
.throwOnError();
}

View File

@@ -105,12 +105,18 @@ export const createMedusaSyncSuccessEntry = async () => {
});
}
export async function getAnalyses({ ids }: { ids: number[] }): Promise<AnalysesWithGroupsAndElements> {
const { data } = await getSupabaseServerAdminClient()
export async function getAnalyses({ ids, originalIds }: { ids?: number[], originalIds?: string[] }): Promise<AnalysesWithGroupsAndElements> {
const query = getSupabaseServerAdminClient()
.schema('medreport')
.from('analyses')
.select(`*, analysis_elements(*, analysis_groups(*))`)
.in('id', ids);
.select(`*, analysis_elements(*, analysis_groups(*))`);
if (Array.isArray(ids)) {
query.in('id', ids);
}
if (Array.isArray(originalIds)) {
query.in('analysis_id_original', originalIds);
}
const { data } = await query.throwOnError();
return data as unknown as AnalysesWithGroupsAndElements;
}

View File

@@ -10,6 +10,7 @@ import {
getClientInstitution,
getClientPerson,
getConfidentiality,
getOrderEnteredPerson,
getPais,
getPatient,
getProviderInstitution,
@@ -97,7 +98,7 @@ export async function getLatestPublicMessageListItem() {
Action: MedipostAction.GetPublicMessageList,
User: USER,
Password: PASSWORD,
Sender: 'syndev',
Sender: RECIPIENT,
// LastChecked (date+time) can be used here to get only messages since the last check - add when cron is created
// MessageType check only for messages of certain type
},
@@ -553,14 +554,12 @@ export async function composeOrderXML({
${getPais(USER, RECIPIENT, orderCreatedAt, orderId)}
<Tellimus cito="EI">
<ValisTellimuseId>${orderId}</ValisTellimuseId>
<!--<TellijaAsutus>-->
${getClientInstitution()}
<!--<TeostajaAsutus>-->
${getProviderInstitution()}
<!--<TellijaIsik>-->
${getClientPerson(person)}
${getClientPerson()}
${getOrderEnteredPerson()}
<TellijaMarkused>${comment ?? ''}</TellijaMarkused>
${getPatient(person)}
${getPatient(person)}
${getConfidentiality()}
${specimenSection.join('')}
${analysisSection?.join('')}
@@ -666,7 +665,7 @@ async function syncPrivateMessage({
unit: element.Mootyhik ?? null,
original_response_element: element,
analysis_name: element.UuringNimi || element.KNimetus,
comment: element.UuringuKommentaar
comment: element.UuringuKommentaar ?? '',
})),
);
}
@@ -715,7 +714,7 @@ export async function sendOrderToMedipost({
orderedAnalysisElements,
}: {
medusaOrderId: string;
orderedAnalysisElements: { analysisElementId: number }[];
orderedAnalysisElements: { analysisElementId?: number; analysisId?: number }[];
}) {
const medreportOrder = await getOrder({ medusaOrderId });
const account = await getAccountAdmin({ primaryOwnerUserId: medreportOrder.user_id });
@@ -727,8 +726,8 @@ export async function sendOrderToMedipost({
lastName: account.last_name ?? '',
phone: account.phone ?? '',
},
orderedAnalysisElementsIds: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId),
orderedAnalysesIds: [],
orderedAnalysisElementsIds: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId).filter(Boolean) as number[],
orderedAnalysesIds: orderedAnalysisElements.map(({ analysisId }) => analysisId).filter(Boolean) as number[],
orderId: medusaOrderId,
orderCreatedAt: new Date(medreportOrder.created_at),
comment: '',
@@ -784,12 +783,13 @@ export async function sendOrderToMedipost({
await updateOrderStatus({ medusaOrderId, orderStatus: 'PROCESSING' });
}
export async function getOrderedAnalysisElementsIds({
export async function getOrderedAnalysisIds({
medusaOrder,
}: {
medusaOrder: StoreOrder;
}): Promise<{
analysisElementId: number;
analysisElementId?: number;
analysisId?: number;
}[]> {
const countryCodes = await listRegions();
const countryCode = countryCodes[0]!.countries![0]!.iso_2!;
@@ -802,6 +802,14 @@ export async function getOrderedAnalysisElementsIds({
return analysisElements.map(({ id }) => ({ analysisElementId: id }));
}
async function getOrderedAnalyses(medusaOrder: StoreOrder) {
const originalIds = (medusaOrder?.items ?? [])
.map((a) => a.product?.metadata?.analysisIdOriginal)
.filter((a) => typeof a === 'string') as string[];
const analyses = await getAnalyses({ originalIds });
return analyses.map(({ id }) => ({ analysisId: id }));
}
async function getOrderedAnalysisPackages(medusaOrder: StoreOrder) {
const orderedPackages = (medusaOrder?.items ?? []).filter(({ product }) => product?.handle.startsWith(ANALYSIS_PACKAGE_HANDLE_PREFIX));
const orderedPackageIds = orderedPackages.map(({ product }) => product?.id).filter(Boolean) as string[];
@@ -841,12 +849,13 @@ export async function getOrderedAnalysisElementsIds({
return analysisElements.map(({ id }) => ({ analysisElementId: id }));
}
const [analysisPackageElements, orderedAnalysisElements] = await Promise.all([
const [analysisPackageElements, orderedAnalysisElements, orderedAnalyses] = await Promise.all([
getOrderedAnalysisPackages(medusaOrder),
getOrderedAnalysisElements(medusaOrder),
getOrderedAnalyses(medusaOrder),
]);
return [...analysisPackageElements, ...orderedAnalysisElements];
return [...analysisPackageElements, ...orderedAnalysisElements, ...orderedAnalyses];
}
export async function createMedipostActionLog({

View File

@@ -3,6 +3,7 @@
import {
getClientInstitution,
getClientPerson,
getOrderEnteredPerson,
getPais,
getPatient,
getProviderInstitution,
@@ -104,7 +105,8 @@ export async function composeOrderTestResponseXML({
<ValisTellimuseId>${orderId}</ValisTellimuseId>
${getClientInstitution({ index: 1 })}
${getProviderInstitution({ index: 1 })}
${getClientPerson(person)}
${getClientPerson()}
${getOrderEnteredPerson()}
<TellijaMarkused>Siia tuleb tellija poolne märkus</TellijaMarkused>
${getPatient(person)}

View File

@@ -16,12 +16,12 @@ const env = () =>
.object({
medusaBackendPublicUrl: z
.string({
required_error: 'MEDUSA_BACKEND_PUBLIC_URL is required',
error: 'MEDUSA_BACKEND_PUBLIC_URL is required',
})
.min(1),
siteUrl: z
.string({
required_error: 'NEXT_PUBLIC_SITE_URL is required',
error: 'NEXT_PUBLIC_SITE_URL is required',
})
.min(1),
})

View File

@@ -10,7 +10,7 @@ export async function createOrder({
orderedAnalysisElements,
}: {
medusaOrder: StoreOrder;
orderedAnalysisElements: { analysisElementId: number }[];
orderedAnalysisElements: { analysisElementId?: number; analysisId?: number }[];
}) {
const supabase = getSupabaseServerClient();
@@ -21,8 +21,8 @@ export async function createOrder({
const orderResult = await supabase.schema('medreport')
.from('analysis_orders')
.insert({
analysis_element_ids: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId),
analysis_ids: [],
analysis_element_ids: orderedAnalysisElements.map(({ analysisElementId }) => analysisElementId).filter(Boolean) as number[],
analysis_ids: orderedAnalysisElements.map(({ analysisId }) => analysisId).filter(Boolean) as number[],
status: 'QUEUED',
user_id: user.id,
medusa_order_id: medusaOrder.id,

View File

@@ -21,70 +21,48 @@ export const getPais = (
<Saaja>${recipient}</Saaja>
<Aeg>${format(createdAt, DATE_TIME_FORMAT)}</Aeg>
<SaadetisId>${orderId}</SaadetisId>
<Email>argo@medreport.ee</Email>
<Email>info@medreport.ee</Email>
</Pais>`;
};
export const getClientInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
return `<Asutus tyyp="TELLIJA" ${index ? ` jarjenumber="${index}"` : ''}>
<AsutuseId>16381793</AsutuseId>
<AsutuseNimi>MedReport OÜ</AsutuseNimi>
<AsutuseKood>TSU</AsutuseKood>
<AsutuseKood>MRP</AsutuseKood>
<Telefon>+37258871517</Telefon>
</Asutus>`;
};
export const getProviderInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
return `<Asutus tyyp="TEOSTAJA" ${index ? ` jarjenumber="${index}"` : ''}>
<AsutuseId>11107913</AsutuseId>
<AsutuseNimi>Synlab HTI Tallinn</AsutuseNimi>
<AsutuseKood>SLA</AsutuseKood>
<AsutuseNimi>Synlab Eesti OÜ</AsutuseNimi>
<AsutuseKood>HTI</AsutuseKood>
<AllyksuseNimi>Synlab HTI Tallinn</AllyksuseNimi>
<Telefon>+3723417123</Telefon>
<Telefon>+37217123</Telefon>
</Asutus>`;
};
export const getClientPerson = ({
idCode,
firstName,
lastName,
phone,
}: {
idCode: string,
firstName: string,
lastName: string,
phone: string,
}) => {
if (isProd) {
// return correct data
}
export const getClientPerson = () => {
return `<Personal tyyp="TELLIJA" jarjenumber="1">
<PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID>
<PersonalKood>${idCode}</PersonalKood>
<PersonalPerekonnaNimi>${lastName}</PersonalPerekonnaNimi>
<PersonalEesNimi>${firstName}</PersonalEesNimi>
${phone ? `<Telefon>${phone.startsWith('+372') ? phone : `+372${phone}`}</Telefon>` : ''}
<PersonalKood>D07907</PersonalKood>
<PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi>
<PersonalEesNimi>Tsvetkov</PersonalEesNimi>
<Telefon>+37258131202</Telefon>
</Personal>`;
};
// export const getOrderEnteredPerson = () => {
// if (isProd) {
// // return correct data
// }
// return `<Personal tyyp="SISESTAJA" jarjenumber="1">
// <PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID>
// <PersonalKood>D07907</PersonalKood>
// <PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi>
// <PersonalEesNimi>Tsvetkov</PersonalEesNimi>
// <Telefon>+37258131202</Telefon>
// </Personal>`;
// };
export const getOrderEnteredPerson = () => {
return `<Personal tyyp="SISESTAJA" jarjenumber="2">
<PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID>
<PersonalKood>D07907</PersonalKood>
<PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi>
<PersonalEesNimi>Tsvetkov</PersonalEesNimi>
<Telefon>+37258131202</Telefon>
</Personal>`;
};
export const getPatient = ({
idCode,

View File

@@ -2,15 +2,14 @@ import { z } from 'zod';
export const companyOfferSchema = z.object({
companyName: z.string({
required_error: 'Company name is required',
error: 'Company name is required',
}),
contactPerson: z.string({
required_error: 'Contact person is required',
error: 'Contact person is required',
}),
email: z
.string({
required_error: 'Email is required',
})
.email('Invalid email'),
.email({
error: 'Invalid email',
}),
phone: z.string().optional(),
});