'use server'; import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account'; import { MontonioOrderHandlerService } from '@/packages/billing/montonio/src'; import { getLogger } from '@/packages/shared/src/logger'; 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({ medusaBackendPublicUrl: (process.env.DEV_MONTONIO_CALLBACK_URL || process.env.MEDUSA_BACKEND_PUBLIC_URL)!, siteUrl: (process.env.DEV_MONTONIO_CALLBACK_URL || process.env.NEXT_PUBLIC_SITE_URL)!, }); export async function handleAddToCart({ selectedVariant, countryCode, }: { selectedVariant: Pick; countryCode: string; }) { const logger = await getLogger(); const ctx = { countryCode, selectedVariant, }; logger.info(ctx, 'Adding to cart...'); const { account } = await loadCurrentUserAccount(); if (!account) { logger.error(ctx, 'Account not found'); 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, }); }