const cron = require('node-cron') const OrderModel = require('../models/OrderModel') const { releaseOrderFunds, PAYMENT_TIMEOUT_MINUTES } = require('../controllers/application/orders/orderController') const { notifyUser } = require('../utils/notifyUser') let ioInstance = null /** Called once from index.js right after the socket.io server is created — cron jobs have no `req`. */ function setIo (io) { ioInstance = io } /** Auto-release seller funds 7 days after fulfillment if the buyer never confirmed receipt. */ const autoReleaseFulfilledOrders = async () => { const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) try { const orders = await OrderModel.find({ status: { $in: ['shipped', 'ready_for_pickup'] }, walletReleased: false, fulfilledAt: { $lte: sevenDaysAgo } }) for (const order of orders) { try { await releaseOrderFunds(order, 'auto_released', ioInstance) } catch (err) { console.error(`[OrderLifecycleCron] failed to release order ${order._id}:`, err) } } if (orders.length) { console.log(`[OrderLifecycleCron] auto-released ${orders.length} order(s)`) } } catch (error) { console.error('[OrderLifecycleCron] auto-release query failed:', error) } } /** Cancel unpaid orders that missed the 60-minute payment window. */ const autoCancelUnpaidOrders = async () => { const cutoff = new Date(Date.now() - PAYMENT_TIMEOUT_MINUTES * 60 * 1000) try { const orders = await OrderModel.find({ status: 'pending_payment', createdAt: { $lte: cutoff } }) for (const order of orders) { try { order.status = 'cancelled' order.cancelReason = 'عدم پرداخت در بازه زمانی مجاز' await order.save() await notifyUser(ioInstance, order.buyer, { project_post_id: order._id, type: 'shop_order', title: 'لغو سفارش', description: 'سفارش شما به دلیل عدم پرداخت در بازه زمانی مجاز لغو شد.' }) } catch (err) { console.error(`[OrderLifecycleCron] failed to cancel order ${order._id}:`, err) } } if (orders.length) { console.log(`[OrderLifecycleCron] auto-cancelled ${orders.length} unpaid order(s)`) } } catch (error) { console.error('[OrderLifecycleCron] auto-cancel failed:', error) } } // هر ساعت: بررسی سفارش‌های تحویل‌شده‌ی بدون تایید خریدار برای آزادسازی خودکار وجه cron.schedule('0 * * * *', autoReleaseFulfilledOrders) // هر ۱۰ دقیقه: لغو سفارش‌های پرداخت‌نشده‌ی خارج از مهلت ۶۰ دقیقه‌ای cron.schedule('*/10 * * * *', autoCancelUnpaidOrders) module.exports = { autoReleaseFulfilledOrders, autoCancelUnpaidOrders, setIo }