From acd49e99a240eaa870ce3645a5e4dcb3fe092cde Mon Sep 17 00:00:00 2001 From: lwl0608 Date: Tue, 19 Mar 2024 17:41:51 +0800 Subject: [PATCH] fix --- app/mix/dao/mysql.go | 2 +- app/mix/service/logic/vas.go | 244 +++++++++++++++++++++++++++++++++- app/mix/service/vasservice.go | 10 +- dbstruct/vas_mysql.go | 11 +- 4 files changed, 255 insertions(+), 12 deletions(-) diff --git a/app/mix/dao/mysql.go b/app/mix/dao/mysql.go index 3f3ee5a5..e6a6ec1c 100644 --- a/app/mix/dao/mysql.go +++ b/app/mix/dao/mysql.go @@ -548,7 +548,7 @@ func (m *Mysql) Get(ctx *gin.Context, tx *sqlx.Tx, id string) (order *dbstruct.C // 待添加微信的订单 func (m *Mysql) GetWaitWechatAddCoinOrders(ctx *gin.Context, tx *sqlx.Tx, mid int64, statusList []int32, offset, limit int) (list []*dbstruct.CoinOrder, err error) { list = make([]*dbstruct.CoinOrder, 0) - sqlStr := fmt.Sprintf("select * from %s where uid=? and product_id=? and order_status in (%s) limit ? offset ?", TableCoinOrder, util.Convert2SqlArr(statusList)) + sqlStr := fmt.Sprintf("select * from %s where uid=? and product_id=? and order_status in (%s) order by ct desc limit ? offset ?", TableCoinOrder, util.Convert2SqlArr(statusList)) if tx != nil { err = tx.SelectContext(ctx, &list, sqlStr, mid, dbstruct.ProductIdContactWechat, limit, offset) } else { diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index 92e4c666..7827f2be 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -2452,6 +2452,10 @@ func (v *Vas) RefundOrder(ctx *gin.Context, req *vasproto.RefundOrderReq) error switch product.Type { case dbstruct.ProductTypeMoneyMembership: return v.refundMembership(ctx, order, req) + case dbstruct.ProductTypeCoins: + return v.refundCoins(ctx, order, req) + case dbstruct.ProductTypeMoneyContact: + return v.refundMoneyContactWechat(ctx, order, req) default: return errors.New("invalid product") } @@ -2702,6 +2706,240 @@ func (v *Vas) refundMembership(ctx *gin.Context, order *dbstruct.Order, req *vas return nil } +func (v *Vas) refundCoins(ctx *gin.Context, order *dbstruct.Order, req *vasproto.RefundOrderReq) error { + switch order.GetOrderStatus() { + case dbstruct.VasOrderStatusNone, dbstruct.VasOrderStatusInit: + return errors.New("订单还未支付,无法退款") + case dbstruct.VasOrderStatusRefund: + return errors.New("已退款,请勿重复操作") + } + + var ( + mid = order.GetMid() + orderId = order.GetID() + ) + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + if order != nil { + _ = v.AddOplogOrder( + ctx, + &dbstruct.OplogOrder{ + OrderId: orderId, + Action: dbstruct.OrderOpLogActionUpdate, + Operator: req.Operator, + Detail: fmt.Sprintf("金币退款"), + BeforeStatus: order.GetOrderStatus(), + AfterStatus: dbstruct.VasOrderStatusRefund, + }, + err, + ) + } + + if err != nil { + logger.Error("global err, req: %v, err: %v", util.ToJson(req), err) + } + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 用户的充值退款记录 + chargeChList, err := v.store.GetChargeCHList(ctx, tx, orderId) + if err != nil { + logger.Error("GetChargeCHList fail, orderId: %v, err: %v", orderId, err) + return err + } + if len(chargeChList) <= 0 || len(chargeChList) > 1 { + err = errors.New("invalid charge ch list") + logger.Error("invalid charge ch list, orderId: %v, err: %v", orderId, err) + return err + } + chargeCh := chargeChList[0] + chargeChNew := &dbstruct.ConsumeHistory{ + Mid: goproto.Int64(chargeCh.GetMid()), + Uid: goproto.Int64(chargeCh.GetUid()), + Did: goproto.String(chargeCh.GetDid()), + Type: goproto.Int32(chargeCh.GetType()), + SType: goproto.Int32(dbstruct.CHSTypeChargeRefundCoins), + TypeId: goproto.String(chargeCh.GetTypeId()), + OrderId: goproto.String(chargeCh.GetOrderId()), + Change: goproto.Int64(-chargeCh.GetChange()), + Ct: goproto.Int64(time.Now().Unix()), + } + err = v.store.CreateConsumeHistory(ctx, tx, chargeChNew) + if err != nil { + logger.Error("CreateConsumeHistory fail, chargeChNew: %v, err: %v", util.ToJson(chargeChNew), err) + return err + } + + // 修改订单状态 xx -> 已退款 + err = v.store.UpdateOrderStatus(ctx, tx, orderId, order.GetOrderStatus(), dbstruct.VasOrderStatusRefund) + if err != nil { + logger.Error("UpdateOrderStatus fail, err: %v", err) + return err + } + + // 扣用户金币 + err = v.store.DecCoins(ctx, tx, mid, util.AbsInt64(chargeCh.GetChange())) + if err != nil { + logger.Error("DecCoins fail, mid: %v, change: %v, err: %v", mid, util.AbsInt64(chargeCh.GetChange()), err) + return err + } + + // 退款 + switch order.GetPayType() { + case vasproto.PayTypeAlipay, vasproto.PayTypeAlipayH5: + alipayCli := alipaycli.GetAlipayClientByAppId(order.GetOid3()) + resp, err := alipayCli.RefundOne(ctx, &alipaycli.RefundOneParam{ + OutTradeNo: orderId, + RefundAmount: order.GetPayAmount(), + RefundReason: "发货A退款", + }) + if err != nil { + logger.Error("alipayCli.RefundOne fail, orderId: %v, resp: %v, err: %v", orderId, util.ToJson(resp), err) + return err + } + case vasproto.PayTypeWxpayNative, vasproto.PayTypeWxpayJsapi, vasproto.PayTypeWxpayH5: + wxpayCli := wxpaycli.GetDefaultWxpayClient() + resp, err := wxpayCli.RefundOne(ctx, &wxpaycli.RefundOneParam{ + OutTradeNo: orderId, + RefundAmount: order.GetPayAmount(), + RefundReason: "发货A退款", + }) + if err != nil { + logger.Error("wxpayCli.RefundOne fail, orderId: %v, resp: %v, err: %v", orderId, util.ToJson(resp), err) + return err + } + } + + return nil +} + +func (v *Vas) refundMoneyContactWechat(ctx *gin.Context, order *dbstruct.Order, req *vasproto.RefundOrderReq) error { + switch order.GetOrderStatus() { + case dbstruct.VasOrderStatusNone, dbstruct.VasOrderStatusInit: + return errors.New("订单还未支付,无法退款") + case dbstruct.VasOrderStatusRefund: + return errors.New("已退款,请勿重复操作") + } + + var ( + mid = order.GetMid() + orderId = order.GetID() + ) + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + if order != nil { + _ = v.AddOplogOrder( + ctx, + &dbstruct.OplogOrder{ + OrderId: orderId, + Action: dbstruct.OrderOpLogActionUpdate, + Operator: req.Operator, + Detail: fmt.Sprintf("微信退款"), + BeforeStatus: order.GetOrderStatus(), + AfterStatus: dbstruct.VasOrderStatusRefund, + }, + err, + ) + } + + if err != nil { + logger.Error("global err, req: %v, err: %v", util.ToJson(req), err) + } + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 用户的充值退款记录 + chargeChList, err := v.store.GetChargeCHList(ctx, tx, orderId) + if err != nil { + logger.Error("GetChargeCHList fail, orderId: %v, err: %v", orderId, err) + return err + } + if len(chargeChList) <= 0 || len(chargeChList) > 1 { + err = errors.New("invalid charge ch list") + logger.Error("invalid charge ch list, orderId: %v, err: %v", orderId, err) + return err + } + chargeCh := chargeChList[0] + chargeChNew := &dbstruct.ConsumeHistory{ + Mid: goproto.Int64(chargeCh.GetMid()), + Uid: goproto.Int64(chargeCh.GetUid()), + Did: goproto.String(chargeCh.GetDid()), + Type: goproto.Int32(chargeCh.GetType()), + SType: goproto.Int32(dbstruct.CHSTypeChargeRefundContactWechat), + TypeId: goproto.String(chargeCh.GetTypeId()), + OrderId: goproto.String(chargeCh.GetOrderId()), + Change: goproto.Int64(-chargeCh.GetChange()), + Ct: goproto.Int64(time.Now().Unix()), + } + err = v.store.CreateConsumeHistory(ctx, tx, chargeChNew) + if err != nil { + logger.Error("CreateConsumeHistory fail, chargeChNew: %v, err: %v", util.ToJson(chargeChNew), err) + return err + } + + // 修改订单状态 xx -> 已退款 + err = v.store.UpdateOrderStatus(ctx, tx, orderId, order.GetOrderStatus(), dbstruct.VasOrderStatusRefund) + if err != nil { + logger.Error("UpdateOrderStatus fail, err: %v", err) + return err + } + + // 扣用户金币 + err = v.store.DecCoins(ctx, tx, mid, util.AbsInt64(chargeCh.GetChange())) + if err != nil { + logger.Error("DecCoins fail, mid: %v, change: %v, err: %v", mid, util.AbsInt64(chargeCh.GetChange()), err) + return err + } + + // 退款 + switch order.GetPayType() { + case vasproto.PayTypeAlipay, vasproto.PayTypeAlipayH5: + alipayCli := alipaycli.GetAlipayClientByAppId(order.GetOid3()) + resp, err := alipayCli.RefundOne(ctx, &alipaycli.RefundOneParam{ + OutTradeNo: orderId, + RefundAmount: order.GetPayAmount(), + RefundReason: "发货A退款", + }) + if err != nil { + logger.Error("alipayCli.RefundOne fail, orderId: %v, resp: %v, err: %v", orderId, util.ToJson(resp), err) + return err + } + case vasproto.PayTypeWxpayNative, vasproto.PayTypeWxpayJsapi, vasproto.PayTypeWxpayH5: + wxpayCli := wxpaycli.GetDefaultWxpayClient() + resp, err := wxpayCli.RefundOne(ctx, &wxpaycli.RefundOneParam{ + OutTradeNo: orderId, + RefundAmount: order.GetPayAmount(), + RefundReason: "发货A退款", + }) + if err != nil { + logger.Error("wxpayCli.RefundOne fail, orderId: %v, resp: %v, err: %v", orderId, util.ToJson(resp), err) + return err + } + } + + return nil +} + // 金币订单退款 func (v *Vas) RefundCoinOrder(ctx *gin.Context, req *vasproto.RefundCoinOrderReq) error { // 获取订单 @@ -2715,13 +2953,13 @@ func (v *Vas) RefundCoinOrder(ctx *gin.Context, req *vasproto.RefundCoinOrderReq switch order.GetProductId() { case dbstruct.ProductIdContactWechat: - return v.refundContactWechat(ctx, order, req) + return v.refundCoinContactWechat(ctx, order, req) default: return errors.New("invalid product") } } -func (v *Vas) refundContactWechat(ctx *gin.Context, order *dbstruct.CoinOrder, req *vasproto.RefundCoinOrderReq) error { +func (v *Vas) refundCoinContactWechat(ctx *gin.Context, order *dbstruct.CoinOrder, req *vasproto.RefundCoinOrderReq) error { switch order.GetOrderStatus() { case dbstruct.VasCoinOrderStatusNone, dbstruct.VasOrderStatusInit: return errors.New("订单还未成功支付,无法退款") @@ -2749,7 +2987,7 @@ func (v *Vas) refundContactWechat(ctx *gin.Context, order *dbstruct.CoinOrder, r OrderId: orderId, Action: dbstruct.OrderOpLogActionUpdate, Operator: req.Operator, - Detail: fmt.Sprintf("微信联系方式"), + Detail: fmt.Sprintf("微信联系方式退款"), BeforeStatus: order.GetOrderStatus(), AfterStatus: dbstruct.VasCoinOrderStatusRefund, }, diff --git a/app/mix/service/vasservice.go b/app/mix/service/vasservice.go index ee0fdbd1..390018cf 100644 --- a/app/mix/service/vasservice.go +++ b/app/mix/service/vasservice.go @@ -282,16 +282,20 @@ func (s *Service) chListCharge(ctx *gin.Context, chList []*dbstruct.ConsumeHisto case dbstruct.CHSTypeChargeOp: item.Desc = "运营充值" item.Change = changeMark + fmt.Sprintf("%d金币", chDB.GetChange()) - case dbstruct.CHSTypeChargeRefund: - item.Desc = "退款" - item.Change = changeMark + fmt.Sprintf("%d金币", chDB.GetChange()) + case dbstruct.CHSTypeChargeRefundCoins: + item.Desc = "金币退款" + item.Change = fmt.Sprintf("%d金币", chDB.GetChange()) case dbstruct.CHSTypeChargeRefundMembership: item.Desc = "会员退款" item.Change = fmt.Sprintf("%d金币", chDB.GetChange()) case dbstruct.CHSTypeChargeMembership: item.Desc = "会员充值" item.Change = changeMark + fmt.Sprintf("%d金币", chDB.GetChange()) + case dbstruct.CHSTypeChargeRefundContactWechat: + item.Desc = "微信联系方式退款" + item.Change = fmt.Sprintf("%d金币", chDB.GetChange()) } + list = append(list, item) } return diff --git a/dbstruct/vas_mysql.go b/dbstruct/vas_mysql.go index 899533fd..04656f05 100644 --- a/dbstruct/vas_mysql.go +++ b/dbstruct/vas_mysql.go @@ -495,11 +495,12 @@ const ( CHSTypeCostMembership = 10003 // 消费明细,会员资格解锁(伪金币记录,会员资格解锁中间无转金币过程) CHSTypeCostRefundMembership = 10004 // 消费明细,会员资格解锁退款(伪金币记录,会员资格解锁中间无转金币过程) - CHSTypeChargeUser = 20001 // 充值明细,用户自己冲 - CHSTypeChargeOp = 20002 // 充值明细,OP充值 - CHSTypeChargeRefund = 20003 // 充值明细,现金退款 - CHSTypeChargeRefundMembership = 20004 // 充值明细,会员退款 - CHSTypeChargeMembership = 20005 // 充值明细,会员充值 + CHSTypeChargeUser = 20001 // 充值明细,用户自己冲 + CHSTypeChargeOp = 20002 // 充值明细,OP充值 + CHSTypeChargeRefundCoins = 20003 // 充值明细,金币退款 + CHSTypeChargeRefundMembership = 20004 // 充值明细,会员退款 + CHSTypeChargeMembership = 20005 // 充值明细,会员充值 + CHSTypeChargeRefundContactWechat = 20006 // 充值明细,微信金币退款 CHSTypeIncomeContact = 30001 // 收入明细,联系方式 CHSTypeIncomeInvite = 30002 // 收入明细,邀请分成