mh_server/model/redeem_code.go

735 lines
22 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}