full
This commit is contained in:
81
services/OrderLifecycleCron.js
Normal file
81
services/OrderLifecycleCron.js
Normal file
@@ -0,0 +1,81 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user