Files
medreport_mrb2b/lib/services/medusaCart.service.ts
2025-09-26 17:23:09 +03:00

180 lines
4.6 KiB
TypeScript

'use server';
import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account';
import { MontonioOrderHandlerService } from '@/packages/billing/montonio/src';
import { addToCart, deleteLineItem, retrieveCart } from '@lib/data/cart';
import { getCartId } from '@lib/data/cookies';
import { StoreCartLineItem, StoreProductVariant } from '@medusajs/types';
import { isSameMinute } from 'date-fns';
import { z } from 'zod';
import {
cancelReservation,
getOrderedTtoServices,
} from '~/lib/services/reservation.service';
import { createCartEntriesLog } from './audit/cartEntries';
import { getAvailableAppointmentsForService } from './connected-online.service';
const env = () =>
z
.object({
medusaBackendPublicUrl: z
.string({
error: 'MEDUSA_BACKEND_PUBLIC_URL is required',
})
.min(1),
siteUrl: z
.string({
error: 'NEXT_PUBLIC_SITE_URL is required',
})
.min(1),
})
.parse({
// Use for local testing
medusaBackendPublicUrl: 'http://webhook.site:3000',
siteUrl: 'http://webhook.site:3000',
// medusaBackendPublicUrl: process.env.MEDUSA_BACKEND_PUBLIC_URL!,
// siteUrl: process.env.NEXT_PUBLIC_SITE_URL!,
});
export async function handleAddToCart({
selectedVariant,
countryCode,
}: {
selectedVariant: Pick<StoreProductVariant, 'id'>;
countryCode: string;
}) {
try {
} catch (e) {
console.error('medusa card error: ', e);
}
const { account } = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
const quantity = 1;
const { newCart, addedItem } = await addToCart({
variantId: selectedVariant.id,
quantity,
countryCode,
});
await createCartEntriesLog({
variantId: selectedVariant.id,
operation: 'ADD_TO_CART',
accountId: account.id,
cartId: newCart.id,
});
return { cart: newCart, addedItem };
}
export async function handleDeleteCartItem({ lineId }: { lineId: string }) {
await deleteLineItem(lineId);
await cancelReservation(lineId);
const cartId = await getCartId();
const { account } = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
await createCartEntriesLog({
variantId: lineId,
operation: 'REMOVE_FROM_CART',
accountId: account.id,
cartId: cartId!,
});
}
export async function handleNavigateToPayment({
language,
paymentSessionId,
amount,
currencyCode,
cartId,
}: {
language: string;
paymentSessionId: string;
amount: number;
currencyCode: string;
cartId: string;
}) {
const { account } = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
const cart = await retrieveCart();
if (!cart) {
throw new Error('No cart found');
}
const orderedTtoServices = await getOrderedTtoServices({ cart });
if (orderedTtoServices?.length) {
const unavailableLineItemIds: string[] = [];
for (const ttoService of orderedTtoServices) {
const availabilities = await getAvailableAppointmentsForService(
ttoService.service_id,
ttoService.provider.key,
ttoService.location_sync_id,
new Date(ttoService.start_time),
1,
);
const isAvailable = availabilities?.T_Booking?.length
? availabilities.T_Booking.find((timeSlot) =>
isSameMinute(ttoService.start_time, timeSlot.StartTime),
)
: false;
if (!isAvailable) {
unavailableLineItemIds.push(ttoService.medusa_cart_line_item_id!);
}
}
if (unavailableLineItemIds.length) {
return { unavailableLineItemIds };
}
}
const paymentLink =
await new MontonioOrderHandlerService().getMontonioPaymentLink({
notificationUrl: `${env().medusaBackendPublicUrl}/hooks/payment/montonio_montonio`,
returnUrl: `${env().siteUrl}/home/cart/montonio-callback`,
amount,
currency: currencyCode.toUpperCase(),
description: `Order from Medreport`,
locale: language,
merchantReference: `${account.id}:${paymentSessionId}:${cartId}`,
});
await createCartEntriesLog({
operation: 'NAVIGATE_TO_PAYMENT',
accountId: account.id,
cartId: cart.id,
});
return { url: paymentLink };
}
export async function handleLineItemTimeout({
lineItem,
}: {
lineItem: StoreCartLineItem;
}) {
const { account } = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
await deleteLineItem(lineItem.id);
await createCartEntriesLog({
operation: 'LINE_ITEM_TIMEOUT',
accountId: account.id,
cartId: lineItem.cart_id,
});
}