const db = require('../plugin/DataBase/db') const { insertLedgerRecord } = require('./Lepao/CountLedger') const { requestPaymentRefund } = require('./PaymentClient') const REFUND_WINDOW_MS = 7 * 24 * 60 * 60 * 1000 const ORDER_STATE_COMPLETED = 2 const ORDER_STATE_REFUNDED = 5 function evaluateRefundEligibility({ state, payTime, userLepaoCount, goodsLepaoCount, skipTimeLimit = false }) { if (Number(state) === ORDER_STATE_REFUNDED) { return { canRefund: false, reason: '订单已退款' } } if (Number(state) !== ORDER_STATE_COMPLETED) { return { canRefund: false, reason: '仅已完成订单可申请退款' } } if (!payTime) { return { canRefund: false, reason: '订单支付时间异常' } } if (!skipTimeLimit && Date.now() - Number(payTime) > REFUND_WINDOW_MS) { return { canRefund: false, reason: '已超过7天退款期限' } } const purchasedCount = Number(goodsLepaoCount || 0) const remainingCount = Number(userLepaoCount || 0) if (purchasedCount > 0 && remainingCount <= purchasedCount) { return { canRefund: false, reason: '账户剩余次数需大于订单购买次数才可退款' } } return { canRefund: true, reason: '' } } async function loadRefundContext(orderId) { const rows = await db.query( `SELECT o.orderId, o.state, o.price, o.pay_id, o.pay_time, o.create_user, g.lepao_count, g.ic_count FROM orders o LEFT JOIN goods g ON o.goods_id = g.id WHERE o.orderId = ? LIMIT 1`, [orderId] ) if (!rows || rows.length !== 1) { return null } const order = rows[0] const userRows = await db.query( 'SELECT lepao_count, ic_count FROM users WHERE uuid = ? LIMIT 1', [order.create_user] ) if (!userRows || userRows.length !== 1) { return null } return { order, user: userRows[0] } } async function executeOrderRefund({ orderId, operatorUuid = null, skipTimeLimit = false, logger }) { try { const context = await loadRefundContext(orderId) if (!context) { return { ok: false, msg: '订单或用户不存在' } } const { order, user } = context const eligibility = evaluateRefundEligibility({ state: order.state, payTime: order.pay_time, userLepaoCount: user.lepao_count, goodsLepaoCount: order.lepao_count, skipTimeLimit }) if (!eligibility.canRefund) { return { ok: false, msg: eligibility.reason } } const deductLepao = Number(order.lepao_count || 0) const deductIc = Number(order.ic_count || 0) if (deductLepao > 0 && Number(user.lepao_count || 0) < deductLepao) { return { ok: false, msg: '账户乐跑次数不足,无法完成退款' } } await requestPaymentRefund({ orderId: order.orderId, tradeNo: order.pay_id, money: order.price, logger }) const conn = await db.connect() try { await conn.beginTransaction() const [orderRows] = await conn.execute( `SELECT o.orderId, o.state, o.create_user, g.lepao_count, g.ic_count FROM orders o LEFT JOIN goods g ON o.goods_id = g.id WHERE o.orderId = ? FOR UPDATE`, [orderId] ) if (!orderRows || orderRows.length !== 1) { await conn.rollback() return { ok: false, msg: '订单不存在' } } const lockedOrder = orderRows[0] if (Number(lockedOrder.state) !== ORDER_STATE_COMPLETED) { await conn.rollback() return { ok: false, msg: '订单状态已变更,请刷新后重试' } } const [userRows] = await conn.execute( 'SELECT lepao_count, ic_count FROM users WHERE uuid = ? FOR UPDATE', [lockedOrder.create_user] ) if (!userRows || userRows.length !== 1) { await conn.rollback() return { ok: false, msg: '用户不存在' } } const lockedUser = userRows[0] const lockedDeductLepao = Number(lockedOrder.lepao_count || 0) const lockedDeductIc = Number(lockedOrder.ic_count || 0) const beforeLepao = Number(lockedUser.lepao_count || 0) const beforeIc = Number(lockedUser.ic_count || 0) if (lockedDeductLepao > 0 && beforeLepao < lockedDeductLepao) { await conn.rollback() logger?.error?.(`退款支付已成功但扣次失败,需人工处理,订单号:${orderId}`) return { ok: false, msg: '支付已退款但扣减次数失败,请联系客服处理' } } const afterLepao = beforeLepao - lockedDeductLepao const afterIc = Math.max(0, beforeIc - lockedDeductIc) const [updateUserRes] = await conn.execute( 'UPDATE users SET lepao_count = ?, ic_count = ? WHERE uuid = ?', [afterLepao, afterIc, lockedOrder.create_user] ) if (!updateUserRes || updateUserRes.affectedRows !== 1) { await conn.rollback() logger?.error?.(`退款支付已成功但更新用户失败,需人工处理,订单号:${orderId}`) return { ok: false, msg: '支付已退款但更新账户失败,请联系客服处理' } } const [updateOrderRes] = await conn.execute( 'UPDATE orders SET state = ? WHERE orderId = ? AND state = ?', [ORDER_STATE_REFUNDED, orderId, ORDER_STATE_COMPLETED] ) if (!updateOrderRes || updateOrderRes.affectedRows !== 1) { await conn.rollback() logger?.error?.(`退款支付已成功但更新订单失败,需人工处理,订单号:${orderId}`) return { ok: false, msg: '支付已退款但更新订单失败,请联系客服处理' } } if (lockedDeductLepao !== 0) { await insertLedgerRecord({ executor: conn, userUuid: lockedOrder.create_user, delta: -lockedDeductLepao, balanceBefore: beforeLepao, balanceAfter: afterLepao, bizType: 'purchase_refund', bizId: orderId, operatorUuid, remark: `订单退款:${orderId}` }) } await conn.commit() return { ok: true, msg: '退款成功' } } catch (dbError) { try { await conn.rollback() } catch (_) { } logger?.error?.(`退款入账失败 ${orderId}: ${dbError.stack || dbError}`) return { ok: false, msg: '支付已退款但入账失败,请联系客服处理' } } } catch (error) { logger?.error?.(`订单退款失败 ${orderId}: ${error.stack || error}`) return { ok: false, msg: error.message || '退款失败,请稍后再试' } } } module.exports = { REFUND_WINDOW_MS, ORDER_STATE_REFUNDED, evaluateRefundEligibility, executeOrderRefund }