diff --git a/api/proto/vas/proto/vas.go b/api/proto/vas/proto/vas.go index b5596383..ad0b3c16 100644 --- a/api/proto/vas/proto/vas.go +++ b/api/proto/vas/proto/vas.go @@ -120,6 +120,7 @@ type WithdrawApplyData struct { // 空间收银台 type ZoneGetCashierReq struct { + base.BaseRequest Zid int64 `json:"zid"` // 空间id MomentId int64 `json:"moment_id"` // 动态id ProductId string `json:"product_id"` // 商品id,ProductIdH5Zone* @@ -130,6 +131,7 @@ type ZoneGetCashierData struct { Price int64 `json:"price"` // 价格,单位: 分 Validity string `json:"validity"` // 有效期,直接展示就行,"30天"、"永久" IsSuperfanshipGiveWechat int `json:"is_superfanship_give_wechat"` // 是否开启超粉空间赠送微信 0: 不赠送, 1: 赠送 + HasBought int `json:"has_bought"` // 是否购买过, 0: 没购买过,1: 已经买了 } type ZoneGetCashierResp struct { diff --git a/api/proto/zone/proto/zone_api.go b/api/proto/zone/proto/zone_api.go index 9acdf197..f7e93011 100644 --- a/api/proto/zone/proto/zone_api.go +++ b/api/proto/zone/proto/zone_api.go @@ -103,11 +103,17 @@ type ApiListByMidReq struct { Limit int `json:"limit"` } +const ( + AdmissionRefundStatusRefunding = 1 // 退款中 + AdmissionRefundStatusFinish = 2 // 已退款 +) + type ApiListByMidData struct { List []*ApiZoneVO `json:"list"` Offset int `json:"offset"` More int `json:"more"` RefundEnable int `json:"refund_enable"` // 1: 能退款,0: 不能退款 + RefundStatus int `json:"refund_status"` // 退款状态, AdmissionRefundStatus* } type ApiListByMidResp struct { diff --git a/app/mix/controller/zone_api.go b/app/mix/controller/zone_api.go index 4c9d6501..13727922 100644 --- a/app/mix/controller/zone_api.go +++ b/app/mix/controller/zone_api.go @@ -151,7 +151,7 @@ func ApiGetZoneListByUserIdFromOutside(ctx *gin.Context) { req.Limit = consts.DefaultPageSize } - refundEnable, list, ec := service.DefaultService.ApiGetZoneListByUserIdFromOutside(ctx, req) + refundEnable, refundStatus, list, ec := service.DefaultService.ApiGetZoneListByUserIdFromOutside(ctx, req) if ec != errcode.ErrCodeZoneSrvOk { logger.Error("ApiGetZoneListByUserIdFromOutside fail, req: %v, ec: %v", util.ToJson(req), ec) ReplyErrCodeMsg(ctx, ec) @@ -172,6 +172,7 @@ func ApiGetZoneListByUserIdFromOutside(ctx *gin.Context) { List: list, Offset: req.Offset + len(list), RefundEnable: refundEnable, + RefundStatus: refundStatus, } if len(list) >= req.Limit { data.More = 1 diff --git a/app/mix/dao/mysql_zone.go b/app/mix/dao/mysql_zone.go index f108d84c..acd5b1c9 100644 --- a/app/mix/dao/mysql_zone.go +++ b/app/mix/dao/mysql_zone.go @@ -266,6 +266,25 @@ func (m *Mysql) DecZoneConsume(ctx *gin.Context, tx *sqlx.Tx, mid, zid, inc int6 // 添加到空间成员 func (m *Mysql) AddZoneMember(ctx *gin.Context, tx *sqlx.Tx, mid, zid int64, memType int32) error { var err error + // 先获取,没有再添加 + var tmpZm *dbstruct.ZoneMember + if tx != nil { + err = tx.GetContext(ctx, tmpZm, fmt.Sprintf("select * from %s where mid=? and zid=? and member_type=?", TableVasZoneMember), mid, zid, memType) + } else { + db := m.getDBVas() + err = db.GetContext(ctx, tmpZm, fmt.Sprintf("select * from %s where mid=? and zid=? and member_type=?", TableVasZoneMember), mid, zid, memType) + } + if err == sql.ErrNoRows { + err = nil + } + if err != nil { + return err + } + if tmpZm != nil { + return nil + } + + // 再添加 sqlStr := "insert into " + TableVasZoneMember + " (zid, mid, member_type, ct) " + " values (?,?,?,?)" if tx != nil { _, err = tx.ExecContext(ctx, sqlStr, zid, mid, memType, time.Now().Unix()) @@ -299,7 +318,7 @@ func (m *Mysql) DeleteZoneMember(ctx *gin.Context, tx *sqlx.Tx, mid, zid int64, // 获取空间成员列表 func (m *Mysql) GetZoneMemberList(ctx *gin.Context, tx *sqlx.Tx, zid int64, memType int32) (list []*dbstruct.ZoneMember, err error) { list = make([]*dbstruct.ZoneMember, 0) - sqlStr := fmt.Sprintf(fmt.Sprintf("select * from %s where zid=? and member_type=? order by ct desc", TableVasZoneUnlock)) + sqlStr := fmt.Sprintf(fmt.Sprintf("select * from %s where zid=? and member_type=? order by ct desc", TableVasZoneMember)) if tx != nil { err = tx.SelectContext(ctx, &list, sqlStr, zid, memType) } else { diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index 9003be35..a4fa3af8 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -2301,7 +2301,7 @@ func (s *Service) ApiGetZoneListByVisitorMid(ctx *gin.Context, req *zoneproto.Ap return } -func (s *Service) ApiGetZoneListByUserIdFromOutside(ctx *gin.Context, req *zoneproto.ApiListByUserIdFromOutsideReq) (refundEnable int, volist []*zoneproto.ApiZoneVO, ec errcode.ErrCode) { +func (s *Service) ApiGetZoneListByUserIdFromOutside(ctx *gin.Context, req *zoneproto.ApiListByUserIdFromOutsideReq) (refundEnable int, refundStatus int, volist []*zoneproto.ApiZoneVO, ec errcode.ErrCode) { ec = errcode.ErrCodeZoneSrvOk volist = make([]*zoneproto.ApiZoneVO, 0) @@ -2358,6 +2358,16 @@ func (s *Service) ApiGetZoneListByUserIdFromOutside(ctx *gin.Context, req *zonep refundEnable = 1 } + // 退款状态 + if _, ok := zidZuMap[zid]; !ok { + return + } + admissionOrderId := zidZuMap[zid].GetAdmissionOrderId() + order, _ := _DefaultVas.GetOrderById(ctx, nil, admissionOrderId) + if order.GetOrderStatus() == dbstruct.VasOrderStatusRefund { + refundStatus = zoneproto.AdmissionRefundStatusFinish + } + return } diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index ed2dda9c..6cf10a78 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -1336,6 +1336,10 @@ func (v *Vas) GetCoinOrderById(ctx *gin.Context, id string) (*dbstruct.CoinOrder return v.store.GetCoinOrderById(ctx, nil, id) } +func (v *Vas) GetOrderById(ctx *gin.Context, tx *sqlx.Tx, id string) (*dbstruct.Order, error) { + return v.store.GetOrderById(ctx, tx, id) +} + func (v *Vas) GetOrderCountGroupByStatus(ctx *gin.Context, req *vasproto.GetOrderByStatusReq) ([]*dbstruct.VasOrderStatusCount, error) { return v.store.GetOrderCountGroupByStatus(ctx, nil, req.OrderStatuses, req.CtStart, req.CtEnd) } diff --git a/app/mix/service/logic/vas_zone.go b/app/mix/service/logic/vas_zone.go index 023fe06e..8f2e2094 100644 --- a/app/mix/service/logic/vas_zone.go +++ b/app/mix/service/logic/vas_zone.go @@ -247,7 +247,7 @@ func (v *Vas) UnlockZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, order *dbstruct ) // 解锁空间会员 - err := v.store.UnlockZoneAdmission(ctx, tx, mid, zid, -1, orderId, unlockType) + err := v.MustUnlockAdmission(ctx, tx, mid, zid, -1, orderId, unlockType) if err != nil { logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, orderId: %v, err: %v", mid, zid, orderId, err) return err @@ -297,9 +297,9 @@ func (v *Vas) UnlockZoneSuperfanship(ctx *gin.Context, tx *sqlx.Tx, order *dbstr ) // 解锁空间超粉 - err := v.store.UnlockZoneSuperfanship(ctx, tx, mid, zid, order.GetSuperfanshipUntil(), orderId, unlockType) + err := v.MustUnlockSuperfanship(ctx, tx, mid, zid, order.GetSuperfanshipUntil(), orderId, unlockType) if err != nil { - logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, orderId: %v, err: %v", mid, zid, orderId, err) + logger.Error("MustUnlockSuperfanship fail, mid: %v, zid: %v, orderId: %v, err: %v", mid, zid, orderId, err) return err } @@ -392,7 +392,7 @@ func (v *Vas) UnlockZoneIronfanshipReachConsume(ctx *gin.Context, tx *sqlx.Tx, m } // 解锁铁粉 - err := v.store.UnlockZoneIronfanship(ctx, tx, mid, zid, -1, "ironfan", dbstruct.ZoneUnlockTypeReachConsume) + err := v.MustUnlockIronfanship(ctx, tx, mid, zid, -1, "ironfan", dbstruct.ZoneUnlockTypeReachConsume) if err != nil { logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) return err @@ -856,7 +856,7 @@ func (v *Vas) ZoneFreeJoin(ctx *gin.Context, mid, zid int64) error { }() // 解锁空间会员 - err = v.store.UnlockZoneAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeFree) + err = v.MustUnlockAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeFree) if err != nil { logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) return err @@ -871,3 +871,39 @@ func (v *Vas) ZoneFreeJoin(ctx *gin.Context, mid, zid int64) error { return nil } + +func (v *Vas) MustUnlockAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid, until int64, orderId string, unlockType int32) error { + // 检查解锁 + _, exist := v.CheckZoneUnlockExist(ctx, tx, mid, zid) + if !exist { + logger.Error("MustUnlockAdmission fail, checkZU fail, mid: %v, zid: %v", mid, zid) + return fmt.Errorf("无法解锁,请联系运营") + } + + // 解锁空间会员 + return v.store.UnlockZoneAdmission(ctx, tx, mid, zid, until, orderId, unlockType) +} + +func (v *Vas) MustUnlockIronfanship(ctx *gin.Context, tx *sqlx.Tx, mid, zid, until int64, orderId string, unlockType int32) error { + // 检查解锁 + _, exist := v.CheckZoneUnlockExist(ctx, tx, mid, zid) + if !exist { + logger.Error("MustUnlockIronfanship fail, checkZU fail, mid: %v, zid: %v", mid, zid) + return fmt.Errorf("无法解锁,请联系运营") + } + + // 解锁铁粉 + return v.store.UnlockZoneIronfanship(ctx, tx, mid, zid, until, orderId, unlockType) +} + +func (v *Vas) MustUnlockSuperfanship(ctx *gin.Context, tx *sqlx.Tx, mid, zid, until int64, orderId string, unlockType int32) error { + // 检查解锁 + _, exist := v.CheckZoneUnlockExist(ctx, tx, mid, zid) + if !exist { + logger.Error("MustUnlockSuperfanship fail, checkZU fail, mid: %v, zid: %v", mid, zid) + return fmt.Errorf("无法解锁,请联系运营") + } + + // 解锁超粉 + return v.store.UnlockZoneSuperfanship(ctx, tx, mid, zid, until, orderId, unlockType) +} diff --git a/app/mix/service/vasservice.go b/app/mix/service/vasservice.go index 2cbf7b84..ef5657f7 100644 --- a/app/mix/service/vasservice.go +++ b/app/mix/service/vasservice.go @@ -666,13 +666,29 @@ func (s *Service) ZoneCreateOrder(ctx *gin.Context, req *vasproto.ZoneCreateOrde func (s *Service) ZoneGetCashier(ctx *gin.Context, req *vasproto.ZoneGetCashierReq) (data *vasproto.ZoneGetCashierData, ec errcode.ErrCode, err error) { ec = errcode.ErrCodeVasSrvOk - data = new(vasproto.ZoneGetCashierData) data.Validity = "永久" - zv, _ := _DefaultVas.GetZoneVasInfo(ctx, req.Zid) + + mid := req.Mid + zid := req.Zid + zv, _ := _DefaultVas.GetZoneVasInfo(ctx, zid) switch req.ProductId { case dbstruct.ProductIdH5ZoneMoment: + // 判断是否已解锁该动态 + zmuMap, err := _DefaultVas.GetZoneMomentUnlockMapByMidMomentIds(ctx, req.Mid, []int64{req.MomentId}) + if err != nil { + ec = errcode.ErrCodeVasSrvFail + logger.Error("GetZoneMomentUnlockMapByMidMomentIds fail, mid: %v, momentId: %v", req.Mid, req.MomentId) + return nil, ec, fmt.Errorf("无法获取动态解锁记录") + } + if _, ok := zmuMap[req.MomentId]; ok { + ec = errcode.ErrCodeVasSrvOk + data.HasBought = 1 + return data, ec, nil + //ec = errcode.ErrCodeVasSrvFail + //return nil, ec, fmt.Errorf("已解锁该动态,请勿重复购买") + } data.Name = "付费动态" // 获取动态价格 zmp, _ := _DefaultVas.GetZoneMomentPriceById(ctx, req.MomentId) @@ -680,6 +696,21 @@ func (s *Service) ZoneGetCashier(ctx *gin.Context, req *vasproto.ZoneGetCashierR data.Price = zmp.Price } case dbstruct.ProductIdH5ZoneAdmission: + // 是否解锁了空间普通会员 + zuMap, _ := _DefaultVas.GetZoneUnlockMapByMidZids(ctx, mid, []int64{zid}) + if zu, ok := zuMap[mid]; ok && zu.IsUnlockAdmission() { + ec = errcode.ErrCodeVasSrvOk + data.HasBought = 1 + return data, ec, nil + } + + // 判断主播是否开通空间 + zone, err := _DefaultZone.GetById(ctx, zid) + if err != nil || zone == nil { + ec = errcode.ErrCodeVasSrvFail + logger.Error("GetById fail, mid: %v, zid: %v, erR: %v", req.Mid, zid, err) + return nil, ec, fmt.Errorf("无法获取主播动态") + } data.Name = "空间会员" if zv == nil { ec = errcode.ErrCodeVasSrvFail @@ -692,14 +723,27 @@ func (s *Service) ZoneGetCashier(ctx *gin.Context, req *vasproto.ZoneGetCashierR ec = errcode.ErrCodeVasSrvFail return nil, ec, fmt.Errorf("该主播未设置空间价格") } - data.Price = zv.AdmissionPrice + data.Price = zv.IronfanshipPrice case dbstruct.ProductIdH5ZoneSuperfanship: + // 判断主播是否开启超粉 + if zv.IsSuperfanshipEnabled != 1 { + ec = errcode.ErrCodeVasSrvFail + return nil, ec, fmt.Errorf("该主播未开启超粉空间") + } + // 用户是否解锁了空间超粉 + zuMap, _ := _DefaultVas.GetZoneUnlockMapByMidZids(ctx, mid, []int64{zid}) + if zu, ok := zuMap[mid]; ok && zu.IsUnlockSuperfanship() { + ec = errcode.ErrCodeVasSrvOk + data.HasBought = 1 + return data, ec, nil + } + data.Name = "超粉" if zv == nil { ec = errcode.ErrCodeVasSrvFail return nil, ec, fmt.Errorf("该主播未设置空间价格") } - data.Price = zv.AdmissionPrice + data.Price = zv.SuperfanshipPrice data.Validity = zv.GetSuperfanshipDurationDesc() } return