Browse Source

✨ feat: 增加订单处理接口

Pchen. 11 months ago
parent
commit
adc4c99ac9
3 changed files with 256 additions and 0 deletions
  1. 66 0
      apis/Order/CallBack.js
  2. 126 0
      apis/Order/CreateOrder.js
  3. 64 0
      apis/Order/GetOrderDetail.js

+ 66 - 0
apis/Order/CallBack.js

@@ -0,0 +1,66 @@
+const API = require("../../lib/API.js")
+const db = require("../../plugin/DataBase/db.js")
+const { BaseStdResponse } = require("../../BaseStdResponse.js")
+const config = require('../../config.json')
+const crypto = require("crypto")
+
+const PAYMENT_KEY = config.pay.key
+
+class CallBack extends API {
+    constructor() {
+        super()
+        this.setPath('/Order/CallBack')
+        this.setMethod('GET')
+    }
+
+    async onRequest(req, res) {
+        const {
+            pid, trade_no, out_trade_no, type, name, money,
+            trade_status, sign, sign_type
+        } = req.query
+
+        // 参数校验
+        if ([pid, trade_no, out_trade_no, type, name, money, trade_status, sign, sign_type].some(v => v === undefined))
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER
+            })
+
+        // 签名校验
+        const rawParams = {
+            money, name, out_trade_no, pid, trade_no, trade_status, type
+        }
+        const sortedKeys = Object.keys(rawParams).sort()
+        const preSignStr = sortedKeys.map(key => `${key}=${rawParams[key]}`).join('&') + `&key=${PAYMENT_KEY}`
+        const localSign = crypto.createHash('md5').update(preSignStr, 'utf8').digest('hex')
+
+        if (localSign !== sign)
+            return res.json({
+                ...BaseStdResponse.ERR,
+                msg: '签名验证失败'
+            })
+
+        // 判断支付状态
+        if (trade_status !== 'TRADE_SUCCESS') {
+            const sql = 'UPDATE orders SET \`state\` = 2, pay_id = ? WHERE orderId = ?'
+            await db.query(sql, [trade_no, out_trade_no])
+        }
+            
+        try {
+            // 更新订单状态
+            const sql = 'UPDATE orders SET \`state\` = 1, pay_type = ?, pay_id = ? WHERE orderId = ? AND \`state\` = 0'
+            const result = await db.query(sql, [type, trade_no, out_trade_no])
+
+            if (result.affectedRows > 0) {
+                return res.send('success')
+            } else {
+                return res.send('订单不存在或已处理')
+            }
+        } catch (err) {
+            this.logger.error(`支付回调异常:${err.stack}`)
+            return res.send('服务器错误')
+        }
+    }
+}
+
+module.exports.CallBack = CallBack
+

+ 126 - 0
apis/Order/CreateOrder.js

