Files
omniai-server/src/routes/payment.js
T

146 lines
5.2 KiB
JavaScript
Raw Normal View History

2026-06-02 13:14:10 +08:00
const { express, requireAuth, isSystemAdmin, wechatPay, alipay, pool } = require("./context");
function registerPaymentRoutes(router) {
// ── Payment ──────────────────────────────────────────────────────────
function getNotifyBaseUrl() {
return process.env.PAYMENT_NOTIFY_BASE_URL || "";
}
router.post("/payment/create", requireAuth, async (req, res) => {
const { orderNo, paymentMethod = "wechat" } = req.body;
if (!orderNo) return res.status(400).json({ error: "缺少订单号" });
const {
rows: [order],
} = await pool.query("SELECT * FROM payment_orders WHERE order_no = $1 AND status = $2", [
orderNo,
"pending",
]);
if (!order) return res.status(404).json({ error: "订单不存在或已处理" });
// Verify order belongs to user
const isOwnOrder =
(order.enterprise_id &&
req.user.enterpriseId &&
order.enterprise_id === req.user.enterpriseId) ||
(order.user_id && order.user_id === req.user.id);
if (!isOwnOrder && !isSystemAdmin(req.user)) {
return res.status(403).json({ error: "无权操作此订单" });
}
const notifyBase = getNotifyBaseUrl();
const description =
order.type === "package" ? `套餐购买 - ${order.order_no}` : `积分充值 - ${order.order_no}`;
try {
if (paymentMethod === "wechat") {
if (!wechatPay.isWechatPayEnabled())
return res.status(503).json({ error: "微信支付未配置" });
const notifyUrl = notifyBase ? `${notifyBase}/api/payment/notify/wechat` : "";
const result = await wechatPay.createNativeOrder(
orderNo,
order.amount_cents,
description,
notifyUrl,
);
return res.json({ paymentMethod: "wechat", codeUrl: result.codeUrl, orderNo });
}
if (paymentMethod === "alipay") {
if (!alipay.isAlipayEnabled()) return res.status(503).json({ error: "支付宝未配置" });
const notifyUrl = notifyBase ? `${notifyBase}/api/payment/notify/alipay` : "";
const result = await alipay.createPrecreateOrder(
orderNo,
order.amount_cents,
description,
notifyUrl,
);
return res.json({ paymentMethod: "alipay", codeUrl: result.qrCode, orderNo });
}
return res.status(400).json({ error: "不支持的支付方式" });
} catch (err) {
console.error("[payment/create] failed", err.message);
res.status(500).json({ error: `创建支付失败: ${err.message}` });
}
});
router.get("/payment/status", requireAuth, async (req, res) => {
const { orderNo } = req.query;
if (!orderNo) return res.status(400).json({ error: "缺少订单号" });
const {
rows: [order],
} = await pool.query(
"SELECT order_no, status, amount_cents, payment_method, paid_at, enterprise_id, user_id FROM payment_orders WHERE order_no = $1",
[orderNo],
);
if (!order) return res.status(404).json({ error: "订单不存在" });
const isOwn =
(order.enterprise_id &&
req.user.enterpriseId &&
order.enterprise_id === req.user.enterpriseId) ||
(order.user_id && order.user_id === req.user.id);
if (!isOwn && !isSystemAdmin(req.user)) {
return res.status(403).json({ error: "无权查看此订单" });
}
res.json({
orderNo: order.order_no,
status: order.status,
amountCents: order.amount_cents,
paymentMethod: order.payment_method,
paidAt: order.paid_at,
});
});
router.post("/payment/notify/wechat", express.raw({ type: "*/*" }), (req, res) => {
try {
let body = req.body;
if (Buffer.isBuffer(body)) body = JSON.parse(body.toString("utf-8"));
const result = wechatPay.verifyAndDecryptNotification(req.headers, body);
if (!result) return res.status(400).json({ code: "FAIL", message: "签名验证失败" });
if (result.trade_state === "SUCCESS") {
wechatPay.handlePaymentSuccess(result.out_trade_no, result.transaction_id);
}
res.json({ code: "SUCCESS", message: "OK" });
} catch (err) {
console.error("[payment/notify/wechat] error:", err.message);
res.status(500).json({ code: "FAIL", message: "Internal error" });
}
});
router.post("/payment/notify/alipay", express.urlencoded({ extended: false }), (req, res) => {
try {
const body = req.body;
const verified = alipay.verifyCallback(req.headers, body);
if (!verified) return res.send("fail");
const orderNo = body.out_trade_no || body.trade_no;
const tradeNo = body.trade_no || body.trade_id;
if (body.trade_status === "TRADE_SUCCESS" || body.trade_status === "TRADE_FINISHED") {
alipay.handlePaymentSuccess(orderNo, tradeNo);
}
res.send("success");
} catch (err) {
console.error("[payment/notify/alipay] error:", err.message);
res.send("fail");
}
});
router.get("/payment/methods", (_req, res) => {
res.json({ wechat: wechatPay.isWechatPayEnabled(), alipay: alipay.isAlipayEnabled() });
});
}
module.exports = {
registerPaymentRoutes,
};