freshyo/apps/backend/src/lib/post-order-handler.ts
2026-02-06 19:35:23 +05:30

128 lines
3.8 KiB
TypeScript

import { db } from '../db/db_index';
import { orders } from '../db/schema';
import redisClient from './redis-client';
import { sendTelegramMessage } from './telegram-service';
import { inArray } from 'drizzle-orm';
const ORDER_CHANNEL = 'orders:placed';
interface OrderIdMessage {
orderIds: number[];
}
const formatDateTime = (dateStr: string | null | undefined): string => {
if (!dateStr) return 'N/A';
return new Date(dateStr).toLocaleString('en-IN', {
dateStyle: 'medium',
timeStyle: 'short',
});
};
const formatOrderMessageWithFullData = (ordersData: any[]): string => {
let message = '🛒 <b>New Order Placed</b>\n\n';
ordersData.forEach((order, index) => {
message += `<b>Order ${order.id}</b>\n`;
message += '📦 <b>Items:</b>\n';
order.orderItems?.forEach((item: any) => {
message += `${item.product?.name || 'Unknown'} x${item.quantity}\n`;
});
message += `\n💰 <b>Total:</b> ₹${order.totalAmount}\n`;
message += `🚚 <b>Delivery:</b> ${
order.isFlashDelivery ? 'Flash Delivery' : formatDateTime(order.slot?.deliveryTime)
}\n`;
message += `\n📍 <b>Address:</b>\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`;
}
if (index < ordersData.length - 1) {
message += '\n---\n\n';
}
});
return message;
};
/**
* Start the post order handler
* Subscribes to the orders:placed channel and sends to Telegram
*/
export const startOrderHandler = async (): Promise<void> => {
try {
console.log('Starting post order handler...');
await redisClient.subscribe(ORDER_CHANNEL, async (message: string) => {
try {
const { orderIds }: OrderIdMessage = JSON.parse(message);
console.log('New order received, sending to Telegram...');
const ordersData = await db.query.orders.findMany({
where: inArray(orders.id, orderIds),
with: {
address: true,
orderItems: { with: { product: true } },
slot: true,
},
});
const telegramMessage = formatOrderMessageWithFullData(ordersData);
await sendTelegramMessage(telegramMessage);
} catch (error) {
console.error('Failed to process order message:', error);
await sendTelegramMessage(`⚠️ Error parsing order: ${message}`);
}
});
console.log('Post order handler started successfully');
} catch (error) {
console.error('Failed to start post order handler:', error);
throw error;
}
};
/**
* Stop the post order handler
*/
export const stopOrderHandler = async (): Promise<void> => {
try {
await redisClient.unsubscribe(ORDER_CHANNEL);
console.log('Post order handler stopped');
} catch (error) {
console.error('Error stopping post order handler:', error);
}
};
export const publishOrder = async (orderDetails: OrderIdMessage): Promise<boolean> => {
try {
const message = JSON.stringify(orderDetails);
await redisClient.publish(ORDER_CHANNEL, message);
return true;
} catch (error) {
console.error('Failed to publish order:', error);
return false;
}
};
export const publishFormattedOrder = async (
createdOrders: any[],
ordersBySlot: Map<number | null, any[]>
): Promise<boolean> => {
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;
}
};