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

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)
}