From 571a961151b01488358246c99c02e85f58f67da3 Mon Sep 17 00:00:00 2001 From: lwl0608 Date: Thu, 13 Jun 2024 16:40:22 +0800 Subject: [PATCH] apple --- api/proto/zone/proto/zone_vo_api.go | 3 + .../zonemoment/proto/zonemoment_vo_api.go | 1 + app/mix/controller/vas.go | 7 ++ app/mix/controller/zone_vas_api.go | 7 ++ app/mix/service/logic/vas.go | 30 ++++--- app/mix/service/logic/vas_zone.go | 15 +++- app/mix/service/service.go | 1 + app/mix/service/utilservice.go | 2 + app/mix/service/vasservice.go | 78 +++++++++++-------- bizcommon/util/util.go | 4 + bizcommon/util/x_test.go | 7 ++ dbstruct/product.go | 11 ++- dbstruct/vas_mongo.go | 17 +++- dbstruct/zonemoment.go | 6 ++ library/payclients/applepaycli/proto.go | 4 + main.go | 9 +++ 16 files changed, 155 insertions(+), 47 deletions(-) create mode 100644 bizcommon/util/x_test.go diff --git a/api/proto/zone/proto/zone_vo_api.go b/api/proto/zone/proto/zone_vo_api.go index c50e7303..8d87fdd5 100644 --- a/api/proto/zone/proto/zone_vo_api.go +++ b/api/proto/zone/proto/zone_vo_api.go @@ -58,9 +58,12 @@ func (vo *ApiZoneVO) SetIsSuperfanshipUnlocked(is_superfanship_unlocked int64) { func (vo *ApiZoneVO) CopyZoneVas(zv *dbstruct.ZoneVas) { if zv != nil { vo.AdmissionPrice = zv.AdmissionPrice + vo.AdmissionCoinPrice = zv.GetAdmissionCoinPrice() vo.IronfanshipPrice = zv.IronfanshipPrice + vo.IronfanshipCoinPrice = zv.GetIronfanshipCoinPrice() vo.IsSuperfanshipEnabled = zv.IsSuperfanshipEnabled vo.SuperfanshipPrice = zv.SuperfanshipPrice + vo.SuperfanshipCoinPrice = zv.GetSuperfanshipCoinPrice() vo.SuperfanshipValidPeriod = zv.SuperfanshipValidPeriod vo.IsSuperfanshipGiveWechat = zv.IsSuperfanshipGiveWechat } diff --git a/api/proto/zonemoment/proto/zonemoment_vo_api.go b/api/proto/zonemoment/proto/zonemoment_vo_api.go index 9f5afae6..4d766772 100644 --- a/api/proto/zonemoment/proto/zonemoment_vo_api.go +++ b/api/proto/zonemoment/proto/zonemoment_vo_api.go @@ -15,6 +15,7 @@ type ApiZoneMomentVO struct { IsZoneMomentUnlocked int64 `json:"is_zone_moment_unlocked"` Expenditure int64 `json:"expenditure"` IronfanshipPrice int64 `json:"ironfanship_price"` + IronfanshipCoinPrice int64 `json:"ironfanship_coin_price"` BuyerCnt int64 `json:"buyer_cnt"` // 动态购买人数 IsSuperfanshipEnabled int64 `json:"is_superfanship_enabled"` } diff --git a/app/mix/controller/vas.go b/app/mix/controller/vas.go index 840ada60..7261b82e 100644 --- a/app/mix/controller/vas.go +++ b/app/mix/controller/vas.go @@ -6,6 +6,7 @@ import ( "service/app/mix/service" "service/bizcommon/common" "service/bizcommon/util" + "service/dbstruct" "service/library/logger" "time" @@ -50,6 +51,12 @@ func CreateOrder(ctx *gin.Context) { ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) return } + // 检查能用金币支付的商品 + if req.PayType == vasproto.PayTypeCoin && !dbstruct.CoinPayValidProductIdMap[req.ProductId] { + ReplyErrorMsg(ctx, "商品错误") + return + } + data, ec, err := service.DefaultService.CreateOrder(ctx, req) if ec != errcode.ErrCodeVasSrvOk { logger.Error("CreateOrder fail, req: %v, ec: %v", util.ToJson(req), ec) diff --git a/app/mix/controller/zone_vas_api.go b/app/mix/controller/zone_vas_api.go index b0dec7e4..c0eb0809 100644 --- a/app/mix/controller/zone_vas_api.go +++ b/app/mix/controller/zone_vas_api.go @@ -6,6 +6,7 @@ import ( vasproto "service/api/proto/vas/proto" "service/app/mix/service" "service/bizcommon/util" + "service/dbstruct" "service/library/logger" ) @@ -16,6 +17,12 @@ func ZoneCreateOrder(ctx *gin.Context) { ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) return } + // 检查能用金币支付的商品 + if req.PayType == vasproto.PayTypeCoin && !dbstruct.CoinPayValidProductIdMap[req.ProductId] { + ReplyErrorMsg(ctx, "商品错误") + return + } + data, ec, err := service.DefaultService.ZoneCreateOrder(ctx, req) if ec != errcode.ErrCodeVasSrvOk { logger.Error("ZoneCreateOrder fail, req: %v, ec: %v", util.ToJson(req), ec) diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index dc2835bb..9b45db1e 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -377,7 +377,7 @@ func (v *Vas) CreateOrderByCoin(ctx *gin.Context, req *vasproto.CreateOrderReq, logger.Error("CheckWalletExist fail, mid: %v, err: %v", req.Mid, err) return } - if wallet.GetCoins() <= priceCoin { + if wallet.GetCoins() < priceCoin { err = errs.ErrVasNoEnoughCoin logger.Error("not enough coin, mid: %v, coins: %v, err: %v", req.Mid, wallet.Coins, err) return @@ -403,7 +403,7 @@ func (v *Vas) CreateOrderByCoin(ctx *gin.Context, req *vasproto.CreateOrderReq, Oid3: goproto.String(req.Oid3), ProductId: goproto.String(req.ProductId), PayType: goproto.String(req.PayType), - PayAmount: goproto.Int64(product.RealPrice), + PayAmount: goproto.Int64(priceCoin), Coins: goproto.Int64(product.ValueCoins), OrderStatus: goproto.Int32(dbstruct.VasOrderStatusInit), OrderFrom: goproto.String(req.From), @@ -1493,6 +1493,9 @@ func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) erro Count: goproto.Int64(order.GetCoins()), Ct: goproto.Int64(time.Now().Unix()), } + if order.GetPayType() == vasproto.PayTypeCoin { + ch.TypeId = goproto.String(ch.GetTypeId() + ":_:pay_type=coin") + } switch product.Id { case dbstruct.ProductIdMembership: ch.SType = goproto.Int32(dbstruct.CHSTypeChargeMembership) @@ -2212,6 +2215,9 @@ func (v *Vas) UnlockMembership(ctx *gin.Context, tx *sqlx.Tx, mid int64, product // 计算收入 var totalDias = int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + if order.GetPayType() == vasproto.PayTypeCoin { + totalDias = order.GetPayAmount() + } incomeList, err := v.calcAndUpdateIncome(ctx, tx, order.GetUid(), mid, order.GetDid(), orderId, order.GetProductId(), totalDias, dbstruct.CHSTypeIncomeMembership) if err != nil { logger.Error("calcAndUpdateIncome fail, order: %v, err: %v", util.ToJson(order), err) @@ -2544,7 +2550,7 @@ func (v *Vas) refundMembership(ctx *gin.Context, order *dbstruct.Order, req *vas } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -2642,7 +2648,7 @@ func (v *Vas) refundCoins(ctx *gin.Context, order *dbstruct.Order, req *vasproto } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -2740,7 +2746,7 @@ func (v *Vas) refundMoneyContactWechat(ctx *gin.Context, order *dbstruct.Order, } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -2966,7 +2972,7 @@ func (v *Vas) refundZoneAdmission(ctx *gin.Context, order *dbstruct.Order, req * } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -3193,7 +3199,7 @@ func (v *Vas) refundZoneMoment(ctx *gin.Context, order *dbstruct.Order, req *vas } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -3429,7 +3435,7 @@ func (v *Vas) refundZoneSuperfanship(ctx *gin.Context, order *dbstruct.Order, re } // 退款 - err = v.payRefund(ctx, order) + err = v.payRefund(ctx, tx, order) if err != nil { return err } @@ -3652,7 +3658,7 @@ func (v *Vas) refundCoinContactWechat(ctx *gin.Context, order *dbstruct.CoinOrde return nil } -func (v *Vas) payRefund(ctx *gin.Context, order *dbstruct.Order) error { +func (v *Vas) payRefund(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct.Order) error { var ( orderId = order.GetID() ) @@ -3679,6 +3685,12 @@ func (v *Vas) payRefund(ctx *gin.Context, order *dbstruct.Order) error { logger.Error("wxpayCli.RefundOne fail, orderId: %v, resp: %v, err: %v", orderId, util.ToJson(resp), err) return err } + case vasproto.PayTypeCoin: + err := v.store.IncCoins(ctx, tx, order.GetMid(), order.GetPayAmount()) + if err != nil { + logger.Error("coin.RefundOne fail, orderId: %v, err: %v", orderId, err) + return err + } } return nil } diff --git a/app/mix/service/logic/vas_zone.go b/app/mix/service/logic/vas_zone.go index 816398ee..386b279e 100644 --- a/app/mix/service/logic/vas_zone.go +++ b/app/mix/service/logic/vas_zone.go @@ -291,7 +291,10 @@ func (v *Vas) UnlockZoneMoment(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct.Or } // 计算收入 - totalDias := int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + var totalDias = int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + if order.GetPayType() == vasproto.PayTypeCoin { + totalDias = order.GetPayAmount() + } incomeList, err := v.calcAndUpdateIncome(ctx, tx, order.GetUid(), mid, order.GetDid(), orderId, order.GetProductId(), totalDias, dbstruct.CHSTypeIncomeZoneStreamer) if err != nil { logger.Error("calcAndUpdateIncome fail, order: %v, err: %v", util.ToJson(order), err) @@ -371,7 +374,10 @@ func (v *Vas) UnlockZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct } // 计算收入 - totalDias := int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + var totalDias = int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + if order.GetPayType() == vasproto.PayTypeCoin { + totalDias = order.GetPayAmount() + } incomeList, err := v.calcAndUpdateIncome(ctx, tx, order.GetUid(), mid, order.GetDid(), orderId, order.GetProductId(), totalDias, dbstruct.CHSTypeIncomeZoneStreamer) if err != nil { logger.Error("calcAndUpdateIncome fail, order: %v, err: %v", util.ToJson(order), err) @@ -421,7 +427,10 @@ func (v *Vas) UnlockZoneSuperfanship(ctx *gin.Context, tx *sqlx.Tx, order *dbstr } // 计算收入 - totalDias := int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + var totalDias = int64(float64(order.GetPayAmount()) / 100.0 * 10.0) + if order.GetPayType() == vasproto.PayTypeCoin { + totalDias = order.GetPayAmount() + } incomeList, err := v.calcAndUpdateIncome(ctx, tx, order.GetUid(), mid, order.GetDid(), orderId, order.GetProductId(), totalDias, dbstruct.CHSTypeIncomeZoneStreamer) if err != nil { logger.Error("calcAndUpdateIncome fail, order: %v, err: %v", util.ToJson(order), err) diff --git a/app/mix/service/service.go b/app/mix/service/service.go index 01a5afad..e53e67fc 100644 --- a/app/mix/service/service.go +++ b/app/mix/service/service.go @@ -1021,6 +1021,7 @@ func (s *Service) GetMembershipProductList(ctx *gin.Context, req *vasproto.GetMe ec = errcode.ErrCodeVasSrvFail return } + product.RealCoinPrice = product.GetRealPriceCoin() data = &vasproto.GetMembershipProductListData{ Product: product, } diff --git a/app/mix/service/utilservice.go b/app/mix/service/utilservice.go index ed4a7918..00f43e78 100644 --- a/app/mix/service/utilservice.go +++ b/app/mix/service/utilservice.go @@ -1843,6 +1843,7 @@ func (s *Service) utilFillZoneMomentsWithApiVOInfo(ctx *gin.Context, list []*dbs // 7.填充所有信息 for _, vo := range volist { + vo.ZoneMoment.CoinPrice = vo.ZoneMoment.GetCoinPrice() zid := vo.ZoneMoment.GetZid() @@ -1886,6 +1887,7 @@ func (s *Service) utilFillZoneMomentsWithApiVOInfo(ctx *gin.Context, list []*dbs // 铁粉价格 if zv, ok := zvMap[zid]; ok { vo.IronfanshipPrice = zv.IronfanshipPrice + vo.IronfanshipCoinPrice = zv.GetIronfanshipCoinPrice() vo.IsSuperfanshipEnabled = int64(zv.IsSuperfanshipEnabled) } } diff --git a/app/mix/service/vasservice.go b/app/mix/service/vasservice.go index 0ea43787..6898627a 100644 --- a/app/mix/service/vasservice.go +++ b/app/mix/service/vasservice.go @@ -18,6 +18,7 @@ import ( "service/library/mycrypto" "service/library/payclients/applepaycli" "strconv" + "strings" "github.com/gin-gonic/gin" ) @@ -317,6 +318,14 @@ func (s *Service) chListCharge(ctx *gin.Context, chList []*dbstruct.ConsumeHisto item.Desc = "解锁空间超粉退款" item.Change = fmt.Sprintf("+%.1f元", float64(util.AbsInt64(chDB.GetChange()))/100.0) } + if strings.Contains(chDB.GetTypeId(), ":_:pay_type=coin") && strings.Contains(item.Change, "元") { + oldChange := item.Change + newChange := "" + if len(item.Change) > 0 { + newChange += oldChange[:1] + } + newChange += fmt.Sprintf("%d金币", chDB.GetChange()) + } list = append(list, item) } @@ -1090,41 +1099,44 @@ func (s *Service) ApplepayCallback(ctx *gin.Context, notify applepaycli.Applepay mid, _ = strconv.ParseInt(event.AppUserID, 10, 64) ) - // 验证用户 - acnt, _ := _DefaultAccount.GetAccountMapByMids(ctx, []int64{mid}) - if _, ok := acnt[mid]; !ok { - err := fmt.Errorf("invalid user") - logger.Error("ApplepayCallback fail, invalid user, mid: %v, notify: %v", mid, notify) - return err - } + switch event.Type { + case applepaycli.NotifyTypeNonRenewingPurchase: + // 验证用户 + acnt, _ := _DefaultAccount.GetAccountMapByMids(ctx, []int64{mid}) + if _, ok := acnt[mid]; !ok { + err := fmt.Errorf("invalid user") + logger.Error("ApplepayCallback fail, invalid user, mid: %v, notify: %v", mid, notify) + return err + } - // 先创建订单 - createOrderParam := &vasproto.CreateOrderReq{ - BaseRequest: base.BaseRequest{ - Mid: mid, - DevType: common.DeviceTypeIos, - }, - ProductId: event.ProductID, - PayType: vasproto.PayTypeCoin, - Oid3: event.AppID, - } - data, err := _DefaultVas.CreateOrder(ctx, createOrderParam) - if err != nil { - logger.Error("CreateOrder fail, param: %v, err: %v", createOrderParam, err) - return err - } - orderId := data.OrderId + // 先创建订单 + createOrderParam := &vasproto.CreateOrderReq{ + BaseRequest: base.BaseRequest{ + Mid: mid, + DevType: common.DeviceTypeIos, + }, + ProductId: event.ProductID, + PayType: vasproto.PayTypeCoin, + Oid3: event.AppID, + } + data, err := _DefaultVas.CreateOrder(ctx, createOrderParam) + if err != nil { + logger.Error("CreateOrder fail, param: %v, err: %v", createOrderParam, err) + return err + } + orderId := data.OrderId - // 手动回调 - payCallbackParam := &vasproto.PayCallbackParamIn{ - OrderId: orderId, - OutOrderId: event.TransactionID, - CallbackPayType: vasproto.CallBackPayTypeApplepay, - } - err = _DefaultVas.PayCallback(ctx, payCallbackParam) - if err != nil { - logger.Error("PayCallback fail, param: %v, err: %v", payCallbackParam, err) - return err + // 手动回调 + payCallbackParam := &vasproto.PayCallbackParamIn{ + OrderId: orderId, + OutOrderId: event.TransactionID, + CallbackPayType: vasproto.CallBackPayTypeApplepay, + } + err = _DefaultVas.PayCallback(ctx, payCallbackParam) + if err != nil { + logger.Error("PayCallback fail, param: %v, err: %v", payCallbackParam, err) + return err + } } return nil diff --git a/bizcommon/util/util.go b/bizcommon/util/util.go index bc694380..bf7bcab4 100644 --- a/bizcommon/util/util.go +++ b/bizcommon/util/util.go @@ -190,3 +190,7 @@ func VerisonCompare(ver1 string, ver2 string) (bool, error) { } return false, nil } + +func RoundUp(num float64) int64 { + return int64(math.Ceil(num)) +} diff --git a/bizcommon/util/x_test.go b/bizcommon/util/x_test.go new file mode 100644 index 00000000..c2d66fe5 --- /dev/null +++ b/bizcommon/util/x_test.go @@ -0,0 +1,7 @@ +package util + +import "testing" + +func TestRound(t *testing.T) { + Round() +} diff --git a/dbstruct/product.go b/dbstruct/product.go index 936eb208..45c4218b 100644 --- a/dbstruct/product.go +++ b/dbstruct/product.go @@ -1,5 +1,7 @@ package dbstruct +import "service/bizcommon/util" + // 商品id const ( ProductIdOpCoin = "op_coin" // op充值的金币 @@ -50,6 +52,13 @@ var ProductIdDescMap = map[string]string{ ProductIdH5ZoneSuperfanship: "解锁超粉", } +var CoinPayValidProductIdMap = map[string]bool{ + ProductIdMembership: true, + ProductIdH5ZoneMoment: true, + ProductIdH5ZoneAdmission: true, + ProductIdH5ZoneSuperfanship: true, +} + // 商品类型 const ( ProductTypeCoins = "coins" // 商品类型:金币 @@ -98,5 +107,5 @@ type Product struct { } func (p Product) GetRealPriceCoin() int64 { - return p.RealPrice / 10 + return util.RoundUp(float64(p.RealPrice) / 10.0) } diff --git a/dbstruct/vas_mongo.go b/dbstruct/vas_mongo.go index b7a86e3d..a8cf801e 100644 --- a/dbstruct/vas_mongo.go +++ b/dbstruct/vas_mongo.go @@ -1,6 +1,9 @@ package dbstruct -import "math" +import ( + "math" + "service/bizcommon/util" +) // 用户增值信息 const ( @@ -122,6 +125,18 @@ func (p ZoneVas) GetSuperfanshipDurationDesc() string { } } +func (p ZoneVas) GetAdmissionCoinPrice() int64 { + return util.RoundUp(float64(p.AdmissionPrice) / 10.0) +} + +func (p ZoneVas) GetIronfanshipCoinPrice() int64 { + return util.RoundUp(float64(p.IronfanshipPrice) / 10.0) +} + +func (p ZoneVas) GetSuperfanshipCoinPrice() int64 { + return util.RoundUp(float64(p.SuperfanshipPrice) / 10.0) +} + // 空间动态价格 type ZoneMomentPrice struct { MomentId int64 `json:"id" bson:"_id"` // 动态id diff --git a/dbstruct/zonemoment.go b/dbstruct/zonemoment.go index 49230ad0..21119699 100644 --- a/dbstruct/zonemoment.go +++ b/dbstruct/zonemoment.go @@ -1,5 +1,7 @@ package dbstruct +import "service/bizcommon/util" + type ZoneMoment struct { Id *int64 `json:"id" bson:"_id"` // 私密圈动态表id Mid *int64 `json:"mid" bson:"mid"` // 用户表id @@ -117,3 +119,7 @@ func (p *ZoneMoment) GetPaidText() string { } return "" } + +func (p *ZoneMoment) GetCoinPrice() int64 { + return util.RoundUp(float64(p.CoinPrice) / 10.0) +} diff --git a/library/payclients/applepaycli/proto.go b/library/payclients/applepaycli/proto.go index 096ad312..000d5398 100644 --- a/library/payclients/applepaycli/proto.go +++ b/library/payclients/applepaycli/proto.go @@ -1,5 +1,9 @@ package applepaycli +const ( + NotifyTypeNonRenewingPurchase = "NON_RENEWING_PURCHASE" // 非续费型消费 +) + type Event struct { EventTimestampMs int64 `json:"event_timestamp_ms"` ProductID string `json:"product_id"` diff --git a/main.go b/main.go index f0aaf4e6..196316ae 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,15 @@ type C struct { } func main() { + numbers := []float64{12.9, 99.9} + + for _, number := range numbers { + rounded := util.RoundUp(number) + fmt.Printf("%.1f -> %d\n", number, rounded) + } + + return + c := C{ A: &A{Mid: 111}, B: &B{Mid: 222},