Files
medreport_mrb2b/lib/services/connected-online.service.ts
Helena 538a17031a B2B-52: add Connected Online syncing, tables and functions (#18)
* B2B-52: add Connected Online syncing, tables and functions

* clean up

* improve autogenerated types

* add use server directive

---------

Co-authored-by: Helena <helena@Helenas-MacBook-Pro.local>
2025-06-18 17:06:24 +03:00

269 lines
7.6 KiB
TypeScript

'use server'
import logRequestResult from '@/lib/services/audit.service';
import { RequestStatus } from '@/lib/types/audit';
import {
AvailableAppointmentsResponse,
BookTimeResponse,
ConfirmedLoadResponse,
ConnectedOnlineMethodName,
} from '@/lib/types/connected-online';
import { ExternalApi } from '@/lib/types/external';
import { Tables } from '@/supabase/database.types';
import { createClient } from '@/utils/supabase/server';
import axios from 'axios';
export async function getAvailableAppointmentsForService(
serviceId: number,
startTime?: Date,
) {
try {
const showTimesFrom = startTime ? { StartTime: startTime } : {};
const response = await axios.post(
`${process.env.CONNECTED_ONLINE_URL!}/${ConnectedOnlineMethodName.GetAvailabilities}`,
{
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
param: JSON.stringify({
ServiceID: serviceId,
Key: '7T624nlu',
Lang: 'et',
...showTimesFrom,
}),
},
);
const responseData: AvailableAppointmentsResponse = JSON.parse(
response.data.d,
);
if (
responseData?.ErrorCode !== 0 ||
!responseData.Data.T_Service?.length ||
!responseData.Data.T_Booking?.length
) {
let comment = `Response returned error code ${responseData.ErrorCode}, message: ${responseData.ErrorMessage}`;
if (responseData?.ErrorCode === 0) {
comment = responseData.Data.T_Service?.length
? `No service present in appointment availability response, service id: ${serviceId}, start time: ${startTime}`
: `No booking times present in appointment availability response, service id: ${serviceId}, start time: ${startTime}`;
}
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.GetAvailabilities,
RequestStatus.Fail,
comment,
);
return null;
}
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.GetAvailabilities,
RequestStatus.Success,
JSON.stringify(responseData),
);
return responseData.Data;
} catch (error) {
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.GetAvailabilities,
RequestStatus.Fail,
JSON.stringify(error),
);
return null;
}
}
export async function bookAppointment(
serviceSyncId: number,
clinicId: number,
appointmentUserId: number,
syncUserID: number,
startTime: string,
locationId = 0,
comments = '',
isEarlierTimeRequested = false,
earlierTimeRequestComment = '',
) {
const supabase = await createClient();
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user?.id) {
throw new Error('User not authenticated');
}
const [
{ data: dbClinic, error: clinicError },
{ data: dbService, error: serviceError },
] = await Promise.all([
supabase
.from('connected_online_providers')
.select('*')
.eq('id', clinicId)
.limit(1),
supabase
.from('connected_online_services')
.select('*')
.eq('sync_id', serviceSyncId)
.eq('clinic_id', clinicId)
.limit(1),
]);
if (!dbClinic?.length || !dbService?.length) {
return logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.BookTime,
RequestStatus.Fail,
dbClinic?.length
? `Could not find clinic with id ${clinicId}, error: ${JSON.stringify(clinicError)}`
: `Could not find service with sync id ${serviceSyncId} and clinic id ${clinicId}, error: ${JSON.stringify(serviceError)}`,
startTime,
serviceSyncId,
clinicId,
);
}
const clinic: Tables<'connected_online_providers'> = dbClinic![0];
const service: Tables<'connected_online_services'> = dbService![0];
// TODO the dummy data needs to be replaced with real values once they're present on the user/account
const response = await axios.post(
`${process.env.CONNECTED_ONLINE_URL!}/${ConnectedOnlineMethodName.BookTime}`,
{
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
param: JSON.stringify({
EarlierTime: isEarlierTimeRequested, // once we have the e-shop functionality we can let the user select if she would like to be offered earlier time slots if they become available
EarlierTimeComment: earlierTimeRequestComment,
ClinicID: clinic.id,
ServiceID: service.id,
ClinicServiceID: service.sync_id,
UserID: appointmentUserId,
SyncUserID: syncUserID,
StartTime: startTime,
FirstName: 'Test',
LastName: 'User',
PersonalCode: '4',
Email: user.email,
Phone: 'phone',
Comments: comments,
Location: locationId,
FreeCode: '',
AddToBasket: false,
Key: '7T624nlu',
Lang: 'et', // update when integrated into app, if needed
}),
},
);
const responseData: BookTimeResponse = JSON.parse(response.data.d);
if (responseData?.ErrorCode !== 0 || !responseData.Value) {
return logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.BookTime,
RequestStatus.Fail,
JSON.stringify(responseData),
startTime,
service.id,
clinicId,
);
}
const responseParts = responseData.Value.split(',');
const { error } = await supabase
.from('connected_online_reservation')
.insert({
booking_code: responseParts[1],
clinic_id: clinic.id,
comments,
lang: 'et', // change later, if needed
service_id: service.id,
service_user_id: appointmentUserId,
start_time: startTime,
sync_user_id: syncUserID,
requires_payment: !!responseParts[0],
user_id: user.id,
});
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.BookTime,
RequestStatus.Success,
JSON.stringify(responseData),
startTime,
service.id,
clinicId,
);
if (error) {
throw new Error(error.message);
}
return responseData.Value;
} catch (error) {
return logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.BookTime,
RequestStatus.Fail,
JSON.stringify(error),
startTime,
serviceSyncId,
clinicId,
);
}
}
export async function getConfirmedService(reservationCode: string) {
try {
const response = await axios.post(
`${process.env.CONNECTED_ONLINE_URL!}/${ConnectedOnlineMethodName.ConfirmedLoad}`,
{
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
param: JSON.stringify({ Value: `${reservationCode}|7T624nlu|et` }),
},
);
const responseData: ConfirmedLoadResponse = JSON.parse(response.data.d);
if (responseData?.ErrorCode !== 0) {
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.ConfirmedLoad,
RequestStatus.Fail,
JSON.stringify(responseData),
);
return null;
}
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.ConfirmedLoad,
RequestStatus.Success,
JSON.stringify(responseData),
);
return responseData.Data;
} catch (error) {
await logRequestResult(
ExternalApi.ConnectedOnline,
ConnectedOnlineMethodName.ConfirmedLoad,
RequestStatus.Fail,
JSON.stringify(error),
);
return null;
}
}