package order import ( "errors" "fmt" "git.oa00.com/go/mysql" "log" "recook/configs" "recook/internal/back" "recook/internal/dbc" "recook/internal/libs/snow" "recook/internal/model/goods" "recook/internal/model/order" "recook/internal/model/order_preview" "recook/internal/model/shopping_trolley" "recook/internal/model/user" "recook/internal/v2/lib/jcook" "recook/internal/v2/lib/shama" "recook/internal/v2/lib/supply" "recook/internal/v2/model/jyy" goods2 "recook/internal/v2/model/recook/goods" "recook/tools" "strconv" "github.com/gin-gonic/gin" "github.com/golangkit/formatime" "github.com/jinzhu/gorm" "github.com/shopspring/decimal" ) /*创建普通订单的参数*/ type submitOrderParam struct { UserID uint `json:"userId"` PreviewOrderID uint `json:"previewOrderId"` } //var submitOrderSentinel sync.Mutex func SubmitOrder(c *gin.Context) { var p submitOrderParam err := tools.ParseParams(&p, c) if err != nil { back.Fail(c, err.Error()) return } var previewOrderInfo order_preview.Information if err = dbc.DB.First(&previewOrderInfo, "id = ?", p.PreviewOrderID).Error; err != nil { back.Err(c, err.Error()) return } orderInfo := (&order.Information{}).Reflect(&previewOrderInfo) if orderInfo.OrderType == 2 { orderInfo.ExpireTime = formatime.NewSecondFrom(orderInfo.ExpireTime.Time.AddDate(100, 0, 0)) } var u user.Information dbc.DB.First(&u, "id = ?", orderInfo.UserID) if orderInfo.OrderType == 2 && (u.Level < 2 || (u.Level == 2 && !u.IsOffline)) { back.Err(c, "订单不合法") return } // 检测地址 var previewOrderAddr order_preview.Addr { if !previewOrderInfo.IsVirtual { if err = dbc.DB.First(&previewOrderAddr, "order_id = ?", p.PreviewOrderID).Error; err != nil { back.Err(c, err.Error()) return } if previewOrderAddr.AddressID == 0 { back.Err(c, "请选择收货地址") return } } } var preOrderGoodsList []order_preview.GoodsDetail if err = dbc.DB.Find(&preOrderGoodsList, "order_id = ?", p.PreviewOrderID).Error; err != nil { back.Err(c, err.Error()) return } // 商品信息是否变化了 // 活动是否失效了 // 有没有库存 preGoodSkuMap := map[uint]*goods.Sku{} for _, v := range preOrderGoodsList { var goodsInfo goods.Information { if err = dbc.DB.First(&goodsInfo, "id = ?", v.GoodsID).Error; err != nil { back.Err(c, err.Error()) return } if !configs.IsProductionEnv() { if goodsInfo.ThirdPartyType != 0 && goodsInfo.ThirdPartyType != goods2.RecookGoodsInfoThirdPartyTypeSupply { back.Fail(c, "测试环境无法购买") return } } if goodsInfo.Hash != v.Hash { back.Fail(c, "商品信息已经发生变化,请重新下单") return } cc := goodsInfo.PublishStatus == 0 if orderInfo.OrderType == 2 { cc = goodsInfo.SalePublish == 0 } if cc { back.Fail(c, "商品已下架:"+goodsInfo.GoodsName) return } } var sku goods.Sku { if !goodsInfo.IsVipGoods() { if err = dbc.DB.Select("id, inventory, sale_inventory").First(&sku, "id = ?", v.SkuID).Error; err != nil { back.Err(c, err.Error()) return } // 仅考虑商品库存 condition := orderInfo.OrderType != 2 // 批发不需要验证库存 //if orderInfo.OrderType == 2 { // condition = v.Quantity > sku.SaleInventory //} if condition { if v.Quantity > sku.Inventory { back.Fail(c, v.GoodsName+"已被抢光啦") return } } preGoodSkuMap[v.ID] = &sku } if goodsInfo.IsVipGoods() && u.IsVip() { back.Fail(c, "无须购买会员卡") return } } } var previewOrderShoppingTrolleyInfos []order_preview.ShoppingTrolleyInfo if orderInfo.OrderType == 1 && previewOrderInfo.Channel == 1 { err = dbc.DB.Find(&previewOrderShoppingTrolleyInfos, "order_id = ?", p.PreviewOrderID).Error if err != nil && !gorm.IsRecordNotFoundError(err) { back.Err(c, err.Error()) return } } data := make(map[uint][]order_preview.GoodsDetail) fData := make(map[uint]decimal.Decimal) virtualID := GetVirtualID() tx := dbc.DB.Begin() { 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 = uint(orderID) for vendor, value := range data { id1, err := work.NextID() if err != nil { back.Err(c, err.Error()) return } orderCopy := order.Information{ ID: uint(id1), AncestorID: orderInfo.AncestorID, ParentID: orderInfo.ParentID, SharerID: orderInfo.SharerID, LiveId: orderInfo.LiveId, UserID: orderInfo.UserID, Title: value[0].GoodsName, BrandCouponTotalAmount: decimal.Decimal{}, UniverseCouponTotalAmount: decimal.Decimal{}, CoinTotalAmount: decimal.Decimal{}, ExpressTotalFee: decimal.Decimal{}, GoodsTotalAmount: decimal.Decimal{}, GoodsTotalCommission: decimal.Decimal{}, ActualTotalAmount: decimal.Decimal{}, Channel: orderInfo.Channel, ShippingMethod: orderInfo.ShippingMethod, StoreID: orderInfo.StoreID, BuyerMessage: orderInfo.BuyerMessage, Status: orderInfo.Status, ExpressStatus: orderInfo.ExpressStatus, InvoiceStatus: orderInfo.InvoiceStatus, EvaluatedAt: orderInfo.EvaluatedAt, CreatedAt: orderInfo.CreatedAt, ExpireTime: orderInfo.ExpireTime, PayIP: orderInfo.PayIP, TradeNo: orderInfo.TradeNo, PayTime: orderInfo.PayTime, PayMethod: orderInfo.PayMethod, CompletedAt: orderInfo.CompletedAt, IsFirst: orderInfo.IsFirst, VirtualID: virtualID, Cost: orderInfo.Cost, OrderType: orderInfo.OrderType, IsSplit: orderInfo.IsSplit, } kind := 0 switch vendor { case 1800, 2000: channelOrderID := strconv.Itoa(int(orderCopy.ID)) resp, err := JdOrderSubmit(tx, c.ClientIP(), data, vendor, previewOrderAddr, fData, channelOrderID) if err != nil { log.Println("订单生成失败:", err.Error()) back.Err(c, err.Error()) tx.Rollback() return } if vendor == 1800 { kind = 1 } else { kind = 2 } orderCopy.Kind = kind fmt.Println("订单号为", resp.OrderID) orderCopy.JCookOrderID = resp.OrderID case 3000: channelOrderID := strconv.Itoa(int(orderCopy.ID)) resp, err := ShaMaOrderSubmit(tx, c.ClientIP(), data, vendor, previewOrderAddr, fData, channelOrderID) if err != nil { log.Println("订单生成失败:", err.Error()) back.Err(c, err.Error()) tx.Rollback() return } orderCopy.Kind = 3 orderCopy.ShaMaOrderID = resp.OrderID case 4000: channelOrderID := strconv.Itoa(int(orderCopy.ID)) thirdPartyOrderSn, err := SupplyOrderSubmit(tx, c.ClientIP(), data, vendor, previewOrderAddr, fData, channelOrderID) if err != nil { log.Println("订单生成失败:", err.Error()) back.Err(c, err.Error()) tx.Rollback() return } orderCopy.Kind = 4 orderCopy.ThirdPartyType = goods2.RecookGoodsInfoThirdPartyTypeSupply orderCopy.ThirdPartyOrderSn = thirdPartyOrderSn } if condition { orderInfo.ID = orderCopy.ID orderCopy.VirtualID = orderCopy.ID } for _, v := range value { orderCopy.BrandCouponTotalAmount = orderCopy.BrandCouponTotalAmount.Add(v.BrandCouponAmount) orderCopy.UniverseCouponTotalAmount = orderCopy.UniverseCouponTotalAmount.Add(v.UniverseCouponAmount) orderCopy.CoinTotalAmount = orderCopy.CoinTotalAmount.Add(v.CoinAmount) orderCopy.ExpressTotalFee = orderCopy.ExpressTotalFee.Add(v.ExpressFee) orderCopy.GoodsTotalAmount = orderCopy.GoodsTotalAmount.Add(v.GoodsAmount) orderCopy.GoodsTotalCommission = orderCopy.GoodsTotalCommission.Add(v.TotalCommission) orderCopy.ActualTotalAmount = orderCopy.ActualTotalAmount.Add(v.ActualAmount) } if err = tx.Create(&orderCopy).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } orderAddr := (&order.Addr{}).Reflect(&previewOrderAddr, &orderCopy) if err = tx.Create(orderAddr).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } for _, v := range value { goodsDetail := (&order.GoodsDetail{}).Reflect(&v, &orderCopy) if err = tx.Create(goodsDetail).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } sku := preGoodSkuMap[v.ID] if orderCopy.OrderType == 1 && !orderCopy.IsSplit && sku.ID != 0 { // 仅考虑商品库存的情况 if err = tx.Model(sku).UpdateColumn("inventory", gorm.Expr("inventory - ?", v.Quantity)).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } } if orderInfo.OrderType == 1 && !orderCopy.IsSplit { if err = tx.Model(sku).UpdateColumn("sales_volume", gorm.Expr("sales_volume + ?", v.Quantity)).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } } if orderInfo.OrderType == 2 { if err = tx.Model(sku).UpdateColumn("sale_volume", gorm.Expr("sale_volume + ?", v.Quantity)).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } } } } // 如果是购物车下单 则要清除一下购物车 for _, v := range previewOrderShoppingTrolleyInfos { err = tx.Delete(shopping_trolley.Information{ID: v.TrolleyID}).Error if err != nil { back.Err(c, err.Error()) tx.Rollback() return } } if orderInfo.OrderType == 2 && orderInfo.Channel == 1 { ids := make([]uint, 0) for _, v := range preGoodSkuMap { ids = append(ids, v.ID) tx.Delete(&jyy.ShopCartEntry{}, "sku_id in (?) and user_id = ?", ids, p.UserID) } } } tx.Commit() if len(data) > 1 { orderInfo.ID = virtualID } back.Suc(c, "提交成功,请20分钟内完成付款", orderInfo) } func JdOrderSubmit(tx *gorm.DB, ip string, data map[uint][]order_preview.GoodsDetail, vendor uint, previewOrderAddr order_preview.Addr, fData map[uint]decimal.Decimal, channelOrderID string) (jcook.OrderSubmitResp, error) { client := jcook.GetClient() t := make([]jcook.LogisticsInfo, 0) orderFee := decimal.Zero for _, j := range data[vendor] { var sku goods.Sku if err := tx.First(&sku, "id = ?", j.SkuID).Error; err != nil { return jcook.OrderSubmitResp{}, err } cid, _ := strconv.Atoi(sku.ThirdPartySkuId) t = append(t, jcook.LogisticsInfo{ SkuID: uint(cid), Quantity: j.Quantity, SkuPrice: sku.PurchasePrice, }) amount := sku.PurchasePrice.Mul(decimal.NewFromInt(int64(j.Quantity))) orderFee = orderFee.Add(amount) } addr := previewOrderAddr.Province + previewOrderAddr.City + previewOrderAddr.District + previewOrderAddr.Address req1 := jcook.OrderSubmitReq{ Address: addr, SkuList: t, OrderFee: orderFee, Receiver: jcook.OrderReceiver{ Name: previewOrderAddr.ReceiverName, Mobile: previewOrderAddr.Mobile, }, FreightFee: fData[vendor], UserIp: ip, ChannelOrderID: channelOrderID, } var resp jcook.OrderSubmitResp if err := client.Exec(req1, &resp); err != nil { if err.Error() == "商品价格不匹配" { go func() { rq := jcook.SkuPriceReq{} for _, info := range t { rq.SkuIDSet = append(rq.SkuIDSet, info.SkuID) } var res []jcook.SkuPriceResp if err := client.Exec(rq, &res); err != nil { return } if len(res) == 0 { return } for _, t := range res { var sku goods2.RecookGoodsSkuModel if err := mysql.Db.Table(sku.TableName()).Where("third_party_sku_id = ? and third_party_type=3", strconv.FormatUint(uint64(t.SkuID), 10)).Updates(map[string]interface{}{ "purchase_price": t.SupplyPrice, }).Error; err != nil { log.Println(err.Error()) return } } }() return jcook.OrderSubmitResp{}, errors.New("价格变动,请重新下单") } return jcook.OrderSubmitResp{}, err } return resp, nil } func ShaMaOrderSubmit(tx *gorm.DB, ip string, data map[uint][]order_preview.GoodsDetail, vendor uint, previewOrderAddr order_preview.Addr, fData map[uint]decimal.Decimal, channelOrderID string) (shama.OrderSubmitResp, error) { client := shama.GetClient() t := make([]shama.LogisticsInfo, 0) orderFee := decimal.Zero for _, j := range data[vendor] { var sku goods.Sku if err := tx.First(&sku, "id = ?", j.SkuID).Error; err != nil { return shama.OrderSubmitResp{}, err } cid, _ := strconv.Atoi(sku.ThirdPartySkuId) t = append(t, shama.LogisticsInfo{ SkuID: uint(cid), Quantity: j.Quantity, SkuPrice: sku.PurchasePrice, }) amount := sku.PurchasePrice.Mul(decimal.NewFromInt(int64(j.Quantity))) orderFee = orderFee.Add(amount) } addr := previewOrderAddr.Province + previewOrderAddr.City + previewOrderAddr.District + previewOrderAddr.Address req1 := shama.OrderSubmitReq{ Address: addr, SkuList: t, OrderFee: orderFee, Receiver: shama.OrderReceiver{ Name: previewOrderAddr.ReceiverName, Mobile: previewOrderAddr.Mobile, }, FreightFee: fData[vendor], UserIp: ip, ChannelOrderID: channelOrderID, } var resp shama.OrderSubmitResp if err := client.Exec(req1, &resp); err != nil { return shama.OrderSubmitResp{}, err } return resp, nil } func SupplyOrderSubmit(tx *gorm.DB, ip string, data map[uint][]order_preview.GoodsDetail, vendor uint, previewOrderAddr order_preview.Addr, fData map[uint]decimal.Decimal, channelOrderID string) (supplyOrderSn string, err error) { orderFee := decimal.Zero var freightFeeItems []supply.OrderFreightFeeItem for _, j := range data[vendor] { var sku goods.Sku if err := tx.First(&sku, "id = ?", j.SkuID).Error; err != nil { return supplyOrderSn, errors.New("商品错误") } supplySkuId, _ := strconv.Atoi(sku.ThirdPartySkuId) freightFeeItems = append(freightFeeItems, supply.OrderFreightFeeItem{ SkuId: uint(supplySkuId), Quantity: j.Quantity, Price: sku.PurchasePrice, }) orderFee = orderFee.Add(sku.PurchasePrice.Mul(decimal.NewFromInt(int64(j.Quantity)))) } addr := previewOrderAddr.Province + previewOrderAddr.City + previewOrderAddr.District + previewOrderAddr.Address freightFees, err := supply.Api.Order.FreightFee(addr, freightFeeItems) if err != nil { return } var orderFreightFees []supply.OrderFreightFee totalFreightFee := decimal.Zero for _, freightFee := range freightFees { orderFreightFees = append(orderFreightFees, supply.OrderFreightFee{ SkuIds: freightFee.SkuIds, FreightFee: decimal.NewFromFloat(freightFee.FreightFee), }) totalFreightFee = totalFreightFee.Add(decimal.NewFromFloat(freightFee.FreightFee)) } if fData[vendor].Cmp(totalFreightFee) != 0 { return supplyOrderSn, errors.New("运费错误") } submit, err := supply.Api.Order.Submit(supply.OrderSubmit{ ChannelOrderSn: channelOrderID, Address: addr, Skus: freightFeeItems, Receiver: supply.Receiver{ Name: previewOrderAddr.ReceiverName, Mobile: previewOrderAddr.Mobile, Email: "shangmenghaishi@163.com", ZipCode: "315000", }, OrderFee: orderFee, FreightFees: orderFreightFees, UserIp: ip, }) if err != nil { return supplyOrderSn, err } return submit.OrderSn, nil } func GetVirtualID() uint { id, _ := snow.GetOrderWorker().NextID() return uint(id) }