package seller import ( "Wine-Server/utils" "Wine-Server/utils/tables" "encoding/json" "errors" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers" "github.com/wechatpay-apiv3/wechatpay-go/core/downloader" "github.com/wechatpay-apiv3/wechatpay-go/core/notify" ) func VersionHandler(ctx *gin.Context) { version := tables.VersionTable{} err := version.GetLatest() if err != nil { ctx.JSON(utils.HttpError, utils.Fail("Get latest version failed")) return } ctx.JSON(utils.HttpOk, utils.Success(version)) } func updateWineInfo(trade *tradeRedis) (uint16, error) { wine := tables.WineTable{Id: trade.Wine} err := wine.Get() if err != nil { utils.Logger.Println("wine get error:", err) return 0, err } wine.Income += uint64(trade.Cash) wine.Order++ err = wine.UpdateSelf() if err != nil { utils.Logger.Println("wine update error:", err) return 0, err } return uint16(50*float64(trade.Weight)/float64(wine.Density)/1000 + 0.5), nil } func updateDeviceInfo(trade *tradeRedis, volume uint16) (string, error) { table := tables.DeviceTable{Id: trade.Device} err := table.Get() if err != nil { utils.Logger.Println("device get error:", err) return "", err } table.Order++ table.Income += uint64(trade.Cash) table.Wines[trade.Cell].Remain -= volume err = table.UpdateSelf() if err != nil { utils.Logger.Println("device update error:", err) return "", err } return table.Manager, nil } func updateManagerInfo(mid string, trade *tradeRedis) error { if mid == "" { utils.Logger.Println("blank manager id") return errors.New("blank manager id") } table := tables.ManagerTable{Id: mid} err := table.Get() if err != nil { utils.Logger.Println("manager get error:", err) return err } table.Order++ table.Income += uint64(trade.Cash) err = table.UpdateSelf() if err != nil { utils.Logger.Println("manager update error:", err) return err } return nil } func WxPayHandler(ctx *gin.Context) { err := downloader.MgrInstance().RegisterDownloaderWithPrivateKey( utils.WxPayCli, utils.WxPrivateKey, utils.WxCertSeq, utils.WxMchId, utils.WxV3Key, ) visitor := downloader.MgrInstance().GetCertificateVisitor(utils.WxMchId) handler, _ := notify.NewRSANotifyHandler(utils.WxV3Key, verifiers.NewSHA256WithRSAVerifier(visitor)) var wxNotify notifyParam _, err = handler.ParseNotifyRequest(utils.WxPayCli, ctx.Request, &wxNotify) if wxNotify.TradeState != "SUCCESS" { utils.Logger.Printf("trade[%s] status[%s]\n", wxNotify.TradeNo, wxNotify.TradeState) ctx.JSON(utils.HttpOk, utils.Success(nil)) return } dbKey := utils.Format("WxPay_%s", wxNotify.TradeNo) exist, err := utils.Redis.Exists(utils.WxPayCli, dbKey).Result() if exist != 1 { utils.Logger.Println("re-notified or expire of:", wxNotify.TradeNo) ctx.JSON(utils.HttpOk, utils.Success(nil)) return } res, err := utils.Redis.Get(utils.WxPayCli, dbKey).Result() var dbTrade tradeRedis err = json.Unmarshal([]byte(res), &dbTrade) utils.Redis.Del(utils.WxPayCli, dbKey) volume, err := updateWineInfo(&dbTrade) manager, err := updateDeviceInfo(&dbTrade, volume) err = updateManagerInfo(manager, &dbTrade) table := tables.TradeTable{ Id: wxNotify.TransactionId, Trade: wxNotify.TradeNo, Device: dbTrade.Device, Payer: wxNotify.Payer.Openid, Wine: dbTrade.Wine, Weight: dbTrade.Weight, Cash: dbTrade.Cash, Manager: manager, } err = table.Insert() if err != nil { ctx.JSON(utils.HttpError, utils.Fail("server error")) return } if device, din := utils.SellerDevices[dbTrade.Device]; din { if device.Online { _ = device.Conn.WriteJSON(utils.WsEvent("qrcodeScanned", nil)) utils.Sleep(1) _ = device.Conn.WriteJSON(utils.WsEvent("orderPayed", volume)) ctx.JSON(utils.HttpOk, utils.Success(nil)) } } ctx.JSON(utils.HttpError, utils.Fail("server error")) } func infoOfDevice(device *tables.DeviceTable, conn *websocket.Conn) { var err error for i := 0; i < 4; i++ { err = device.Wines[i].Get() if err != nil { utils.Logger.Println("Query wine info failed:", err) _ = conn.WriteJSON(utils.WsError("Query wine info failed")) return } } _ = conn.WriteJSON(utils.WsEvent("wineResult", device.Wines)) var advList []tables.AdvertiseTable advList, err = tables.AdvListAll() if err != nil { utils.Logger.Println("Query advertise failed:", err) _ = conn.WriteJSON(utils.WsError("Query advertise failed")) return } _ = conn.WriteJSON(utils.WsEvent("advResult", advList)) var runParams []tables.ParamsTable runParams, err = tables.ParamsListAll() if err != nil { utils.Logger.Println("Query running params failed:", err) _ = conn.WriteJSON(utils.WsError("Query running params failed")) return } _ = conn.WriteJSON(utils.WsEvent("runParamResult", runParams)) _ = conn.WriteJSON(utils.WsEvent("initFinish", nil)) } func keepAlive(conn *websocket.Conn, data any) { _ = conn.WriteJSON(utils.WsEvent("pon", data)) } func getQrcode(device *tables.DeviceTable, conn *websocket.Conn, data any) { var param qrcodeParam err := utils.AnyTrans(data, ¶m) if err != nil { _ = conn.WriteJSON(utils.WsError("param error")) return } wine := tables.WineTable{Id: param.Id} err = wine.Get() if err != nil { utils.Logger.Printf("Query wine[%d] failed: %s\n", param.Id, err) _ = conn.WriteJSON(utils.WsError(utils.Format("no such wine: %d", param.Id))) return } cash := int(param.Weight) * int(wine.Price) if cash != param.Cash { utils.Logger.Printf("got a wrong cash[user: %d, need: %d]\n", param.Cash, cash) _ = conn.WriteJSON(utils.WsError(utils.Format("got a wrong cash[you: %d, real: %d]", param.Cash, cash))) return } _ = device.Get() trade := device.Id + utils.TimeString() store := tradeRedis{Device: device.Id, Cell: param.Cell, Wine: wine.Id, Weight: param.Weight, Cash: cash} marshal, err := json.Marshal(store) if err != nil { utils.Logger.Println("marshal trade failed:", err) _ = conn.WriteJSON(utils.WsError("marshal trade failed")) return } err = utils.Redis.Set(utils.WxPayCli, utils.Format("WxPay_%s", trade), marshal, utils.Duration(1800)).Err() if err != nil { utils.Logger.Println("store trade failed:", err) _ = conn.WriteJSON(utils.WsError("store trade failed")) return } var img []byte img, err = utils.TryWxPay(trade, wine.Name, cash) if err != nil { utils.Logger.Println("access to wxpay failed:", err) _ = conn.WriteJSON(utils.WsError("access to Wechat Pay failed")) return } _ = conn.WriteJSON(utils.WsEvent("qrcodeOkayed", img)) } func checkAuthCode(did string, conn *websocket.Conn, data any) { var param authParam err := utils.AnyTrans(data, ¶m) if err != nil { _ = conn.WriteJSON(utils.WsError("params error")) return } if param.Code != "284655" { _ = conn.WriteJSON(utils.WsEvent("authCodeResult", utils.JsonType{ "type": param.Type, "ok": false, })) return } switch param.Type { case "Changing": // TODO: check redis `${did}_${param.who}_Change` === param.code, query real work _ = conn.WriteJSON(utils.WsEvent("authCodeResult", utils.JsonType{ "type": param.Type, "ok": true, "work": []utils.JsonType{ { "cell": 1, "old": utils.JsonType{"id": 13026, "name": "某一款酒名-1", "remain": 300}, "new": utils.JsonType{"id": 13026, "name": "某一款酒名-1", "remain": 15000}, }, { "cell": 2, "old": utils.JsonType{"id": 13027, "name": "某一款酒名-2", "remain": 286}, "new": utils.JsonType{"id": 13029, "name": "某一款酒名-3", "remain": 15000}, }, { "cell": 3, "old": utils.JsonType{"id": 13027, "name": "某一款酒名-2", "remain": 286}, "new": utils.JsonType{"id": 13029, "name": "某一款酒名-3", "remain": 15000}, }, { "cell": 4, "old": utils.JsonType{"id": 13027, "name": "某一款酒名-2", "remain": 286}, "new": utils.JsonType{"id": 13029, "name": "某一款酒名-3", "remain": 15000}, }, }, })) break case "Fixing": // TODO: check redis `${did}_${param.who}_Fix` === param.code _ = conn.WriteJSON(utils.WsEvent("authCodeResult", utils.JsonType{ "type": param.Type, "ok": true, })) break default: _ = conn.WriteJSON(utils.WsError("unrecognized open type")) } } func openResult(conn *websocket.Conn, data any) { var param resultParam err := utils.AnyTrans(data, ¶m) if err != nil { _ = conn.WriteJSON(utils.WsError("params error")) return } if worker, win := utils.WorkerWss[param.Who]; win { _ = worker.WriteJSON(utils.WsEvent("openResult", utils.JsonType{ "type": param.Type, "result": param.Result, })) return } if debugger, din := utils.DebugWss[param.Who]; din { _ = debugger.WriteJSON(utils.WsEvent("openResult", utils.JsonType{ "type": param.Type, "result": param.Result, })) return } } func workFinished(conn *websocket.Conn, data any) { var param finishParam err := utils.AnyTrans(data, ¶m) if err != nil { _ = conn.WriteJSON(utils.WsError("params error")) return } if worker, win := utils.WorkerWss[param.Who]; win { _ = worker.WriteJSON(utils.WsEvent("workFinished", param.Type)) return } if debugger, din := utils.DebugWss[param.Who]; din { _ = debugger.WriteJSON(utils.WsEvent("workFinished", param.Type)) return } }