From 8bf8e9357f28cece6ce7a55ee4bb20c4b2a84307 Mon Sep 17 00:00:00 2001 From: lwl0608 Date: Tue, 4 Jun 2024 17:44:06 +0800 Subject: [PATCH] create order. add paytype: coin --- api/proto/vas/proto/pay.go | 2 + app/mix/service/logic/vas.go | 153 +++++++++++++++++++++++++++++----- app/mix/service/vasservice.go | 2 +- dbstruct/product.go | 4 + 4 files changed, 137 insertions(+), 24 deletions(-) diff --git a/api/proto/vas/proto/pay.go b/api/proto/vas/proto/pay.go index 4fb2ac20..dfa22391 100644 --- a/api/proto/vas/proto/pay.go +++ b/api/proto/vas/proto/pay.go @@ -32,11 +32,13 @@ const ( PayTypeWxpayNative = "wxpay_native" // 微信 native PayTypeWxpayJsapi = "wxpay_jsapi" // 微信 jsapi PayTypeWxpayH5 = "wxpay_h5" // 微信支付 h5 + PayTypeCoin = "coin" // 金币支付 ) const ( CallBackPayTypeAlipay = "alipay" CallBackPayTypeWxpay = "wxpay" + CallBackPayTypeCoin = "coin" ) const ( diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index f68f680e..abad884e 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -296,6 +296,8 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data return } req.Oid3 = wxpayCli.AppId + case vasproto.PayTypeCoin: + return v.CreateOrderByCoin(ctx, req, product) } // 添加订单 @@ -344,6 +346,110 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data return } +func (v *Vas) CreateOrderByCoin(ctx *gin.Context, req *vasproto.CreateOrderReq, product *dbstruct.Product) (data *vasproto.CreateOrderData, err error) { + var ( + order *dbstruct.Order + orderId = idgenerator.GenOrderId() // 订单id + priceCoin = product.GetRealPriceCoin() + ) + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return nil, err + } + defer func() { + if err != nil { + logger.Error("global err, req: %v, order: %v, err: %v", util.ToJson(req), util.ToJson(order), err) + } + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 检查钱包 + wallet, exists := v.CheckWalletExist(ctx, tx, req.Mid) + if !exists { + err = errs.ErrVasWalletNotExist + logger.Error("CheckWalletExist fail, mid: %v, err: %v", req.Mid, err) + return + } + if wallet.GetCoins() <= priceCoin { + err = errs.ErrVasNoEnoughCoin + logger.Error("not enough coin, mid: %v, coins: %v, err: %v", req.Mid, wallet.Coins, err) + return + } + + // 扣金币 + err = v.store.DecCoins(ctx, tx, req.Mid, priceCoin) + if err != nil { + logger.Error("DecCoins fail, mid: %v, priceCoin: %v, err: %v", req.Mid, priceCoin, err) + return + } + + // 添加订单 + var ( + timeNow = time.Now().Unix() + ) + order = &dbstruct.Order{ + ID: goproto.String(orderId), + Mid: goproto.Int64(req.Mid), + Uid: goproto.Int64(req.Uid), + Oid1: goproto.String(req.Oid1), + Oid2: goproto.String(req.Oid2), + Oid3: goproto.String(req.Oid3), + ProductId: goproto.String(req.ProductId), + PayType: goproto.String(req.PayType), + PayAmount: goproto.Int64(product.RealPrice), + Coins: goproto.Int64(product.ValueCoins), + OrderStatus: goproto.Int32(dbstruct.VasOrderStatusInit), + OrderFrom: goproto.String(req.From), + Ct: goproto.Int64(timeNow), + Ut: goproto.Int64(timeNow), + Operator: goproto.String(req.Operator), + Did: goproto.String(req.Did), + Version: goproto.String(req.Version), + OsVersion: goproto.String(req.Version), + DevType: goproto.Int32(req.DevType), + Channel: goproto.String(req.Channel), + Model: goproto.String(req.Model), + NetType: goproto.String(req.NetType), + Ip: goproto.String(req.Ip), + } + err = v.store.CreateOrder(ctx, tx, order) + if err != nil { + logger.Error("CreateOrder fail, order: %v, err: %v", util.ToJson(order), err) + return + } + + // 提交事务 + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + err = errTx + return + } + + // 手动回调 + err = v.PayCallback(ctx, &vasproto.PayCallbackParamIn{ + OrderId: orderId, + OutOrderId: fmt.Sprintf("%s_bycoin", orderId), + CallbackPayType: vasproto.CallBackPayTypeCoin, + }) + if err != nil { + logger.Error("PayCallback fail, err: %v", err) + return + } + + data = &vasproto.CreateOrderData{ + OrderId: orderId, + } + return +} + func (v *Vas) CheckWalletExist(ctx *gin.Context, tx *sqlx.Tx, mid int64) (wallet *dbstruct.Wallet, exist bool) { wallet, err := v.store.GetWalletByMid(ctx, tx, mid) switch err { @@ -1249,7 +1355,7 @@ func (v *Vas) GetUserWechatUnlock(ctx *gin.Context, mid, uid int64) (uu *dbstruc } // 【支付】回调 -func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { +func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) (err error) { var ( orderId = p.OrderId outOrderId = p.OutOrderId @@ -1261,16 +1367,16 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { checkOrder, err := v.store.GetOrderById(ctx, nil, orderId) if err != nil { logger.Error("GetOrderById fail, p: %v, err: %v", util.ToJson(p), err) - return + return err } if checkOrder == nil { logger.Warn("GetOrderById nil, p: %v", util.ToJson(p)) - return + return err } // 是否已处理过的订单 if checkOrder.GetOrderStatus() != dbstruct.VasOrderStatusInit { logger.Error("repeat deal, p: %v", util.ToJson(p)) - return + return err } // out_order_id检查 @@ -1281,29 +1387,29 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { } if err != nil { logger.Error("GetOrderByOutOrderId fail, p: %v, err: %v", util.ToJson(p), err) - return + return err } if outOrder != nil { logger.Error("out order exists, p: %v", util.ToJson(p)) - return + return err } // 获取商品 product, err := v.store.GetProductById(ctx, checkOrder.GetProductId()) if err != nil { logger.Error("GetProductById fail, id: %v, err: %v", checkOrder.GetProductId(), err) - return + return err } if product == nil { logger.Error("GetProductById nil, id: %v", checkOrder.GetProductId()) - return + return err } // 钱包 _, hasWallet := v.CheckWalletExist(ctx, nil, checkOrder.GetMid()) if !hasWallet { logger.Error("CheckWalletExist fail, mid: %v", checkOrder.GetMid()) - return + return err } // 解锁信息 @@ -1313,7 +1419,7 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { _, hasZoneUnlock := v.CheckZoneUnlockExist(ctx, nil, mid, zid) if !hasZoneUnlock { logger.Error("CheckZoneUnlockExist fail, mid: %v, zid: %v", mid, zid) - return + return err } } @@ -1321,7 +1427,7 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { tx, err := v.store.VasBegin(ctx) if err != nil { logger.Error("vas begin fail, err: %v", err) - return + return err } defer func() { _ = v.AddOplogOrder( @@ -1368,7 +1474,7 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { order, err := v.store.GetOrderByIdForUpdate(ctx, tx, orderId) if err != nil { logger.Error("GetOrderByIdForUpdate fail, p: %v", util.ToJson(p)) - return + return err } // 锁住钱包 @@ -1403,14 +1509,14 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { err = v.store.CreateConsumeHistory(ctx, tx, ch) if err != nil { logger.Error("CreateConsumeHistory fail, ch: %v, err: %v", util.ToJson(ch), err) - return + return err } // 更新状态 err = v.store.UpdateOrderStatus(ctx, tx, orderId, dbstruct.VasOrderStatusInit, dbstruct.VasOrderStatusPaySuccess) if err != nil { logger.Error("UpdateOrderStatus fail, p: %v", util.ToJson(p)) - return + return err } afterStatus = dbstruct.VasOrderStatusPaySuccess @@ -1418,7 +1524,7 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { err = v.store.UpdateOutOrderId(ctx, tx, orderId, outOrderId) if err != nil { logger.Error("UpdateOutOrderId fail, p: %v", util.ToJson(p)) - return + return err } // 商品判断 @@ -1428,12 +1534,12 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { err = v.store.IncCoins(ctx, tx, order.GetMid(), order.GetCoins()) if err != nil { logger.Error("IncCoins fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } err = v.store.UpdateOrderStatus(ctx, tx, orderId, dbstruct.VasOrderStatusPaySuccess, dbstruct.VasOrderStatusFinish) if err != nil { logger.Error("UpdateOrderStatus fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } afterStatus = dbstruct.VasOrderStatusFinish case product.Id == dbstruct.ProductIdH5ContactWechat: @@ -1441,32 +1547,32 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { err = v.store.IncCoins(ctx, tx, order.GetMid(), order.GetCoins()) if err != nil { logger.Error("IncCoins fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } case product.Id == dbstruct.ProductIdMembership: // 解锁会员资格 _, err = v.UnlockMembership(ctx, tx, util.DerefInt64(order.Mid), product, order, wallet) if err != nil { logger.Error("UnlockMembership fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } case product.Id == dbstruct.ProductIdH5ZoneMoment: err = v.UnlockZoneMoment(ctx, tx, order) if err != nil { logger.Error("UnlockZoneMoment fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } case product.Id == dbstruct.ProductIdH5ZoneAdmission: err = v.UnlockZoneAdmission(ctx, tx, order, dbstruct.ZoneUnlockTypePay) if err != nil { logger.Error("UnlockZoneAdmission fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } case product.Id == dbstruct.ProductIdH5ZoneSuperfanship: err = v.UnlockZoneSuperfanship(ctx, tx, order, dbstruct.ZoneUnlockTypePay) if err != nil { logger.Error("UnlockZoneSuperfanship fail, order: %v, err: %v", util.ToJson(order), err) - return + return err } } @@ -1474,8 +1580,9 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) { _err := v.UnlockZoneIronfanshipReachConsume(ctx, tx, order.GetMid(), order.GetZid(), order.GetUid()) if _err != nil { logger.Error("UnlockZoneIronfanshipReachConsume fail, order: %v, err: %v", util.ToJson(order), _err) - return + return err } + return err } func (v *Vas) GetCoinOrderById(ctx *gin.Context, id string) (*dbstruct.CoinOrder, error) { diff --git a/app/mix/service/vasservice.go b/app/mix/service/vasservice.go index d242e824..63eaa94e 100644 --- a/app/mix/service/vasservice.go +++ b/app/mix/service/vasservice.go @@ -499,7 +499,7 @@ func (s *Service) H5DirectUnlockWechat(ctx *gin.Context, req *vasproto.H5DirectU // 支付回调 func (s *Service) PayCallback(ctx *gin.Context, req *vasproto.PayCallbackParamIn) (data *vasproto.H5DirectUnlockWechatData, ec errcode.ErrCode) { - _DefaultVas.PayCallback(ctx, req) + _ = _DefaultVas.PayCallback(ctx, req) return } diff --git a/dbstruct/product.go b/dbstruct/product.go index ac87fb1c..936eb208 100644 --- a/dbstruct/product.go +++ b/dbstruct/product.go @@ -96,3 +96,7 @@ type Product struct { Images []*ToCImage `json:"images"` Videos []*ToCVideo `json:"videos"` } + +func (p Product) GetRealPriceCoin() int64 { + return p.RealPrice / 10 +}