const db = require('../plugin/DataBase/db') function roundMoney(n) { return Math.round(Number(n) * 100) / 100 } function calcDiscount(price, discountType, discountValue) { const p = Number(price) let discount = 0 if (discountType === 'percent') { const pct = Math.min(100, Math.max(0, Number(discountValue))) discount = roundMoney((p * pct) / 100) } else { discount = roundMoney(Math.min(p, Math.max(0, Number(discountValue)))) } let finalPrice = roundMoney(p - discount) if (finalPrice < 0.01) finalPrice = 0.01 if (finalPrice > p) finalPrice = p discount = roundMoney(p - finalPrice) return { discountAmount: discount, finalPrice } } async function countActiveUsage(couponId, userUuid) { const totalRows = await db.query( `SELECT COUNT(*) AS cnt FROM coupon_usage cu INNER JOIN orders o ON o.orderId = cu.order_id WHERE cu.coupon_id = ? AND o.state IN (0, 1, 2)`, [couponId] ) const userRows = await db.query( `SELECT COUNT(*) AS cnt FROM coupon_usage cu INNER JOIN orders o ON o.orderId = cu.order_id WHERE cu.coupon_id = ? AND cu.user_uuid = ? AND o.state IN (0, 1, 2)`, [couponId, userUuid] ) return { total: Number(totalRows?.[0]?.cnt || 0), perUser: Number(userRows?.[0]?.cnt || 0) } } /** * 校验优惠码并计算优惠后价格 */ async function validateCoupon({ code, userUuid, goodsId, goodsPrice }) { const normalizedCode = String(code || '').trim().toUpperCase() if (!normalizedCode) { return { ok: false, msg: '请输入优惠码' } } const rows = await db.query( `SELECT * FROM coupons WHERE code = ? AND state = 1 LIMIT 1`, [normalizedCode] ) if (!rows || rows.length !== 1) { return { ok: false, msg: '优惠码不存在或已失效' } } const coupon = rows[0] const now = Date.now() if (coupon.start_time && now < Number(coupon.start_time)) { return { ok: false, msg: '优惠码尚未生效' } } if (coupon.end_time && now > Number(coupon.end_time)) { return { ok: false, msg: '优惠码已过期' } } const price = Number(goodsPrice) const minAmount = Number(coupon.min_amount || 0) if (minAmount > 0 && price < minAmount) { return { ok: false, msg: `订单满 ¥${minAmount} 才可使用该优惠码` } } if (Number(coupon.goods_scope) === 1) { const goodsRows = await db.query( 'SELECT 1 FROM coupon_goods WHERE coupon_id = ? AND goods_id = ? LIMIT 1', [coupon.id, goodsId] ) if (!goodsRows || goodsRows.length === 0) { return { ok: false, msg: '该优惠码不适用于当前商品' } } } if (Number(coupon.user_scope) === 1) { const userRows = await db.query( 'SELECT 1 FROM coupon_users WHERE coupon_id = ? AND user_uuid = ? LIMIT 1', [coupon.id, userUuid] ) if (!userRows || userRows.length === 0) { return { ok: false, msg: '您暂无使用该优惠码的权限' } } } const usage = await countActiveUsage(coupon.id, userUuid) const totalLimit = Number(coupon.total_limit || 0) const perUserLimit = Number(coupon.per_user_limit || 1) if (totalLimit > 0 && usage.total >= totalLimit) { return { ok: false, msg: '优惠码已达使用上限' } } if (usage.perUser >= perUserLimit) { return { ok: false, msg: '您已达到该优惠码的使用次数上限' } } const { discountAmount, finalPrice } = calcDiscount( price, coupon.discount_type, coupon.discount_value ) if (discountAmount <= 0) { return { ok: false, msg: '优惠码无效,未产生优惠' } } return { ok: true, couponId: coupon.id, code: coupon.code, name: coupon.name, discountType: coupon.discount_type, discountValue: Number(coupon.discount_value), originalPrice: roundMoney(price), discountAmount, finalPrice, displayDiscount: coupon.discount_type === 'percent' ? `${coupon.discount_value}% 折扣` : `立减 ¥${coupon.discount_value}` } } async function recordUsage(couponId, orderId, userUuid, discountAmount) { const time = Date.now() await db.query( `INSERT INTO coupon_usage (coupon_id, order_id, user_uuid, discount_amount, create_time) VALUES (?, ?, ?, ?, ?)`, [couponId, orderId, userUuid, discountAmount, time] ) await db.query('UPDATE coupons SET used_count = used_count + 1 WHERE id = ?', [couponId]) } async function releaseUsageForOrder(orderId) { const rows = await db.query( 'SELECT coupon_id FROM orders WHERE orderId = ? AND coupon_id IS NOT NULL LIMIT 1', [orderId] ) if (!rows || !rows[0]?.coupon_id) return const couponId = rows[0].coupon_id const del = await db.query('DELETE FROM coupon_usage WHERE order_id = ?', [orderId]) if (del?.affectedRows > 0) { await db.query( 'UPDATE coupons SET used_count = GREATEST(used_count - 1, 0) WHERE id = ?', [couponId] ) } } module.exports = { roundMoney, calcDiscount, validateCoupon, recordUsage, releaseUsageForOrder }