267 lines
6.6 KiB
Go
267 lines
6.6 KiB
Go
package service
|
||
|
||
import (
|
||
"blazing/cool"
|
||
basemodel "blazing/modules/base/model"
|
||
"blazing/modules/base/service"
|
||
"blazing/modules/player/model"
|
||
"context"
|
||
"fmt"
|
||
"math"
|
||
"time"
|
||
|
||
"github.com/gogf/gf/v2/database/gdb"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
)
|
||
|
||
type GoldListService struct {
|
||
BaseService
|
||
}
|
||
|
||
func (s *GoldListService) validateOrderInput(exchangeNum uint32, rate float64) error {
|
||
if exchangeNum == 0 {
|
||
return gerror.New("出售数量必须大于0")
|
||
}
|
||
if rate <= 0 {
|
||
return gerror.New("汇率必须大于0")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (s *GoldListService) validateOrderRecord(order *model.GoldBeanOrder) error {
|
||
if order == nil || order.ID == 0 {
|
||
return gerror.New("重复订单")
|
||
}
|
||
return s.validateOrderInput(order.ExchangeNum, order.Rate)
|
||
}
|
||
|
||
func (s *GoldListService) getPrevDayAvgRate() float64 {
|
||
var (
|
||
now = gtime.Now()
|
||
yesterday = now.AddDate(0, 0, -1)
|
||
dayStart = gtime.NewFromStr(yesterday.Format("Y-m-d") + " 00:00:00")
|
||
nextDay = dayStart.AddDate(0, 0, 1)
|
||
result struct {
|
||
AvgRate float64 `json:"avg_rate"`
|
||
}
|
||
)
|
||
|
||
err := s.dbm_fix(s.Model).
|
||
Fields("COALESCE(AVG(rate), 0) AS avg_rate").
|
||
Where("status", 1).
|
||
WhereGTE("createTime", dayStart).
|
||
WhereLT("createTime", nextDay).
|
||
Scan(&result)
|
||
if err != nil || result.AvgRate <= 0 {
|
||
return 1
|
||
}
|
||
|
||
return result.AvgRate
|
||
}
|
||
|
||
func (s *GoldListService) ModifyBefore(ctx context.Context, method string, param map[string]interface{}) (err error) {
|
||
admin := cool.GetAdmin(ctx)
|
||
userId := admin.UserId
|
||
|
||
if method == "Add" {
|
||
var (
|
||
exchangeNum = gconv.Uint32(param["exchange_num"])
|
||
rate = gconv.Float64(param["rate"])
|
||
)
|
||
|
||
if err = s.validateOrderInput(exchangeNum, rate); err != nil {
|
||
return err
|
||
}
|
||
|
||
if service.NewBaseSysUserService().GetGold(userId) < int64(exchangeNum)*100 {
|
||
return fmt.Errorf("金额不足")
|
||
}
|
||
|
||
t, _ := s.dbm_fix(s.Model).Where("player_id", userId).Where("status", 0).Count()
|
||
if t > 0 {
|
||
return fmt.Errorf("不允许多挂单")
|
||
}
|
||
|
||
var (
|
||
prevAvg = s.getPrevDayAvgRate()
|
||
minRate = math.Round(prevAvg*0.9*10000) / 10000
|
||
maxRate = math.Round(prevAvg*1.1*10000) / 10000
|
||
)
|
||
|
||
if rate < minRate || rate > maxRate {
|
||
return fmt.Errorf("不允许超过10%%的单子,当前需在昨日均价 %.4f 的上下10%%范围内(%.4f - %.4f)", prevAvg, minRate, maxRate)
|
||
}
|
||
} else {
|
||
var items []model.GoldBeanOrder
|
||
if err = s.dbm_fix(s.Model).WhereIn("id", param["ids"]).Scan(&items); err != nil {
|
||
return err
|
||
}
|
||
for _, v := range items {
|
||
if _, err = s.dbm_fix(s.Model).
|
||
Where("rate", v.Rate).
|
||
Where("exchange_num", v.ExchangeNum).
|
||
Where("player_id", 10001).
|
||
Delete(); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return
|
||
}
|
||
func (s *GoldListService) Done(listid uint32) (*model.GoldBeanOrder, error) {
|
||
var rr model.GoldBeanOrder
|
||
s.dbm_fix(s.Model).Where("id", listid).Scan(&rr)
|
||
if err := s.validateOrderRecord(&rr); err != nil {
|
||
return nil, err
|
||
}
|
||
r, err := s.dbm_fix(s.Model).Data("status", 1).Where("status", 0).Where("id", listid).Update()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
is, _ := r.RowsAffected()
|
||
if is == 0 {
|
||
return nil, fmt.Errorf("重复订单")
|
||
}
|
||
return &rr, nil
|
||
}
|
||
|
||
func (s *GoldListService) Trade(ctx context.Context, listid uint32, buyerID uint32) (*model.GoldBeanOrder, error) {
|
||
var result *model.GoldBeanOrder
|
||
|
||
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||
var (
|
||
order model.GoldBeanOrder
|
||
buyer basemodel.BaseSysUser
|
||
seller basemodel.BaseSysUser
|
||
)
|
||
|
||
if err := tx.Model(s.Model).Where("id", listid).Where("status", 0).Scan(&order); err != nil {
|
||
return err
|
||
}
|
||
if err := s.validateOrderRecord(&order); err != nil {
|
||
return err
|
||
}
|
||
|
||
if !order.UpdateTime.Add(1 * time.Hour).Before(gtime.Now()) {
|
||
return fmt.Errorf("未到购买时间")
|
||
}
|
||
|
||
costFree := int64(math.Round(order.Rate * float64(order.ExchangeNum) * 100))
|
||
sellerGold := int64(order.ExchangeNum) * 100
|
||
sellerIncome := int64(math.Round(order.Rate * float64(order.ExchangeNum) * 95))
|
||
buyerGold := int64(order.ExchangeNum * 95)
|
||
|
||
if err := tx.Model(basemodel.BaseSysUser{}).Where("id", buyerID).Fields("free_gold").Scan(&buyer); err != nil {
|
||
return err
|
||
}
|
||
if buyer.FreeGold < costFree {
|
||
return fmt.Errorf("余额不足")
|
||
}
|
||
|
||
if err := tx.Model(basemodel.BaseSysUser{}).Where("id", order.PlayerID).Fields("goldbean").Scan(&seller); err != nil {
|
||
return err
|
||
}
|
||
if seller.GoldBean < sellerGold {
|
||
return fmt.Errorf("卖家余额不足")
|
||
}
|
||
|
||
res, err := tx.Model(basemodel.BaseSysUser{}).
|
||
Where("id", buyerID).
|
||
WhereGTE("free_gold", costFree).
|
||
Increment("free_gold", -costFree)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
rows, _ := res.RowsAffected()
|
||
if rows == 0 {
|
||
return fmt.Errorf("余额不足")
|
||
}
|
||
|
||
res, err = tx.Model(basemodel.BaseSysUser{}).
|
||
Where("id", order.PlayerID).
|
||
WhereGTE("goldbean", sellerGold).
|
||
Increment("goldbean", -sellerGold)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
rows, _ = res.RowsAffected()
|
||
if rows == 0 {
|
||
return fmt.Errorf("卖家余额不足")
|
||
}
|
||
|
||
if _, err = tx.Model(basemodel.BaseSysUser{}).Where("id", order.PlayerID).Increment("free_gold", sellerIncome); err != nil {
|
||
return err
|
||
}
|
||
if _, err = tx.Model(basemodel.BaseSysUser{}).Where("id", buyerID).Increment("goldbean", buyerGold); err != nil {
|
||
return err
|
||
}
|
||
|
||
res, err = tx.Model(s.Model).
|
||
Data("status", 1).
|
||
Where("id", listid).
|
||
Where("status", 0).
|
||
Update()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
rows, _ = res.RowsAffected()
|
||
if rows == 0 {
|
||
return fmt.Errorf("重复订单")
|
||
}
|
||
|
||
result = &order
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
func (s *GoldListService) Get() []model.GoldBeanOrder {
|
||
var rr []model.GoldBeanOrder
|
||
s.dbm_fix(s.Model).
|
||
Where("status", 0).
|
||
WhereGT("exchange_num", 0).
|
||
WhereGT("rate", 0).
|
||
Order("rate", "asc").
|
||
Scan(&rr)
|
||
|
||
return rr
|
||
}
|
||
func NewGoldListService(id uint32) *GoldListService {
|
||
return &GoldListService{
|
||
|
||
BaseService: BaseService{userid: id,
|
||
|
||
Service: &cool.Service{Model: model.NewGoldBeanOrder(),
|
||
Where: func(ctx context.Context) []g.Array {
|
||
admin := cool.GetAdmin(ctx)
|
||
return [][]interface{}{
|
||
{"player_id", admin.UserId, true},
|
||
}
|
||
},
|
||
ListQueryOp: &cool.QueryOp{
|
||
|
||
Extend: func(ctx g.Ctx, m *gdb.Model) *gdb.Model {
|
||
return m.WhereGT("exchange_num", 0).WhereGT("rate", 0)
|
||
},
|
||
AddOrderby: g.MapStrStr{"updateTime": "asc"},
|
||
},
|
||
InsertParam: func(ctx context.Context) g.MapStrAny {
|
||
admin := cool.GetAdmin(ctx)
|
||
return g.MapStrAny{
|
||
"player_id": admin.UserId,
|
||
}
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
}
|