const OfferModel = require('../models/OfferModel') const WalletTransactionModel = require('../models/WalletTransactionModel') const { notifyUser } = require('./notifyUser') const OFFER_REPLY_WINDOW_MS = 12 * 60 * 60 * 1000 /** * Called whenever a chat message is sent. If there's a pending paid Offer * between these two users, tracks the requester's first direct message and * the receiver's reply — the receiver's 50% commission is only credited if * they reply within 12 hours of that first message. */ async function trackOfferMessageForCommission (io, senderId, receiverId) { try { const offer = await OfferModel.findOne({ $or: [ { sender: senderId, receiver: receiverId }, { sender: receiverId, receiver: senderId } ], commissionCredited: false, pendingCommissionAmount: { $gt: 0 } }).sort({ createdAt: -1 }) if (!offer) return const isFromRequester = String(offer.sender) === String(senderId) if (isFromRequester) { if (!offer.firstMessageAt) { offer.firstMessageAt = new Date() offer.replyDeadline = new Date(Date.now() + OFFER_REPLY_WINDOW_MS) await offer.save() } return } // پیام از طرف گیرنده — کسی که باید ظرف ۱۲ ساعت پاسخ بدهد if (!offer.firstMessageAt || offer.repliedAt) return if (new Date() > offer.replyDeadline) return offer.repliedAt = new Date() offer.commissionCredited = true await offer.save() await WalletTransactionModel.create({ user: offer.receiver, bucket: 'gift', type: 'credit', amount: offer.pendingCommissionAmount, referenceType: 'payment', referenceId: offer._id, description: 'سهم دریافتی از درخواست همکاری (۵۰٪، پس از پاسخ به‌موقع)' }) if (io) { try { io.to(`user:${String(offer.receiver)}`).emit('notification', { type: 'offer_commission', title: 'واریز سهم درخواست همکاری', description: 'با پاسخ به‌موقع، ۵۰٪ مبلغ درخواست همکاری به کیف پول شما واریز شد.' }) } catch (_) {} } } catch (error) { console.error('trackOfferMessageForCommission error:', error) } } /** * Sweep for paid Offers whose 12-hour reply deadline has passed without the * receiver replying — refunds the pending 30% commission to the sender's * wallet instead (both web and Android go through the same payment callback, * so a single server-side sweep covers both). Meant to be called * periodically by a cron job (see services/OfferReplyCron.js). */ async function refundExpiredOfferCommissions (io) { const now = new Date() const expiredOffers = await OfferModel.find({ commissionCredited: false, commissionRefunded: false, pendingCommissionAmount: { $gt: 0 }, firstMessageAt: { $ne: null }, repliedAt: null, replyDeadline: { $lte: now } }) for (const offer of expiredOffers) { try { offer.commissionRefunded = true await offer.save() await WalletTransactionModel.create({ user: offer.sender, bucket: 'gift', type: 'credit', amount: offer.pendingCommissionAmount, referenceType: 'payment', referenceId: offer._id, description: 'بازگشت وجه درخواست همکاری (طرف مقابل ظرف ۱۲ ساعت مقرر پاسخ نداد)' }) await notifyUser(io, offer.sender, { type: 'offer_commission_refunded', title: 'بازگشت وجه به کیف پول', description: 'طرف مقابل ظرف مهلت ۱۲ ساعته به درخواست همکاری شما پاسخ نداد؛ مبلغ به کیف پول شما بازگشت.' }) } catch (error) { console.error('refundExpiredOfferCommissions error for offer', offer._id, error) } } return expiredOffers.length } module.exports = { trackOfferMessageForCommission, refundExpiredOfferCommissions, OFFER_REPLY_WINDOW_MS }