import { getOrdersByIdsWithFullData, getOrderByIdWithFullData, composeSkuName, composeUnitNotation, } from '@/src/dbService' import { sendTelegramMessage } from '@/src/lib/telegram-service' import { queueDataPusher } from '@/src/lib/queue-data-pusher' import { ensureWorkerInit } from './worker-init'; import { getAppUrl } from '@/src/lib/env-exporter' interface OrderIdMessage { orderIds: number[]; } interface CancellationMessage { orderId: number; cancelledBy: 'user' | 'admin'; reason: string; cancelledAt: string; } const formatDateTime = (dateStr: string | null | undefined): string => { if (!dateStr) return 'N/A'; return new Date(dateStr).toLocaleString('en-IN', { dateStyle: 'medium', timeStyle: 'short', timeZone: 'Asia/Kolkata', }); }; const buildTelegramLinks = (orderId: number, userId?: number | null): string => { const baseUrl = getAppUrl() || 'https://ui.freshyo.in' const orderUrl = `${baseUrl}/manage-orders/order-details/${orderId}` const orderLink = `↪ Order` if (!userId) { return orderLink } const userUrl = `${baseUrl}/user-management/${userId}` const userLink = `↪ User` return `${orderLink} | ${userLink}` } const formatOrderMessageWithFullData = (ordersData: any[]): string => { console.log('formatting the msg') let message = 'šŸ›’ New Order Placed\n\n'; ordersData.forEach((order, index) => { message += `Order ${order.id}\n`; message += 'šŸ“¦ Items:\n'; order.orderItems?.forEach((item: any) => { const sku = item.sku const features = sku?.features || [] const name = composeSkuName(sku?.product?.name || 'Unknown', features) const unit = composeUnitNotation(features) message += ` • ${name} ${unit} x${item.quantity}\n`; }); message += `\nšŸ’° Total: ₹${order.totalAmount}\n`; message += `🚚 Delivery: ${ order.isFlashDelivery ? 'Flash Delivery' : formatDateTime(order.slot?.deliveryTime) }\n`; message += `\nšŸ“ Address:\n`; message += ` ${order.address?.name || 'N/A'}\n`; message += ` ${order.address?.addressLine1 || ''}\n`; if (order.address?.addressLine2) { message += ` ${order.address.addressLine2}\n`; } message += ` ${order.address?.city || ''}, ${order.address?.state || ''} - ${order.address?.pincode || ''}\n`; if (order.address?.phone) { message += ` šŸ“ž ${order.address.phone}\n`; } message += `\n${buildTelegramLinks(order.id, order.userId)}\n` if (index < ordersData.length - 1) { message += '\n---\n\n'; } }); return message; }; const formatCancellationMessage = (orderData: any, cancellationData: CancellationMessage): string => { const message = `āŒ Order Cancelled Order #${orderData.id} šŸ‘¤ Name: ${orderData.address?.name || 'N/A'} šŸ“ž Phone: ${orderData.address?.phone || 'N/A'} šŸ“¦ Items: ${orderData.orderItems?.map((item: any) => ` • ${item.sku?.product?.name || 'Unknown'} x${item.quantity}`).join('\n') || ' N/A'} šŸ’° Total: ₹${orderData.totalAmount} šŸ’³ Refund: ${orderData.refundStatus === 'na' ? 'N/A (COD)' : orderData.refundStatus || 'Pending'} ā“ Reason: ${cancellationData.reason} šŸ‘¤ Cancelled by: ${cancellationData.cancelledBy === 'admin' ? 'Admin' : 'User'} ā° Time: ${formatDateTime(cancellationData.cancelledAt)} ${buildTelegramLinks(orderData.id, orderData.userId)} `; return message; }; export const handleOrderPlaced = async (orderIds: number[], rawMessage?: string): Promise => { try { const ordersData = await getOrdersByIdsWithFullData(orderIds) const telegramMessage = formatOrderMessageWithFullData(ordersData) await sendTelegramMessage(telegramMessage) } catch (error) { console.error('Failed to process order message:', error) const fallback = rawMessage ? `āš ļø Error parsing order: ${rawMessage}` : 'āš ļø Error parsing order' await sendTelegramMessage(fallback) } } export const handleOrderCancelled = async ( cancellationData: CancellationMessage, rawMessage?: string ): Promise => { try { console.log('Order cancellation received, sending to Telegram...') const orderData = await getOrderByIdWithFullData(cancellationData.orderId) if (!orderData) { console.error('Order not found for cancellation:', cancellationData.orderId) await sendTelegramMessage(`āš ļø Order ${cancellationData.orderId} was cancelled but could not be found in database`) return } const refundStatus = orderData.refunds?.[0]?.refundStatus || 'pending' const telegramMessage = formatCancellationMessage({ ...orderData, refundStatus }, cancellationData) await sendTelegramMessage(telegramMessage) } catch (error) { console.error('Failed to process cancellation message:', error) const fallback = rawMessage ? `āš ļø Error processing cancellation: ${rawMessage}` : 'āš ļø Error processing cancellation' await sendTelegramMessage(fallback) } } /** * Start the post order handler * Subscribes to the orders:placed channel and sends to Telegram */ export const publishOrder = async (orderDetails: OrderIdMessage): Promise => { console.log('publishing order') try { await queueDataPusher.pushOrderPlacedQueue({ name: 'order-placed', orderIds: orderDetails.orderIds, }) return true; } catch (error) { console.error('Failed to publish order:', error); return false; } }; export const publishFormattedOrder = async ( createdOrders: any[], ordersBySlot: Map ): Promise => { try { const orderIds = createdOrders.map(order => order.id); return await publishOrder({ orderIds }); } catch (error) { console.error('Failed to format and publish order:', error); return false; } }; export const publishCancellation = async ( orderId: number, cancelledBy: 'user' | 'admin', reason: string ): Promise => { try { const message: CancellationMessage = { orderId, cancelledBy, reason, cancelledAt: new Date().toISOString(), }; await queueDataPusher.pushOrderCancelledQueue({ name: 'order-cancelled', ...message, }) console.log('Cancellation published to queue:', orderId); return true; } catch (error) { console.error('Failed to publish cancellation:', error); return false; } };