267 lines
7.8 KiB
TypeScript
267 lines
7.8 KiB
TypeScript
import axios from 'axios';
|
|
|
|
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
|
|
|
import { logSyncResult } from '~/lib/services/audit.service';
|
|
import { SyncStatus } from '~/lib/types/audit';
|
|
import type {
|
|
ISearchLoadResponse,
|
|
P_JobTitleTranslation,
|
|
} from '~/lib/types/connected-online';
|
|
|
|
function createTranslationMap(translations: P_JobTitleTranslation[]) {
|
|
const result: Map<
|
|
number,
|
|
Map<number, { textEN: string; textRU: string; textET: string }>
|
|
> = new Map();
|
|
|
|
for (const translation of translations) {
|
|
const { ClinicID, TextET, TextEN, TextRU, SyncID } = translation;
|
|
|
|
if (!result.has(ClinicID)) {
|
|
result.set(ClinicID, new Map());
|
|
}
|
|
|
|
result.get(ClinicID)!.set(SyncID, {
|
|
textET: TextET,
|
|
textEN: TextEN,
|
|
textRU: TextRU,
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function getSpokenLanguages(spokenLanguages?: string) {
|
|
if (!spokenLanguages || !spokenLanguages.length) return [];
|
|
return spokenLanguages.split(',');
|
|
}
|
|
|
|
export default async function syncConnectedOnline() {
|
|
const isProd = !['test', 'localhost'].some((pathString) =>
|
|
process.env.NEXT_PUBLIC_SITE_URL?.includes(pathString),
|
|
);
|
|
|
|
const baseUrl = process.env.CONNECTED_ONLINE_URL;
|
|
|
|
if (!baseUrl) {
|
|
throw new Error('Could not access all necessary environment variables');
|
|
}
|
|
|
|
const supabase = getSupabaseServerAdminClient();
|
|
|
|
try {
|
|
const searchLoadResponse = await axios.post<{ d: string }>(
|
|
`${baseUrl}/Search_Load`,
|
|
{
|
|
headers: {
|
|
'Content-Type': 'application/json; charset=utf-8',
|
|
},
|
|
param: "{'Value':'|et|-1'}", // get all available services in Estonian
|
|
},
|
|
);
|
|
|
|
const responseData: ISearchLoadResponse = JSON.parse(
|
|
searchLoadResponse.data.d,
|
|
);
|
|
|
|
if (responseData?.ErrorCode !== 0) {
|
|
throw new Error('Failed to get Connected Online data');
|
|
}
|
|
|
|
if (
|
|
!responseData.Data.T_Lic?.length ||
|
|
!responseData.Data.T_Service?.length
|
|
) {
|
|
return supabase.schema('audit').from('sync_entries').insert({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
comment: 'No clinic or service data received',
|
|
status: 'FAIL',
|
|
changed_by_role: 'service_role',
|
|
});
|
|
}
|
|
|
|
// Filter out "Dentas Demo OÜ" in prod or only sync "Dentas Demo OÜ" in any other environment
|
|
const isDemoClinic = (clinicId: number) =>
|
|
isProd ? clinicId !== 2 : clinicId === 2;
|
|
const clinics = responseData.Data.T_Lic.filter(({ ID }) =>
|
|
isDemoClinic(ID),
|
|
);
|
|
const services = responseData.Data.T_Service.filter(({ ClinicID }) =>
|
|
isDemoClinic(ClinicID),
|
|
);
|
|
const serviceProviders = responseData.Data.T_Doctor.filter(({ ClinicID }) =>
|
|
isDemoClinic(ClinicID),
|
|
);
|
|
const jobTitleTranslations = createTranslationMap(
|
|
responseData.Data.P_JobTitleTranslations.filter(({ ClinicID }) =>
|
|
isDemoClinic(ClinicID),
|
|
),
|
|
);
|
|
|
|
const mappedClinics = clinics.map((clinic) => {
|
|
return {
|
|
id: clinic.ID,
|
|
can_select_worker: !!clinic.OnlineCanSelectWorker,
|
|
email: clinic.Email || null,
|
|
name: clinic.Name,
|
|
personal_code_required: !!clinic.PersonalCodeRequired,
|
|
phone_number: clinic.Phone || null,
|
|
key: clinic.Key,
|
|
address: clinic.Address,
|
|
};
|
|
});
|
|
|
|
const mappedServices = services.map((service) => {
|
|
return {
|
|
id: service.ID,
|
|
clinic_id: service.ClinicID,
|
|
sync_id: Number(service.SyncID),
|
|
name: service.Name,
|
|
description: service.Description || null,
|
|
price: service.Price,
|
|
requires_payment: !!service.RequiresPayment,
|
|
duration: service.Duration,
|
|
neto_duration: service.NetoDuration,
|
|
display: service.Display,
|
|
price_periods: service.PricePeriods || null,
|
|
online_hide_duration: service.OnlineHideDuration,
|
|
online_hide_price: service.OnlineHidePrice,
|
|
code: service.Code,
|
|
has_free_codes: !!service.HasFreeCodes,
|
|
};
|
|
});
|
|
|
|
const mappedServiceProviders = serviceProviders.map((serviceProvider) => {
|
|
const jobTitleTranslation = serviceProvider.JobTitleID
|
|
? jobTitleTranslations
|
|
.get(serviceProvider.ClinicID)
|
|
?.get(serviceProvider.JobTitleID)
|
|
: null;
|
|
return {
|
|
id: serviceProvider.ID,
|
|
prefix: serviceProvider.Prefix,
|
|
name: serviceProvider.Name,
|
|
spoken_languages: getSpokenLanguages(serviceProvider.SpokenLanguages),
|
|
job_title_et: jobTitleTranslation?.textET,
|
|
job_title_en: jobTitleTranslation?.textEN,
|
|
job_title_ru: jobTitleTranslation?.textRU,
|
|
job_title_id: serviceProvider.JobTitleID,
|
|
is_deleted: !!serviceProvider.Deleted,
|
|
clinic_id: serviceProvider.ClinicID,
|
|
};
|
|
});
|
|
|
|
const { error: providersError } = await supabase
|
|
.schema('medreport')
|
|
.from('connected_online_providers')
|
|
.upsert(mappedClinics);
|
|
|
|
if (providersError) {
|
|
return logSyncResult({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
comment:
|
|
'Error saving connected online providers: ' +
|
|
JSON.stringify(providersError),
|
|
status: SyncStatus.Fail,
|
|
changed_by_role: 'service_role',
|
|
});
|
|
}
|
|
|
|
const { error: servicesError } = await supabase
|
|
.schema('medreport')
|
|
.from('connected_online_services')
|
|
.upsert(mappedServices, {
|
|
onConflict: 'id',
|
|
ignoreDuplicates: false,
|
|
});
|
|
|
|
if (servicesError) {
|
|
return logSyncResult({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
comment:
|
|
'Error saving connected online services: ' +
|
|
JSON.stringify(servicesError),
|
|
status: SyncStatus.Fail,
|
|
changed_by_role: 'service_role',
|
|
});
|
|
}
|
|
|
|
const { error: serviceProvidersError } = await supabase
|
|
.schema('medreport')
|
|
.from('connected_online_service_providers')
|
|
.upsert(mappedServiceProviders, {
|
|
onConflict: 'id',
|
|
ignoreDuplicates: false,
|
|
});
|
|
|
|
if (serviceProvidersError) {
|
|
return logSyncResult({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
comment:
|
|
'Error saving service providers: ' +
|
|
JSON.stringify(serviceProvidersError),
|
|
status: SyncStatus.Fail,
|
|
changed_by_role: 'service_role',
|
|
});
|
|
}
|
|
|
|
for (const mappedClinic of mappedClinics) {
|
|
const defaultLoadResponse = await axios.post<{ d: string }>(
|
|
`${baseUrl}/Default_Load`,
|
|
{
|
|
headers: {
|
|
'Content-Type': 'application/json; charset=utf-8',
|
|
},
|
|
param: `{'Value':'${mappedClinic.key}|et'}`,
|
|
},
|
|
);
|
|
|
|
const defaultLoadResponseData = JSON.parse(defaultLoadResponse.data.d);
|
|
|
|
if (defaultLoadResponseData?.ErrorCode !== 0) {
|
|
throw new Error('Failed to get Connected Online location data');
|
|
}
|
|
|
|
const clinicLocations: {
|
|
SyncID: number;
|
|
Address: string;
|
|
Name: string;
|
|
}[] = defaultLoadResponseData.Data.T_SelectableLocation;
|
|
|
|
if (clinicLocations?.length) {
|
|
const mappedLocations = clinicLocations.map(
|
|
({ SyncID, Address, Name }) => ({
|
|
address: Address,
|
|
clinic_id: mappedClinic.id,
|
|
sync_id: SyncID,
|
|
name: Name,
|
|
}),
|
|
);
|
|
|
|
await supabase
|
|
.schema('medreport')
|
|
.from('connected_online_locations')
|
|
.insert(mappedLocations)
|
|
.throwOnError();
|
|
}
|
|
}
|
|
|
|
await logSyncResult({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
status: SyncStatus.Success,
|
|
changed_by_role: 'service_role',
|
|
});
|
|
} catch (e) {
|
|
await logSyncResult({
|
|
operation: 'CONNECTED_ONLINE_SYNC',
|
|
status: SyncStatus.Fail,
|
|
comment: JSON.stringify(e),
|
|
changed_by_role: 'service_role',
|
|
});
|
|
throw new Error(
|
|
`Failed to sync Connected Online data, error: ${JSON.stringify(e)}`,
|
|
);
|
|
}
|
|
}
|