@@ -0,0 +1,126 @@
+const API = require("../../lib/API.js")
+const db = require("../../plugin/DataBase/db.js")
+const { BaseStdResponse } = require("../../BaseStdResponse.js")
+const AccessControl = require("../../lib/AccessControl.js")
+const crypto = require('crypto')
+const config = require('../../config.json')
+
+function generateOrderId() {
+    const now = new Date()
+    const pad = (n, w = 2) => n.toString().padStart(w, '0')
+    return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`
+        + `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`
+        + `${pad(now.getMilliseconds(), 3)}`
+}
+
+function generatePaymentSign(params, key) {
+    const sorted = Object.keys(params).sort();
+    const query = sorted.map(k => `${k}=${params[k]}`).join('&') + `&key=${key}`;
+    return crypto.createHash('md5').update(query, 'utf8').digest('hex');
+}
+
+class CreateOrder extends API {
+    constructor() {
+        super()
+        this.setPath('/Order/CreateOrder')
+        this.setMethod('POST')
+    }
+
+    async onRequest(req, res) {
+        const { uuid, session, goods_id, pay_type } = req.body
+
+        if ([uuid, session, goods_id, pay_type].some(v => v === '' || v === null || v === undefined)) {
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER,
+                endpoint: 1513126
+            })
+        }
+
+        const sessionValid = await AccessControl.checkSession(uuid, session)
+        if (!sessionValid) {
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+        }
+
+        try {
+            // 查询商品信息
+            const goodsSql = 'SELECT name, price, num, state FROM goods WHERE id = ?'
+            const goodsRows = await db.query(goodsSql, [goods_id])
+
+            if (!goodsRows || goodsRows.length !== 1) {
+                return res.json({
+                    ...BaseStdResponse.ERR,
+                    msg: '商品不存在',
+                    endpoint: 1513126
+                })
+            }
+
+            const goods = goodsRows[0]
+            if (goods.num < 1 || goods.state !== 1) {
+                return res.json({
+                    ...BaseStdResponse.ERR,
+                    msg: '商品已下架或库存不足',
+                    endpoint: 1513126
+                })
+            }
+
+            const createTime = new Date().getTime()
+            const orderId = generateOrderId()
+
+            const insertSql = `
+                INSERT INTO orders (orderId, create_user, create_time, goods_id, price, pay_type)
+                VALUES (?, ?, ?, ?, ?, ?)
+            `
+            const insertParams = [orderId, uuid, createTime, goods_id, goods.price, pay_type]
+            const result = await db.query(insertSql, insertParams)
+
+            const updateSql = 'UPDATE goods SET num = num - 1 WHERE id = ?'
+            await db.query(updateSql, [goods_id])
+
+            if (result && result.affectedRows > 0) {
+                const paymentConfig = config.pay
+
+                const payParams = {
+                    pid: paymentConfig.pid,
+                    type: pay_type,
+                    out_trade_no: orderId,
+                    notify_url: config.url + '/Order/CallBack',
+                    return_url: paymentConfig.return_url,
+                    name: goods.name,
+                    money: goods.price.toFixed(2),
+                    sitename: paymentConfig.sitename
+                }
+
+                const sign = generatePaymentSign(payParams, paymentConfig.key);
+                payParams.sign = sign
+                payParams.sign_type = 'MD5'
+
+                // 构造支付URL
+                const queryString = new URLSearchParams(payParams).toString();
+                const payUrl = `${paymentConfig.url}?${queryString}`;
+
+                return res.json({
+                    ...BaseStdResponse.OK,
+                    id: orderId,
+                    payUrl
+                })
+            } else {
+                return res.json({
+                    ...BaseStdResponse.ERR,
+                    msg: '创建订单失败!请联系客服',
+                    endpoint: 7894378
+                })
+            }
+
+        } catch (err) {
+            this.logger.error(`创建订单失败!${err.stack}`)
+            return res.json({
+                ...BaseStdResponse.ERR,
+                msg: "创建订单失败!请联系客服",
+            })
+        }
+    }
+}
+
+module.exports.CreateOrder = CreateOrder

+ 64 - 0
apis/Order/GetOrderDetail.js

@@ -0,0 +1,64 @@
+const API = require("../../lib/API.js");
+const db = require("../../plugin/DataBase/db.js");
+const { BaseStdResponse } = require("../../BaseStdResponse.js");
+const AccessControl = require("../../lib/AccessControl.js");
+
+class GetAccount extends API {
+    constructor() {
+        super();
+
+        this.setPath('/JW/Account')
+        this.setMethod('GET')
+    }
+
+    async onRequest(req, res) {
+        let { uuid, session, orderId } = req.query
+
+        if ([uuid, session, orderId].some(value => value === '' || value === null || value === undefined))
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER,
+                endpoint: 1513126
+            })
+
+        if (!await AccessControl.checkSession(uuid, session))
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+
+        let sql = `
+                SELECT 
+                    a.orderId,
+                    a.create_time,
+                    a.price,
+                    a.state,
+                    a.pay_id,
+                    a.pay_type,
+                    a.pay_time,
+                    a.state,
+                    g.name
+                FROM 
+                    orders a
+                LEFT JOIN 
+                    goods g 
+                ON 
+                    a.goods_id = g.id
+                WHERE 
+                    a.create_user = ?
+            `
+
+        let rows = await db.query(sql, [uuid])
+
+        if (!rows || rows.length !== 1)
+            return res.json({
+                ...BaseStdResponse.ERR,
+                msg: '订单获取失败!'
+            })
+
+        res.json({
+            ...BaseStdResponse.OK,
+            data: rows[0]
+        })
+    }
+}
+
+module.exports.GetAccount = GetAccount;