Initial commit: OmniAI backend server
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
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,
|
||||
};
|
||||
Reference in New Issue
Block a user