You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
16 KiB
506 lines
16 KiB
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)
|
|
}
|