package model import ( "crypto/sha512" "errors" "fmt" "github.com/codinl/go-logger" "github.com/jinzhu/gorm" "mh-server/lib/utils" "strings" "time" ) const ( RedeemCodeStatusStock = "stocking" // 库存 RedeemCodeStatusHold = "user-hold" // 用户持有 RedeemCodeStatusUsed = "used" // 已使用 ) const ( CodeTypeMemberCard30 = "member-card-30" // 会员卡 30天 CodeTypeMemberGoldMember = "member-card-gold-member" CodeTypeMemberPlatinumMember = "member-card-platinum-member" CodeTypeMemberBlackGoldMember = "member-card-black-gold-member" CodeTypeDeductionCoupon5 = "deduction-coupon-5" CodeTypeMemberPrivilegeMember = "member-card-privilege-member" // 尊享会员兑换码 ) const ( RedeemCodeSecretKey = "046033a527d1b723ed0a1012e6518d490" ) const ( UserRedeemCodeStatusHold = "user-hold" UserRedeemCodeStatusUsed = "used" ) const ( RedeemCodeActivityTypeStore = 1 // 门店赠送 RedeemCodeActivityTypeUserInvite = 2 // 用户邀请 ) // gen:qs // //go:generate goqueryset -in redeem_code.go type RedeemCode struct { Model SerialCode string `json:"serial_code" gorm:"index;comment:'兑换编码'"` // 兑换编码 CodeType string `json:"code_type"` // memberCard Status string `json:"status" gorm:"index;comment:'兑换状态'"` // stocking user-hold used StoreId uint32 `json:"store_id" gorm:"index"` // 门店id CodeSecret string `json:"code_secret"` // 兑换密码 EffectiveTime time.Time `json:"effective_time"` // 生效时间 ExpirationTime time.Time `json:"expiration_time"` // 过期时间 CouponId uint32 `json:"coupon_id" gorm:"index"` //Remark string `json:"remark"` } const ( UserRedeemCodeStatsExpired = "expired" ) // gen:qs type UserRedeemCode struct { Model Uid uint32 `json:"uid" gorm:"index;comment:'用户id'"` Status string `json:"status" gorm:"index;comment:'兑换状态'"` // user-hold used expired StoreId uint32 `json:"store_id" gorm:"index"` // 门店id SerialCode string `json:"serial_code" gorm:"index;comment:'兑换编码'"` // 兑换编码 CodeType string `json:"code_type"` // memberCard ConvertTime time.Time `json:"convert_time"` // 绑定时间 ActivityType uint32 `json:"activity_type"` // 1-门店赠送 2-用户邀请 ExpiredTime time.Time `json:"expired_time"` // 过期时间: } //type BindingRedeemCodeRecord struct { // Model //} // 会员兑换码 // 用户押金 // 支付押金 // 押金 // 开通会员 // 管理端 发 会员 Sign 校验 func RedeemSecretCode(redeem string) string { semen := redeem[:13] + strings.ToUpper(RedeemCodeSecretKey) shaer := sha512.New() shaer.Write([]byte(semen)) r := shaer.Sum(nil) hs := fmt.Sprintf("%x", r) return hs[:7] } func UserRedeemCodeList(uid uint32, status string) ([]UserRedeemCode, error) { var userRedeems []UserRedeemCode qs := NewUserRedeemCodeQuerySet(DB).UidEq(uid) //if status != "" { //} if status == UserRedeemCodeStatsExpired { qs = qs.StatusEq(status) } else { qs = qs.StatusNe(UserRedeemCodeStatsExpired) } err := qs.OrderDescByID().All(&userRedeems) if err != nil && err != RecordNotFound { logger.Error("user redeem code err:", err) return userRedeems, err } if len(userRedeems) == 0 { return userRedeems, nil } nowTime := time.Now() holdList := make([]UserRedeemCode, 0) usedList := make([]UserRedeemCode, 0) expiredIds := make([]uint32, 0) for i, _ := range userRedeems { if userRedeems[i].ExpiredTime.Year() == 1 { userRedeems[i].ExpiredTime = userRedeems[i].CreatedAt.AddDate(1, 0, 0) } if userRedeems[i].Status == UserRedeemCodeStatusHold { holdList = append(holdList, userRedeems[i]) if userRedeems[i].CreatedAt.AddDate(1, 0, 0).Before(nowTime) { expiredIds = append(expiredIds, userRedeems[i].ID) } } else { usedList = append(usedList, userRedeems[i]) } } if len(expiredIds) != 0 { err = NewUserRedeemCodeQuerySet(DB).IDIn(expiredIds...).GetUpdater(). SetStatus(UserRedeemCodeStatsExpired).Update() if err != nil { logger.Error("updater user redeem code status err:", err) } } return append(holdList, usedList...), nil } // UserRedeemCodeConvert 会员兑换码兑换 func UserRedeemCodeConvert(uid uint32, serialCode string) error { var userRedeem UserRedeemCode err := NewUserRedeemCodeQuerySet(DB).UidEq(uid).SerialCodeEq(serialCode).One(&userRedeem) if err != nil { logger.Error("user redeem code err:", err) return err } if userRedeem.Status != UserRedeemCodeStatusHold { return errors.New("user redeem code not exist") } if userRedeem.CodeType == CodeTypeMemberPrivilegeMember { // 尊享会员兑换码 return PrivilegeUserRedeemCodeConvert(uid, serialCode) } begin := DB.Begin() num, err := NewRedeemCodeQuerySet(begin).SerialCodeEq(serialCode).GetUpdater().SetStatus(RedeemCodeStatusUsed).UpdateNum() if err != nil { logger.Error("user redeem code err:", err) begin.Rollback() return err } if num == 0 { logger.Error("num is 0 err:") begin.Rollback() return err } updateNum, err := NewUserRedeemCodeQuerySet(begin).UidEq(uid).SerialCodeEq(serialCode).GetUpdater(). SetStatus(UserRedeemCodeStatusUsed).SetConvertTime(time.Now()).UpdateNum() if err != nil { logger.Error("user redeem code err:", err) begin.Rollback() return err } if updateNum == 0 { logger.Error("num is 0 err:") begin.Rollback() return err } user := GetUserByUid(uid) qs := NewUserQuerySet(begin).UidEq(uid).GetUpdater() if user.MemberLevel != 1 && user.MemberLevel != 3 && userRedeem.CodeType != CodeTypeMemberCard30 { logger.Error("code type used by consumer:") begin.Rollback() return errors.New("code type used by consumer") } addDates := 0 memberLevel := uint32(0) switch userRedeem.CodeType { case CodeTypeMemberCard30: addDates = 30 memberLevel = 3 case CodeTypeMemberGoldMember: addDates = 365 memberLevel = 2 qs = qs.SetMemberLevel(MemberLevelGold).SetOpenMemberTime(time.Now()).SetOpenMemberChannel(OpenMemberChannelRedeemCode) case CodeTypeMemberPlatinumMember: addDates = 365 memberLevel = 4 qs = qs.SetMemberLevel(MemberLevelPlatinum).SetOpenMemberTime(time.Now()).SetOpenMemberChannel(OpenMemberChannelRedeemCode) case CodeTypeMemberBlackGoldMember: addDates = 365 memberLevel = 5 qs = qs.SetMemberLevel(MemberLevelBlackGold).SetOpenMemberTime(time.Now()).SetOpenMemberChannel(OpenMemberChannelRedeemCode) default: logger.Error(" code type err:", err) begin.Rollback() return err } if user.MemberExpire.After(time.Now()) { qs = qs.SetMemberExpire(user.MemberExpire.AddDate(0, 0, addDates)) } else { qs = qs.SetMemberExpire(time.Now().AddDate(0, 0, addDates)) } if user.MemberLevel == 1 || user.MemberLevel == 3 { qs = qs.SetMemberLevel(memberLevel) } userNum, err := qs.UpdateNum() if err != nil { logger.Error("user redeem code err:", err) begin.Rollback() return err } if userNum == 0 { logger.Error("num is 0 err:") begin.Rollback() return err } err = begin.Commit().Error if err != nil { logger.Error("user redeem code err:", err) begin.Rollback() return err } return nil } // PrivilegeUserRedeemCodeConvert 尊享会员兑换码兑换 func PrivilegeUserRedeemCodeConvert(uid uint32, serialCode string) error { begin := DB.Begin() // 更新 redeem_code 表状态 num, err := NewRedeemCodeQuerySet(begin).SerialCodeEq(serialCode). GetUpdater().SetStatus(RedeemCodeStatusUsed).UpdateNum() if err != nil || num == 0 { logger.Error("update redeem_code status failed:", err) begin.Rollback() return err } // 更新 user_redeem_code 表状态 updateNum, err := NewUserRedeemCodeQuerySet(begin).UidEq(uid).SerialCodeEq(serialCode). GetUpdater().SetStatus(UserRedeemCodeStatusUsed).SetConvertTime(time.Now()).UpdateNum() if err != nil || updateNum == 0 { logger.Error("update user_redeem_code status failed:", err) begin.Rollback() return err } // 更新尊享会员邀请记录,并发放优惠券 err = UpdatePrivilegeMember(uid, begin) if err != nil { logger.Error("UpdatePrivilegeMember err:", err) begin.Rollback() return err } err = begin.Commit().Error if err != nil { logger.Error("transaction commit failed:", err) begin.Rollback() return err } return nil } // UpdatePrivilegeMember 更新尊享会员邀请记录,并发放优惠券 func UpdatePrivilegeMember(uid uint32, db *gorm.DB) error { logger.Info("兑换码开通尊享会员") record := &UserOpenMemberRecord{ Uid: uid, MemberLevel: MemberLevelPrivilege, } memberRecord := &UserMemberRecord{ Uid: record.Uid, AfterMemberLevel: record.MemberLevel, } newTime := time.Now() privilegeMemberNew := &PrivilegeMember{} var spendType uint32 // 开通类型: 1-未开通 2-开通会员 3-续费 var user User err := NewUserQuerySet(db).UidEq(record.Uid).One(&user) if err != nil { logger.Error("err:", err) return err } else { var privilegeMember PrivilegeMember err = NewPrivilegeMemberQuerySet(db).UidEq(record.Uid).One(&privilegeMember) if err != nil && err != RecordNotFound { logger.Error("PrivilegeMember:", err) return err } var expireTime time.Time expireTime = newTime.AddDate(1, 0, 0) if err == RecordNotFound { // 没有记录,用户新开通尊享会员 spendType = 2 // 2-开通会员 memberRecord.OpenMemberTime = newTime memberRecord.Type = 9 // 开通会员类型 privilegeMemberNew.Uid = record.Uid privilegeMemberNew.Tel = user.Tel privilegeMemberNew.MemberLevel = MemberLevelPrivilege privilegeMemberNew.MemberExpire = &expireTime privilegeMemberNew.OpenMemberTime = &newTime privilegeMemberNew.ExtendStatus = ExtendWaitActive } else { // 有记录,用户续费尊享会员 spendType = 3 // 3-续费 memberRecord.OpenMemberTime = *privilegeMember.OpenMemberTime memberRecord.BeforeMemberLevel = privilegeMember.MemberLevel memberRecord.BeforeMemberExpire = *privilegeMember.MemberExpire memberRecord.Serial = uint32(privilegeMember.MemberExpire.Unix()) if privilegeMember.MemberExpire.After(newTime) { expireTime = privilegeMember.MemberExpire.AddDate(1, 0, 0) } memberRecord.Type = 10 // 续费会员类型 userUpdateQs := NewPrivilegeMemberQuerySet(db).UidEq(record.Uid).GetUpdater(). SetMemberLevel(record.MemberLevel).SetMemberExpire(&expireTime).SetExtendStatus(ExtendWaitActive) _, err = userUpdateQs.UpdateNum() if err != nil { logger.Error("err:", err) return err } } memberRecord.AfterMemberExpire = expireTime memberRecord.OpenMemberLevel = record.MemberLevel // 邀请记录 var invite UserInvite err = NewUserInviteQuerySet(db).ToUidEq(record.Uid).OrderDescByCreatedAt().Limit(1).One(&invite) if err != nil && err != RecordNotFound { logger.Error("err:", err) } else { if err == nil { effectiveStoreInfo, err := GetUserEffectiveStore(invite.FromUid) if err != nil { logger.Error("GetUserEffectiveStore err:", err) effectiveStoreInfo.StoreID = 0 } privilegeMemberNew.StoreId = effectiveStoreInfo.StoreID if invite.Action == 1 { // 首次开通会员 qs := NewUserInviteQuerySet(db).IDEq(invite.ID).GetUpdater() invite.RenewHide = 1 // 自动 qs = qs.SetMemberOpenTime(newTime).SetMemberLevel(record.MemberLevel) _, err = qs.SetMemberType(2).SetMemberStatus(2). SetAction(2).SetSpendType(spendType).SetMemberGenre(record.MemberGenre).UpdateNum() if err != nil { logger.Error("update user invite action spend type err:", err) } if invite.UserInviteRecordId != 0 { err = NewUserInviteRecordQuerySet(db).IDEq(invite.UserInviteRecordId).GetUpdater(). SetAction(2).SetSpendType(spendType).SetMemberLevel(record.MemberLevel). SetActionTime(newTime).SetMemberGenre(record.MemberGenre).SetRenewHide(invite.RenewHide).Update() if err != nil { logger.Error("update user invite record err:", err) } } } else { // 续费会员-用户直接续费 inviteRecordNew := &UserInviteRecord{ ToUid: invite.ToUid, FromUid: invite.FromUid, StoreId: effectiveStoreInfo.StoreID, Action: 2, SpendType: spendType, MemberLevel: record.MemberLevel, First: 0, Scan: 0, // 自动生成 ActionTime: newTime, MemberGenre: record.MemberGenre, RenewHide: 1, } err = db.Create(inviteRecordNew).Error if err != nil { logger.Error("create invite record err:", err) } userInviteNew := &UserInvite{ FromUid: invite.FromUid, UserType: invite.UserType, StoreId: effectiveStoreInfo.StoreID, StoreType: invite.StoreType, MemberOpenTime: time.Now(), MemberType: 2, MemberStatus: 2, ToUid: invite.ToUid, Action: 2, SpendType: spendType, MemberLevel: record.MemberLevel, UserInviteRecordId: inviteRecordNew.ID, FirstInvite: 0, Scan: 0, MemberGenre: record.MemberGenre, RenewHide: 1, //MemberOpenTime: invite.MemberOpenTime, } err = db.Create(userInviteNew).Error if err != nil { logger.Error("create invite record err:", err) } } if invite.FromUid != 0 { logger.Info("invite.FromUid != 0") fmt.Println("invite.FromUid != 0") inviteUser := GetUserByUid(invite.FromUid) if inviteUser != nil && inviteUser.UserType == 2 { // 记录对应的数量 switch spendType { case 2: // 开通 fmt.Println("用户开通------") AddCooperativeMemberPromotion(inviteUser.CooperativeBusinessId, uint32(effectiveStoreInfo.StoreID), inviteUser.Uid, int(record.MemberLevel), int(record.MemberGenre)) case 3: // 续费 fmt.Println("用户续费---") AddCooperativeMemberRenewal(inviteUser.CooperativeBusinessId, uint32(invite.StoreId), inviteUser.Uid, int(record.MemberLevel), int(record.MemberGenre), true) } } } } else if err == RecordNotFound { // 没有邀请记录,完全是用户自己开通会员,自己续费;按产品要求也需要有记录 inviteRecordNew := &UserInviteRecord{ ToUid: user.Uid, Action: 2, SpendType: spendType, MemberLevel: record.MemberLevel, First: 0, Scan: 0, // 自动生成 ActionTime: newTime, MemberGenre: record.MemberGenre, RenewHide: 1, } err = db.Create(inviteRecordNew).Error if err != nil { logger.Error("create invite record err:", err) } // 记录对应的数量 switch spendType { case 2: // 开通 fmt.Println("用户开通------") AddCooperativeMemberPromotion(user.CooperativeBusinessId, 0, 0, int(record.MemberLevel), int(record.MemberGenre)) case 3: // 续费 fmt.Println("用户续费---") AddCooperativeMemberRenewal(user.CooperativeBusinessId, 0, 0, int(record.MemberLevel), int(record.MemberGenre), true) } } } if spendType == 2 { // 开通会员,新建尊享会员记录 err = db.Create(privilegeMemberNew).Error if err != nil { logger.Error("create invite record err:", err) } } err = db.Create(memberRecord).Error if err != nil { logger.Error("create member record err:", err) } } // 发放优惠券 var coupons []Coupon err = NewCouponQuerySet(db).ActivityIdEq(PrivilegeMemberActivityId).All(&coupons) if err != nil { logger.Error("coupons err:", err) return err } for i, _ := range coupons { if coupons[i].ActivityType == 6 || coupons[i].ActivityType == 7 { // 15元周边券,20元配件券,发4张 for j := 0; j < 4; j++ { couponCode, err := utils.GenerateRandomNumber19() if err != nil { logger.Error("GenerateRandomNumber19err:", err) } userCoupon := &UserCoupon{ Uid: record.Uid, CouponId: coupons[i].ID, CouponType: coupons[i].CouponType, ActivityType: coupons[i].ActivityType, ActivityId: coupons[i].ActivityId, Value: coupons[i].Value, State: 1, ActiveStart: time.Now(), ActiveEnd: time.Now().AddDate(0, 6, 0), UseTime: time.Time{}, MemberLevel: coupons[i].MemberLevel, Approach: 0, PromotionalSales: 0, RedeemCode: "", CategoryNumber: coupons[i].CategoryNumber, CommodityNumber: coupons[i].CommodityNumber, Code: couponCode, } err = db.Create(userCoupon).Error if err != nil { logger.Error("user coupon err:", err) continue } } } else if coupons[i].ActivityType == 8 { // 20元游戏券,发3张 for j := 0; j < 3; j++ { couponCode, err := utils.GenerateRandomNumber19() if err != nil { logger.Error("GenerateRandomNumber19err:", err) } userCoupon := &UserCoupon{ Uid: record.Uid, CouponId: coupons[i].ID, CouponType: coupons[i].CouponType, ActivityType: coupons[i].ActivityType, ActivityId: coupons[i].ActivityId, Value: coupons[i].Value, State: 1, ActiveStart: time.Now(), ActiveEnd: time.Now().AddDate(0, 6, 0), UseTime: time.Time{}, MemberLevel: coupons[i].MemberLevel, Approach: 0, PromotionalSales: 0, RedeemCode: "", CategoryNumber: coupons[i].CategoryNumber, CommodityNumber: coupons[i].CommodityNumber, Code: couponCode, } err = db.Create(userCoupon).Error if err != nil { logger.Error("user coupon err:", err) continue } } } else if coupons[i].ActivityType == 9 { // 贴膜券,2张 for j := 0; j < 2; j++ { couponCode, err := utils.GenerateRandomNumber19() if err != nil { logger.Error("GenerateRandomNumber19err:", err) } userCoupon := &UserCoupon{ Uid: record.Uid, CouponId: coupons[i].ID, CouponType: coupons[i].CouponType, ActivityType: coupons[i].ActivityType, ActivityId: coupons[i].ActivityId, Value: coupons[i].Value, State: 1, ActiveStart: time.Now(), ActiveEnd: time.Now().AddDate(1, 0, 0), UseTime: time.Time{}, MemberLevel: coupons[i].MemberLevel, Approach: 0, PromotionalSales: 0, RedeemCode: "", CategoryNumber: coupons[i].CategoryNumber, CommodityNumber: coupons[i].CommodityNumber, Code: couponCode, } err = db.Create(userCoupon).Error if err != nil { logger.Error("user coupon err:", err) continue } } } } return nil } func CodeSendToUser(uid uint32, codeType string, activityType uint32) error { count, err := NewUserRedeemCodeQuerySet(DB).UidEq(uid).Count() if err != nil { logger.Error("err:", err) return err } if count > 24 { logger.Error("redeem code limit 24") return errors.New("redeem code limit 24") } var redeemCode RedeemCode err = NewRedeemCodeQuerySet(DB).StatusEq(RedeemCodeStatusStock).CodeTypeEq(codeType).Limit(1).One(&redeemCode) if err != nil { logger.Errorf("err:%#v", err) return err } begin := DB.Begin() sql := fmt.Sprintf("UPDATE redeem_code SET `status` ='%s' WHERE id =%d", RedeemCodeStatusHold, redeemCode.ID) err = begin.Exec(sql).Error if err != nil { logger.Errorf("err:%#v", err) begin.Rollback() return err } userRedeemCode := &UserRedeemCode{ Uid: uid, Status: UserRedeemCodeStatusHold, SerialCode: redeemCode.SerialCode, CodeType: redeemCode.CodeType, ActivityType: activityType, //ActivityType: RedeemCodeActivityTypeUserInvite, } err = begin.Create(userRedeemCode).Error if err != nil { logger.Errorf("err:%#v", err) begin.Rollback() return err } err = begin.Commit().Error if err != nil { logger.Errorf("err:%#v", err) begin.Rollback() return err } return nil } func SendUserVm(uid, memberLevel, inviteLevel uint32) error { if memberLevel == 3 { return nil } config, err := GetMemberVmConfig(memberLevel) if err != nil { logger.Error("err:", err) return err } amount := 0 describe := "" event := "" if inviteLevel == 0 { amount = int(config.MemberVm) describe = "开通会员奖励" event = VmEventOpenMember } else if inviteLevel == 1 { amount = int(config.Invite1Vm) describe = "邀请会员奖励" event = VmEventInvite1Member } else if inviteLevel == 2 { amount = int(config.Invite2Vm) describe = "邀请会员奖励" event = VmEventInvite2Member } else if inviteLevel == 100 { amount = int(config.AutomationMemberVm) describe = "开通会员奖励" event = VmEventOpenMember } err = UserVmUpdate(uid, amount, event, describe) if err != nil { logger.Error("err:", err) return err } return nil } // NewSendUserVm 会员积分:开通会员、续费/升级会员,积分规则为1:1;邀请不再有积分 func NewSendUserVm(uid, nAmount, nType uint32) error { describe := "" event := "" if nType == 2 { // 开通租卡会员 describe = "开通租卡会员" event = VmEventOpenMember } else if nType == 3 { // 续费租卡会员 describe = "续费租卡会员" event = VmEventRenewMember } else if nType == 4 { // 升级租卡会员 describe = "升级租卡会员" event = VmEventUpgradeMember } else if nType == 5 { // 开通尊享会员 describe = "开通尊享会员" event = VmEventOpenPrivilegeMember } else if nType == 6 { // 续费尊享会员 describe = "续费尊享会员" event = VmEventRenewPrivilegeMember } else { logger.Errorf("err:", "记录会员积分失败,nType类型错误为:%d", nType) return errors.New("记录会员积分失败") } err := UserVmUpdate(uid, int(nAmount), event, describe) if err != nil { logger.Error("err:", err) return err } return nil } func GetUserRenewalCouponIds() ([]uint32, error) { ids := make([]uint32, 0) var coupons []Coupon err := NewCouponQuerySet(DB).ActivityIdEq(1).All(&coupons) if err != nil { logger.Error("coupons err:", err) return ids, err } for i, _ := range coupons { ids = append(ids, coupons[i].ID) } return ids, nil }