/** * 支付控制器 * * 功能:处理支付和发票管理的业务逻辑 */ const { Payment, Invoice } = require('../models/Payment'); const Order = require('../models/Order'); const { validateRequired, validateEmail, validateBatch } = require('../utils/validator'); const { success } = require('../utils/response'); const { BusinessError, ValidationError, AuthorizationError } = require('../middleware/errorHandler'); // ======================================== // 支付相关控制器 // ======================================== /** * 获取支付记录列表 * GET /api/payments * 需要管理员权限 */ const getPayments = async (req, res, next) => { try { const { page = 1, pageSize = 10, payment_method, status, start_date, end_date } = req.query; const result = await Payment.findAll({ page: parseInt(page), pageSize: parseInt(pageSize), payment_method, status, start_date, end_date }); res.json(success({ list: result.list, pagination: { total: result.total, page: result.page, pageSize: result.pageSize, totalPages: Math.ceil(result.total / result.pageSize) } }, '获取支付记录成功')); } catch (err) { next(err); } }; /** * 获取支付详情 * GET /api/payments/:id */ const getPaymentById = async (req, res, next) => { try { const { id } = req.params; const payment = await Payment.findById(id); if (!payment) { throw new BusinessError('支付记录不存在', 404); } // 权限控制:顾客只能查看自己的支付记录 if (req.user.role === 'customer' && payment.customer_id !== req.user.id) { throw new AuthorizationError('您没有权限查看此支付记录'); } res.json(success(payment, '获取支付详情成功')); } catch (err) { next(err); } }; /** * 创建支付(发起支付) * POST /api/payments */ const createPayment = async (req, res, next) => { try { const { order_id, payment_method } = req.body; // 数据验证 const validation = validateBatch([ validateRequired(order_id, '订单ID'), validateRequired(payment_method, '支付方式') ]); if (!validation.valid) { throw new ValidationError('数据验证失败', validation.errors); } // 验证支付方式 const validMethods = ['cash', 'card', 'wechat', 'alipay']; if (!validMethods.includes(payment_method)) { throw new ValidationError(`支付方式必须是以下之一: ${validMethods.join(', ')}`); } // 检查订单是否存在 const order = await Order.findById(order_id); if (!order) { throw new BusinessError('订单不存在', 404); } // 权限控制:只能支付自己的订单 if (req.user.role === 'customer' && order.customer_id !== req.user.id) { throw new AuthorizationError('您没有权限支付此订单'); } // 检查订单状态 if (['paid', 'cancelled', 'refunded'].includes(order.status)) { throw new BusinessError('该订单无法支付'); } // 检查是否已有支付记录 const existingPayment = await Payment.findByOrderId(order_id); if (existingPayment && existingPayment.status === 'paid') { throw new BusinessError('该订单已支付'); } // 创建支付记录 const payment = await Payment.create({ order_id, payment_method, amount: order.final_amount }); res.status(201).json(success(payment, '创建支付成功')); } catch (err) { next(err); } }; /** * 确认支付(模拟支付成功) * POST /api/payments/:id/confirm */ const confirmPayment = async (req, res, next) => { try { const { id } = req.params; const { third_party_transaction_no } = req.body; // 检查支付记录是否存在 const payment = await Payment.findById(id); if (!payment) { throw new BusinessError('支付记录不存在', 404); } // 检查支付状态 if (payment.status === 'paid') { throw new BusinessError('该支付已完成'); } if (payment.status === 'refunded') { throw new BusinessError('该支付已退款'); } // 处理支付成功(包含积分奖励) const updatedPayment = await Payment.handlePaymentSuccess( id, third_party_transaction_no || null ); res.json(success(updatedPayment, '支付成功')); } catch (err) { next(err); } }; /** * 申请退款 * POST /api/payments/:id/refund */ const requestRefund = async (req, res, next) => { try { const { id } = req.params; const { reason } = req.body; // 数据验证 const validation = validateRequired(reason, '退款原因'); if (!validation.valid) { throw new ValidationError('数据验证失败', validation.errors); } // 检查支付记录是否存在 const payment = await Payment.findById(id); if (!payment) { throw new BusinessError('支付记录不存在', 404); } // 权限控制:只能退款自己的订单 if (req.user.role === 'customer' && payment.customer_id !== req.user.id) { throw new AuthorizationError('您没有权限申请退款'); } // 检查支付状态 if (payment.status !== 'paid') { throw new BusinessError('只有已支付的订单才能申请退款'); } const updatedPayment = await Payment.requestRefund(id, reason); res.json(success(updatedPayment, '退款申请已提交')); } catch (err) { next(err); } }; /** * 完成退款 * POST /api/payments/:id/complete-refund * 需要管理员权限 */ const completeRefund = async (req, res, next) => { try { const { id } = req.params; // 检查支付记录是否存在 const payment = await Payment.findById(id); if (!payment) { throw new BusinessError('支付记录不存在', 404); } // 检查支付状态 if (payment.status !== 'refunding') { throw new BusinessError('该支付未申请退款'); } const updatedPayment = await Payment.completeRefund(id); res.json(success(updatedPayment, '退款完成')); } catch (err) { next(err); } }; /** * 获取支付统计 * GET /api/payments/statistics * 需要管理员权限 */ const getPaymentStatistics = async (req, res, next) => { try { const { start_date, end_date } = req.query; const stats = await Payment.getStatistics( start_date || null, end_date || null ); res.json(success(stats, '获取支付统计成功')); } catch (err) { next(err); } }; // ======================================== // 发票相关控制器 // ======================================== /** * 获取发票列表 * GET /api/payments/invoices */ const getInvoices = async (req, res, next) => { try { const { page = 1, pageSize = 10, status } = req.query; // 权限控制:顾客只能查看自己的发票 if (req.user.role === 'customer') { const invoices = await Invoice.getUserInvoices(req.user.id); return res.json(success({ count: invoices.length, invoices }, '获取发票列表成功')); } // 管理员可以查看所有发票 const result = await Invoice.findAll({ page: parseInt(page), pageSize: parseInt(pageSize), status }); res.json(success({ list: result.list, pagination: { total: result.total, page: result.page, pageSize: result.pageSize, totalPages: Math.ceil(result.total / result.pageSize) } }, '获取发票列表成功')); } catch (err) { next(err); } }; /** * 获取发票详情 * GET /api/payments/invoices/:id */ const getInvoiceById = async (req, res, next) => { try { const { id } = req.params; const invoice = await Invoice.findById(id); if (!invoice) { throw new BusinessError('发票不存在', 404); } // 权限控制:需要通过payment查找customer_id const payment = await Payment.findById(invoice.payment_id); if (req.user.role === 'customer' && payment.customer_id !== req.user.id) { throw new AuthorizationError('您没有权限查看此发票'); } res.json(success(invoice, '获取发票详情成功')); } catch (err) { next(err); } }; /** * 申请开票 * POST /api/payments/invoices */ const createInvoice = async (req, res, next) => { try { const { payment_id, invoice_type, invoice_title, tax_no, email } = req.body; // 数据验证 const validation = validateBatch([ validateRequired(payment_id, '支付ID'), validateRequired(invoice_type, '发票类型'), validateRequired(invoice_title, '发票抬头'), validateRequired(email, '邮箱'), validateEmail(email, '邮箱') ]); if (!validation.valid) { throw new ValidationError('数据验证失败', validation.errors); } // 验证发票类型 const validTypes = ['personal', 'company']; if (!validTypes.includes(invoice_type)) { throw new ValidationError('发票类型必须是 personal 或 company'); } // 企业发票需要税号 if (invoice_type === 'company' && !tax_no) { throw new ValidationError('企业发票需要提供税号'); } // 检查支付记录是否存在 const payment = await Payment.findById(payment_id); if (!payment) { throw new BusinessError('支付记录不存在', 404); } // 权限控制:只能为自己的支付开票 if (req.user.role === 'customer' && payment.customer_id !== req.user.id) { throw new AuthorizationError('您没有权限为此支付开票'); } // 检查支付状态 if (payment.status !== 'paid') { throw new BusinessError('只有已支付的订单才能开具发票'); } // 检查是否已开票 const existingInvoice = await Invoice.findByPaymentId(payment_id); if (existingInvoice) { throw new BusinessError('该支付已申请开票'); } const invoice = await Invoice.create({ payment_id, invoice_type, invoice_title, tax_no: tax_no || null, email }); res.status(201).json(success(invoice, '申请开票成功')); } catch (err) { next(err); } }; /** * 更新发票状态(开具发票) * PUT /api/payments/invoices/:id/status * 需要管理员权限 */ const updateInvoiceStatus = async (req, res, next) => { try { const { id } = req.params; const { status } = req.body; // 数据验证 const validation = validateRequired(status, '状态'); if (!validation.valid) { throw new ValidationError('数据验证失败', validation.errors); } // 验证状态值 const validStatuses = ['pending', 'issued', 'cancelled']; if (!validStatuses.includes(status)) { throw new ValidationError(`状态必须是以下之一: ${validStatuses.join(', ')}`); } // 检查发票是否存在 const invoice = await Invoice.findById(id); if (!invoice) { throw new BusinessError('发票不存在', 404); } const updatedInvoice = await Invoice.updateStatus(id, status); const messages = { pending: '发票已标记为待处理', issued: '发票已开具', cancelled: '发票已取消' }; res.json(success(updatedInvoice, messages[status])); } catch (err) { next(err); } }; /** * 获取我的发票列表 * GET /api/payments/my/invoices */ const getMyInvoices = async (req, res, next) => { try { const invoices = await Invoice.getUserInvoices(req.user.id); res.json(success({ count: invoices.length, invoices }, '获取我的发票成功')); } catch (err) { next(err); } }; // 导出所有控制器函数 module.exports = { // 支付相关 getPayments, getPaymentById, createPayment, confirmPayment, requestRefund, completeRefund, getPaymentStatistics, // 发票相关 getInvoices, getInvoiceById, createInvoice, updateInvoiceStatus, getMyInvoices };