mh_server/model/user_vm.go

249 lines
7.7 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 (
"errors"
"fmt"
"github.com/codinl/go-logger"
"github.com/jinzhu/gorm"
"time"
)
const (
//VmEventExchangeGoods = "exchange_goods"
VmEventBuyGoods = "buy_goods" // 购买商品积分抵扣
VmEventBuyGoodsReject = "buy_goods_reject" // 购买商品积分抵扣取消
VmEventOpenMember = "open_member" // 开通租卡会员奖励
VmEventRenewMember = "renew_member" // 续费租卡会员奖励
VmEventUpgradeMember = "upgrade_member" // 升级租卡会员奖励
VmEventInvite1Member = "invite_1_member" // 邀请会员奖励
VmEventInvite2Member = "invite_2_member" // 邀请会员奖励
VmEventAttendance = "attendance" // 签到获取积分
VmEventErpOrderSale = "erp_order_sale" // 零售销售获得积分
VmEventErpOrderReject = "erp_order_reject" // 零售退货扣除积分
VmEventOpenPrivilegeMember = "open_privilege_member" // 开通尊享会员奖励
VmEventRenewPrivilegeMember = "renew_privilege_member" // 续费尊享会员奖励
)
// 用户积分
// gen:qs
//
//go:generate goqueryset -in user_vm.go
type UserVm struct {
Model
Uid uint32 `json:"uid" gorm:"column:uid;unique_index"`
Vm uint32 `json:"vm"`
}
// 用户积分-变动记录
// gen:qs
type UserVmRecord struct {
Model
Uid uint32 `json:"uid" gorm:"column:uid;index"`
BeforeVm uint32 `json:"before_vm"` // 变动前
AfterVm uint32 `json:"after_vm"` // 变动后
Alter int `json:"alter"` // 数值
Event string `json:"event" gorm:"type:varchar(100)"` // 事件
Describe string `json:"describe" gorm:"type:text"` // 描述
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id
BillSn string `json:"bill_sn"` // 零售订单编号
ExpiryDate *time.Time `json:"expiry_date"` // 积分过期时间
UsedVm int `json:"used_vm"` // 已使用积分
ExpiryVm int `json:"expiry_vm" gorm:"-"` // 即将过期的积分
}
func UserVmUpdate(uid uint32, amount int, event, describe string) error {
var userVm UserVm
err := NewUserVmQuerySet(DB).UidEq(uid).One(&userVm)
if err != nil && err != RecordNotFound {
logger.Error("err:", err)
return err
}
begin := DB.Begin()
if err == RecordNotFound {
if amount < 0 {
begin.Rollback()
logger.Error("amount lt 0")
return errors.New("amount lt 0")
}
userVm = UserVm{
Uid: uid,
Vm: uint32(amount),
}
err = begin.Create(&userVm).Error
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
} else {
// 如果用户积分不够抵扣则扣到0为止
if int(userVm.Vm)+amount <= 0 {
sql := fmt.Sprintf("UPDATE user_vm SET vm = ? WHERE uid=?")
err = begin.Exec(sql, 0, uid).Error
} else {
sql := fmt.Sprintf("UPDATE user_vm SET vm = vm+? WHERE uid=?")
err = begin.Exec(sql, amount, uid).Error
}
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
}
vmRecord := &UserVmRecord{
Uid: uid,
BeforeVm: uint32(userVm.Vm),
AfterVm: uint32(int(userVm.Vm) + amount),
Alter: amount,
Event: event,
Describe: describe,
}
if newValue := int(userVm.Vm) + amount; newValue > 0 {
vmRecord.AfterVm = uint32(newValue)
}
// 如果是正积分,则记录该订单对应积分的有效时间
if amount > 0 {
expireTime := time.Now().AddDate(1, 0, 0)
vmRecord.ExpiryDate = &expireTime
if event == VmEventBuyGoodsReject { // 使用积分购买商品后取消
err = RefundPoints(begin, uid, amount)
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
}
} else { // 如果是负积分,则记录积分使用情况;优先扣除最早获得的积分
if event == VmEventBuyGoods || event == VmEventErpOrderReject { // 使用积分购买商品,或者零售退货扣除积分
err = UsePoints(begin, uid, -amount)
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
}
}
err = begin.Create(vmRecord).Error
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("err:", err)
return err
}
return nil
}
// GetUserAvailablePointsRecords 查找用户的所有可用积分记录,按时间排序
func GetUserAvailablePointsRecords(uid uint32) []UserVmRecord {
var userVmRecord []UserVmRecord
err := NewUserVmRecordQuerySet(DB).UidEq(uid).OrderDescByCreatedAt().
EventIn(VmEventOpenMember, VmEventInvite1Member, VmEventInvite2Member, VmEventRenewMember, VmEventUpgradeMember,
VmEventAttendance, VmEventErpOrderSale).All(&userVmRecord)
if err != nil {
logger.Error("get user_vm_record err:", err)
return []UserVmRecord{}
}
return userVmRecord
}
func UsePoints(gdb *gorm.DB, uid uint32, points int) error {
// 1. 查找用户的所有可用积分记录,按时间排序
records := GetUserAvailablePointsRecords(uid)
remaining := points
for _, record := range records {
if record.ExpiryDate != nil && record.ExpiryDate.IsZero() {
record.ExpiryDate = nil
}
available := record.Alter - record.UsedVm // 计算该订单剩余可用积分
if available >= remaining {
// 该订单的剩余积分足够
record.UsedVm += remaining
// 更新积分记录
err := gdb.Model(&record).Where("id = ?", record.ID).Updates(record).Error
if err != nil {
logger.Error("update user_vm_record err:", err)
return err
}
break
} else {
// 该订单的剩余积分不足,全部使用,继续扣减下一条记录
record.UsedVm = record.Alter
remaining -= available
// 更新积分记录
err := gdb.Model(&record).Where("id = ?", record.ID).Updates(record).Error
if err != nil {
logger.Error("update user_vm_record err:", err)
return err
}
}
}
return nil
}
// GetUserUsedPointsRecords 查找用户的已使用积分记录,按使用时间倒序排序
func GetUserUsedPointsRecords(uid uint32) []UserVmRecord {
var userVmRecord []UserVmRecord
err := NewUserVmRecordQuerySet(DB).UidEq(uid).OrderDescByCreatedAt().
EventIn(VmEventOpenMember, VmEventInvite1Member, VmEventInvite2Member, VmEventRenewMember, VmEventUpgradeMember,
VmEventAttendance, VmEventErpOrderSale).UsedVmNe(0).All(&userVmRecord)
if err != nil {
logger.Error("get user_vm_record err:", err)
return []UserVmRecord{}
}
return userVmRecord
}
// RefundPoints 查找用户的已使用积分记录,按使用时间倒序排序
func RefundPoints(gdb *gorm.DB, uid uint32, points int) error {
// 1. 查找用户的已使用积分记录,按使用时间倒序排序
usedRecords := GetUserUsedPointsRecords(uid)
remaining := points
for _, record := range usedRecords {
used := record.UsedVm // 获取该订单已使用的积分
if used >= remaining {
// 该订单已使用的积分足够返还
record.UsedVm -= remaining
// 更新积分记录
err := gdb.Model(&record).Where("id = ?", record.ID).Updates(record).Error
if err != nil {
logger.Error("RefundPoints update user_vm_record err:", err)
return err
}
break
} else {
// 该订单已使用的积分不足以完全返还,全部返还后继续处理下一条记录
record.UsedVm = 0
remaining -= used
// 更新积分记录
err := gdb.Model(&record).Where("id = ?", record.ID).Updates(record).Error
//err := gdb.Omit("created_at").Save(record).Error
if err != nil {
logger.Error("RefundPoints update user_vm_record err:", err)
return err
}
}
}
return nil
}