From 0e43b14436494c2c9ec44da74aba6f93df10cc3b Mon Sep 17 00:00:00 2001 From: howell <2827207845@qq.com> Date: Wed, 8 Dec 2021 12:04:33 +0800 Subject: [PATCH] feat: change order id --- internal/api/mobile/order/submit.go | 193 +++------------------------- internal/libs/snow/snow.go | 89 +++++++++++++ 2 files changed, 109 insertions(+), 173 deletions(-) create mode 100644 internal/libs/snow/snow.go diff --git a/internal/api/mobile/order/submit.go b/internal/api/mobile/order/submit.go index 8261ff1..b34fd7e 100755 --- a/internal/api/mobile/order/submit.go +++ b/internal/api/mobile/order/submit.go @@ -2,28 +2,23 @@ package order import ( "fmt" + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" "github.com/shopspring/decimal" "log" - order_preview2 "recook/internal/api/mobile/order_preview" "recook/internal/back" "recook/internal/dbc" - "recook/internal/model/coupon" + "recook/internal/libs/snow" "recook/internal/model/goods" "recook/internal/model/order" "recook/internal/model/order_preview" "recook/internal/model/promotion" "recook/internal/model/shopping_trolley" "recook/internal/model/user" - "recook/internal/v2/controller/task" "recook/internal/v2/lib/jcook" goods3 "recook/internal/v2/model/recook/goods" "recook/tools" "strconv" - "sync" - "time" - - "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" ) /*创建普通订单的参数*/ @@ -32,20 +27,8 @@ type submitOrderParam struct { PreviewOrderID uint `json:"previewOrderId"` } -var submitOrderSentinel sync.Mutex +//var submitOrderSentinel sync.Mutex -/* -提交订单 用户在订单预览界面时,完全不提交,10分钟再提交。此时判断活动,地址 商品信息,库存等是否发生了变化,变化了则提交失败,需要重新购买 - -生成订单记录 -删除预览订单信息 -如果是购物车下单 删除购物车商品 - -减去库存/活动库存 销量增加 - -标记自己的优惠券状态为使用过 -扣除瑞币 -*/ func SubmitOrder(c *gin.Context) { var p submitOrderParam err := tools.ParseParams(&p, c) @@ -54,12 +37,6 @@ func SubmitOrder(c *gin.Context) { return } - submitOrderSentinel.Lock() - defer submitOrderSentinel.Unlock() - - // 验证库存 验证优惠券是否失效 验证活动 验证金额是否匹配 - now := time.Now().Unix() - var previewOrderInfo order_preview.Information if err = dbc.DB.First(&previewOrderInfo, "id = ?", p.PreviewOrderID).Error; err != nil { back.Err(c, err.Error()) @@ -83,47 +60,6 @@ func SubmitOrder(c *gin.Context) { } } - // 钱包的瑞币是否足够支付 - var wallet user.Wallet - { - if err = dbc.DB.First(&wallet, "user_id = ?", p.UserID).Error; err != nil { - back.Err(c, err.Error()) - return - } - if wallet.Coin.LessThan(previewOrderInfo.CoinTotalAmount) { - back.Fail(c, "瑞币不足,请重新购买") - return - } - } - - // 优惠券是否可用 - var preOrderCouponList []order_preview.CouponDetail - if err = dbc.DB.Find(&preOrderCouponList, "order_id = ?", p.PreviewOrderID).Error; err != nil && false == gorm.IsRecordNotFoundError(err) { - back.Err(c, err.Error()) - return - } - - personalCouponMidList := make([]*coupon.ReceiverMid, 0, 0) - for _, v := range preOrderCouponList { - var couponMid coupon.ReceiverMid - if err = dbc.DB.First(&couponMid, "id = ?", v.PersonalCouponID).Error; err != nil { - back.Err(c, err.Error()) - return - } - - if couponMid.Status == 1 { - back.Fail(c, "优惠券已在其他订单使用,请重新下单") - return - } - - if couponMid.EndTime.Time.Unix() < now { - back.Fail(c, "优惠券已过期,请重新下单") - return - } - - personalCouponMidList = append(personalCouponMidList, &couponMid) - } - var preOrderGoodsList []order_preview.GoodsDetail if err = dbc.DB.Find(&preOrderGoodsList, "order_id = ?", p.PreviewOrderID).Error; err != nil { back.Err(c, err.Error()) @@ -149,17 +85,6 @@ func SubmitOrder(c *gin.Context) { back.Err(c, err.Error()) return } - if goodsInfo.ThirdPartyType == goods3.RecookGoodsInfoThirdPartyTypeJingtong { - jingtong := &task.Jingtong{} - if err := jingtong.Update(goodsInfo.ThirdPartyId); err != nil { - back.Err(c, err.Error()) - return - } - if err = dbc.DB.Select("hash, publish_status,third_party_id,third_party_type").First(&goodsInfo, "id = ?", v.GoodsID).Error; err != nil { - back.Err(c, err.Error()) - return - } - } if goodsInfo.Hash != v.Hash { back.Fail(c, "商品信息已经发生变化,请重新下单") @@ -217,31 +142,30 @@ func SubmitOrder(c *gin.Context) { data := make(map[uint][]order_preview.GoodsDetail) fData := make(map[uint]decimal.Decimal) - var lastId uint virtualID := GetVirtualID() tx := dbc.DB.Begin() { - sql := `select max(id)+floor(1+rand()*50) from recook_order_info` - if err = tx.Raw(sql).Count(&lastId).Error; err != nil { - back.Err(c, err.Error()) - tx.Rollback() - return - } - for _, value := range preOrderGoodsList { data[value.VendorID] = append(data[value.VendorID], value) fData[value.VendorID] = fData[value.VendorID].Add(value.ExpressFee) } + work := snow.GetOrderWorker() + orderID, err := work.NextID() + if err != nil { + back.Err(c, err.Error()) + return + } condition := len(data) == 1 - orderInfo.ID = lastId - var count uint = 0 + orderInfo.ID = uint(orderID) for vendor, value := range data { - //if vendor == 1800 || vendor== 2000 { - // continue - //} + id1, err := work.NextID() + if err != nil { + back.Err(c, err.Error()) + return + } orderCopy := order.Information{ - ID: lastId + count, + ID: uint(id1), AncestorID: orderInfo.AncestorID, ParentID: orderInfo.ParentID, SharerID: orderInfo.SharerID, @@ -276,7 +200,7 @@ func SubmitOrder(c *gin.Context) { } kind := 0 if vendor == 1800 || vendor == 2000 { - channelOrderID := strconv.Itoa(int(lastId + count)) + channelOrderID := strconv.Itoa(int(orderCopy.ID)) resp, err := JdOrderSubmit(tx, c.ClientIP(), data, vendor, previewOrderAddr, fData, channelOrderID) if err != nil { log.Println("订单生成失败:", err.Error()) @@ -296,7 +220,6 @@ func SubmitOrder(c *gin.Context) { if condition { orderCopy.VirtualID = orderCopy.ID } - count += 1 for _, v := range value { orderCopy.BrandCouponTotalAmount = orderCopy.BrandCouponTotalAmount.Add(v.BrandCouponAmount) orderCopy.UniverseCouponTotalAmount = orderCopy.UniverseCouponTotalAmount.Add(v.UniverseCouponAmount) @@ -319,39 +242,9 @@ func SubmitOrder(c *gin.Context) { tx.Rollback() return } - //判断是否为秒杀商品 - smp := make(map[uint]uint) - now1 := previewOrderInfo.CreatedAt.Time - for _, v := range preOrderGoodsList { - res, _ := order_preview2.IfSecKill(now1, v.SkuID) - if res.Id > 0 { - //秒杀中 - num := res.RealStock.Sub(decimal.NewFromInt(int64(v.Quantity))) - if num.LessThan(decimal.Zero) { - back.Err(c, "库存不足") - tx.Rollback() - return - } else { - //库存更新 - err = tx.Table(res.TableName()).Where("id=?", res.Id).Update("real_stock", num).Error - if err != nil { - back.Err(c, err.Error()) - tx.Rollback() - return - } - } - smp[v.SkuID] = res.SecKillActivityId - } else { - continue - } - } for _, v := range value { goodsDetail := (&order.GoodsDetail{}).Reflect(&v, &orderCopy) - if _, ok := smp[v.SkuID]; ok { - goodsDetail.ActivityStatus = 1 - goodsDetail.ActivityId = smp[v.SkuID] - } if err = tx.Create(goodsDetail).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() @@ -371,45 +264,6 @@ func SubmitOrder(c *gin.Context) { } } - if orderCopy.CoinTotalAmount.GreaterThan(decimal.NewFromFloat(0.0)) { - // 标记瑞币, 即扣除了总额 - if err = tx.Model(&wallet).Updates(map[string]interface{}{ - "coin": wallet.Coin.Sub(orderCopy.CoinTotalAmount), - }).Error; err != nil { - back.Err(c, err.Error()) - tx.Rollback() - return - } - - // 加入流水记录, 直接加在coinHistory中 - var uCoinHis user.CoinHistory - uCoinHis.UserID = p.UserID - uCoinHis.CoinNum = orderCopy.CoinTotalAmount.Neg() - uCoinHis.CoinType = user.PurchasedTypeForCoinHistory - uCoinHis.OrderId = orderCopy.ID - uCoinHis.CreatedAt = orderCopy.CreatedAt - uCoinHis.Remark = "订单扣除" - - if err := dbc.DB.Create(&uCoinHis).Error; err != nil { - back.Err(c, err.Error()) - tx.Rollback() - return - } - - walletCoinDetail := user.WalletCoinList{ - UserID: wallet.UserID, - Number: int64(orderCopy.CoinTotalAmount.IntPart()), - Title: orderCopy.Title, - Comment: "订单支付抵扣", - OrderID: orderCopy.ID, - } - if err = tx.Create(&walletCoinDetail).Error; err != nil { - back.Err(c, err.Error()) - tx.Rollback() - return - } - } - } // 如果是购物车下单 则要清除一下购物车 @@ -468,14 +322,7 @@ func JdOrderSubmit(tx *gorm.DB, ip string, data map[uint][]order_preview.GoodsDe return resp, nil } -const initCount int64 = 20210624681 - func GetVirtualID() uint { - result := dbc.Rds.Incr("order_count") - if r, err := result.Result(); err != nil { - log.Println(err.Error()) - return uint(time.Now().Unix()) * 10 - } else { - return uint(r + initCount) - } + id, _ := snow.GetOrderWorker().NextID() + return uint(id) } diff --git a/internal/libs/snow/snow.go b/internal/libs/snow/snow.go new file mode 100644 index 0000000..e287441 --- /dev/null +++ b/internal/libs/snow/snow.go @@ -0,0 +1,89 @@ +package snow + +import ( + "errors" + "sync" + "time" +) + +var OrderWorker *Worker +var once sync.Once + +func GetOrderWorker() *Worker { + once.Do(func() { + OrderWorker = NewWorker(1, 1) + }) + return OrderWorker +} + +const ( + workerIDBits = uint64(4) + businessIDBits = uint64(4) + sequenceBits = uint64(14) + + maxWorkerID = int64(-1) ^ (int64(-1) << workerIDBits) + maxBusinessID = int64(-1) ^ (int64(-1) << businessIDBits) + maxSequence = int64(-1) ^ (int64(-1) << sequenceBits) + + timeLeft = uint8(22) // 6 + 4 + 12 + workLeft = uint8(18) // 4 + 12 + businessLeft = uint(14) // 12 + + initialisierung = int64(1638935759) +) + +type Worker struct { + mu sync.Mutex + LastStamp int64 + WorkerID int64 + BusinessID int64 + Sequence int64 // 当前毫秒已经生成的ID序列号(从0 开始累加) 1毫秒内最多生成4096个ID +} + +func NewWorker(workerID, businessID int64) *Worker { + return &Worker{ + WorkerID: workerID, + LastStamp: 0, + Sequence: 0, + BusinessID: businessID, + } +} + +func (w *Worker) getMilliSeconds() int64 { + return time.Now().Unix() +} + +func (w *Worker) NextID() (uint64, error) { + w.mu.Lock() + defer w.mu.Unlock() + + return w.nextID() +} + +func (w *Worker) nextID() (uint64, error) { + timeStamp := w.getMilliSeconds() + if timeStamp < w.LastStamp { + return 0, errors.New("time is moving backwards,waiting until") + } + + if w.LastStamp == timeStamp { + + w.Sequence = (w.Sequence + 1) & maxSequence + + if w.Sequence == 0 { + for timeStamp <= w.LastStamp { + timeStamp = w.getMilliSeconds() + } + } + } else { + w.Sequence = 0 + } + + w.LastStamp = timeStamp + id := ((timeStamp - initialisierung) << timeLeft) | + (w.WorkerID << workLeft) | + (w.BusinessID << businessLeft) | + w.Sequence + + return uint64(id), nil +}