/** * 订单服务:商品、订单创建、状态机与幂等标记已支付 * * 订单状态: * PENDING —— 已创建待支付 * PAID —— 支付成功(已发货) * CLOSED —— 超时/关闭 */ const { paymentId, outTradeNo } = require('../utils/id'); /** 商品目录(价格单位:分;retail_price_usd 为海外渠道展示用) */ const PRODUCTS = [ { id: 'p001', name: '橘子', quota: 1, retail_price: 1100, // ¥11.00 retail_price_usd: 0, expire_policy: 'once', expire_policy_text: '一次性', description: '演示商品', methods: ['wechat', 'alipay', 'stripe', 'apple', 'google'], }, ]; /** 订单存储(内存 Map;演示足够,重启丢失) */ const orders = new Map(); /** * 按 id 查找商品 * @returns {object|undefined} */ function findProduct(productId) { return PRODUCTS.find((p) => p.id === productId); } /** * 创建订单 * @param {object} param * @param {string} param.productId 商品 ID * @param {string} param.source 来源:app|web * @param {string} param.currency 币种(默认 cny,按商品零售价计) * @returns {{ id, productId, name, amount, currency, status, outTradeNo, createdAt }} */ function createOrder({ productId, source = 'app', currency = 'cny' }) { const product = findProduct(productId); if (!product) { const err = new Error(`product not found: ${productId}`); err.code = 'PRODUCT_NOT_FOUND'; throw err; } const order = { id: paymentId(), outTradeNo: outTradeNo(), productId, name: product.name, amount: product.retail_price, currency, status: 'PENDING', channel: null, channelTradeNo: null, source, createdAt: new Date().toISOString(), paidAt: null, }; orders.set(order.id, order); return order; } /** 查询订单 */ function getOrder(orderId) { return orders.get(orderId); } /** 按商户订单号(out_trade_no)查询订单(回调通知用) */ function getOrderByOutTradeNo(outTradeNo) { for (const order of orders.values()) { if (order.outTradeNo === outTradeNo) return order; } return null; } /** 按商户订单号标记已支付(幂等) */ function markPaidByOutTradeNo(outTradeNo, meta) { const order = getOrderByOutTradeNo(outTradeNo); return order ? markPaid(order.id, meta) : false; } /** * 标记订单已支付(幂等):仅 PENDING → PAID 成功执行一次 * @returns {boolean} 本次是否真正完成变更 */ function markPaid(orderId, { channel, channelTradeNo }) { const order = orders.get(orderId); if (!order) return false; if (order.status !== 'PENDING') return false; // 已处理过,幂等 order.status = 'PAID'; order.channel = channel; order.channelTradeNo = channelTradeNo; order.paidAt = new Date().toISOString(); return true; } /** * 查询支付状态(前端轮询/最终确认) * @returns {{ success: boolean, note: string }} */ function getStatus(orderId) { const order = orders.get(orderId); if (!order) { return { success: false, note: '订单不存在' }; } if (order.status === 'PAID') { return { success: true, note: '支付成功' }; } if (order.status === 'CLOSED') { return { success: false, note: '订单已关闭' }; } return { success: false, note: '等待支付' }; } /** 全部商品列表(前端定价展示) */ function listProducts() { return PRODUCTS; } module.exports = { findProduct, createOrder, getOrder, markPaid, getStatus, listProducts, };