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.

480 lines
15 KiB

4 years ago
package order_preview
import (
"math"
"recook/internal/back"
"recook/internal/dbc"
"recook/internal/model/freight"
"recook/internal/model/goods"
"recook/internal/model/order_preview"
"recook/internal/model/promotion"
"recook/internal/model/user"
"recook/internal/model/vend"
"recook/internal/service/baseCode"
4 years ago
"recook/internal/v2/lib/jcook"
4 years ago
"recook/internal/v2/lib/shama"
4 years ago
"recook/internal/v2/model/flashsale"
"recook/tools"
4 years ago
"strconv"
4 years ago
"time"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/shopspring/decimal"
)
/*普通订单预览的参数*/
type previewNormalOrderParam struct {
4 years ago
UserID uint `json:"userId" validate:"required"`
SkuID uint `json:"skuId" validate:"required"`
Quantity uint `json:"quantity" validate:"required"`
ParentID uint `json:"parentId"` // 可选字段 如果是链接分享 则传入该字段代表分享者的id。 没有的话。就是上级的id顶级用户没有
UseCoin int `json:"useCoin"` //默认0 开启 1 关闭
LiveId uint `json:"liveId"` //直播间id
Address string `json:"address"`
4 years ago
InvitationNo string `json:"invite"`
4 years ago
}
4 years ago
// CreatePreviewNormalOrder 创建普通订单,从商品详情页直接点击《立即购买》按钮进入购买页面,客户端不计算价格,服务端进行计算。
// 明天参加活动的商品不允许购买
4 years ago
func CreatePreviewNormalOrder(c *gin.Context) {
var p previewNormalOrderParam
err := tools.ParseParams(&p, c)
if err != nil {
back.Fail(c, err.Error())
return
}
if p.UserID <= 0 {
back.Fail(c, "游客无法使用该功能,请先登录")
return
}
if p.Quantity > 50 {
back.Fail(c, "单件最多拍50件")
return
}
var ancestorID uint = 0
var myInfo user.Information
if err := dbc.DB.First(&myInfo, p.UserID).Error; err != nil {
back.Err(c, err.Error())
return
}
ancestorID = myInfo.AncestorID
sharerId := myInfo.ID
if p.InvitationNo != "" {
sharerId = uint(baseCode.Decode(p.InvitationNo))
}
4 years ago
if sharerId == 0 {
sharerId = myInfo.ID
}
4 years ago
preOrderInfo := &order_preview.Information{}
preOrderAddr := &order_preview.Addr{}
preOrderGoods := &order_preview.GoodsDetail{}
actualAmount := decimal.NewFromFloat(0.0)
unitPrice := decimal.NewFromFloat(0.0) // 单价
expressFee := decimal.NewFromFloat(0.0) // 快递费
commission := decimal.NewFromInt(0)
brandCouponReducePrice := decimal.NewFromFloat(0.0) // 品牌优惠券抵扣的价格
universeCouponReducePrice := decimal.NewFromFloat(0.0) // 通用优惠券抵扣的价格
coinReducePrice := decimal.NewFromFloat(0.0) // 使用瑞币的价格
mainPhotoURL := ""
// 首先检测库存
var sku goods.Sku
cost := decimal.Zero
4 years ago
{
err = dbc.DB.First(&sku, "id = ?", p.SkuID).Error
if err != nil {
back.Err(c, err.Error())
return
}
cost = cost.Add(cost.Add(sku.PurchasePrice.Mul(decimal.NewFromInt(int64(p.Quantity)))))
4 years ago
}
var promotionGoods promotion.Goods
var promotionSku promotion.Sku
dbc.DB.First(&promotionGoods, "goods_id = ? AND start_time <= ? AND end_time > ?", sku.GoodsID, time.Now(), time.Now())
if promotionGoods.ID == 0 {
dbc.DB.First(&promotionGoods, "goods_id = ? AND start_time > ?", sku.GoodsID, time.Now())
}
// 仅考虑商品的库存
dbc.DB.First(&promotionSku, "promotion_goods_id = ? AND sku_id = ?", promotionGoods.ID, p.SkuID)
if p.Quantity > sku.Inventory {
back.Fail(c, "库存不足")
return
}
unitPrice = sku.DiscountPrice
commission = sku.Commission
mainPhotoURL = sku.PicURL
if len(sku.PicURL) == 0 { // 使用主图
var mainPhoto goods.MainPhoto
err := dbc.DB.First(&mainPhoto, "goods_id = ? AND is_master = 1", sku.GoodsID).Error
if err != nil {
back.Fail(c, err.Error())
return
}
mainPhotoURL = mainPhoto.URL
}
if unitPrice.LessThan(decimal.NewFromFloat(0.01)) {
back.Err(c, "当前商品价格太低。内部错误")
return
}
var defaultAddr user.Addr
{
err = dbc.DB.First(&defaultAddr, "user_id = ? AND is_default = 1", p.UserID).Error
if err != nil && false == gorm.IsRecordNotFoundError(err) {
back.Err(c, err.Error())
return
}
}
if sku.ThirdPartyType == 3 && p.Address == "" && defaultAddr.ID == 0 {
back.Err(c, "请填写默认收货地址")
return
}
var goodsInfo goods.Information
{
err = dbc.DB.First(&goodsInfo, "id = ?", sku.GoodsID).Error
if err != nil {
back.Err(c, err.Error())
return
}
if goodsInfo.PublishStatus == 0 {
back.Fail(c, "商品已下架:"+goodsInfo.GoodsName)
return
}
}
4 years ago
if (sku.ThirdPartyType != 0 && defaultAddr.ID > 0) || p.Address != "" {
4 years ago
// 京东商品查询物流信息
4 years ago
switch sku.ThirdPartyType {
case 3:
client := jcook.GetClient()
if len(p.Address) == 0 {
p.Address = defaultAddr.GetAddress()
}
id, _ := strconv.Atoi(sku.ThirdPartySkuId)
req := jcook.SkuStockReq{
Address: p.Address,
SkuList: []jcook.SkuQuantity{
{
uint(id),
1,
},
4 years ago
},
4 years ago
}
var resp []jcook.SkuStockResp
if err = client.Exec(req, &resp); err != nil {
back.Err(c, err.Error())
4 years ago
return
}
4 years ago
for _, v := range resp {
if v.StockState == 0 {
back.Err(c, "该地区该商品无货")
return
}
}
req1 := jcook.LogisticsFeeReq{
Address: p.Address,
SkuList: []jcook.LogisticsInfo{
{
uint(id),
p.Quantity,
sku.PurchasePrice,
},
4 years ago
},
4 years ago
OrderFee: sku.PurchasePrice.Mul(decimal.NewFromInt(int64(p.Quantity))),
}
var resp2 jcook.LogisticsFeeResp
if err := client.Exec(req1, &resp2); err != nil {
back.Err(c, err.Error())
return
}
expressFee = resp2.Fee
preOrderAddr.IsDeliveryArea = 1
case 4:
client := shama.GetClient()
if len(p.Address) == 0 {
p.Address = defaultAddr.GetAddress()
}
id, _ := strconv.Atoi(sku.ThirdPartySkuId)
req := shama.SkuStockReq{
Address: p.Address,
SkuList: []shama.SkuQuantity{
{
uint(id),
1,
},
},
}
var resp []shama.SkuStockResp
if err = client.Exec(req, &resp); err != nil {
back.Err(c, err.Error())
return
}
for _, v := range resp {
if v.StockState == 0 {
back.Err(c, "该地区该商品无货")
return
}
}
req1 := shama.LogisticsFeeReq{
Address: p.Address,
SkuList: []shama.LogisticsInfo{
{
uint(id),
p.Quantity,
sku.PurchasePrice,
},
},
OrderFee: sku.PurchasePrice.Mul(decimal.NewFromInt(int64(p.Quantity))),
}
var resp2 shama.LogisticsFeeResp
if err := client.Exec(req1, &resp2); err != nil {
back.Err(c, err.Error())
return
}
expressFee = resp2.Fee
preOrderAddr.IsDeliveryArea = 1
4 years ago
}
} else if defaultAddr.ID > 0 {
canDelivery, expFee, err := computeExpressFeeWithGoods(p.Quantity, &goodsInfo, defaultAddr.Province, defaultAddr.City)
if err != nil {
back.Err(c, err.Error())
return
}
if canDelivery {
expressFee = expFee
preOrderAddr.IsDeliveryArea = 1
}
}
var brandInfo goods.Brand
{
err = dbc.DB.First(&brandInfo, "id = ?", goodsInfo.BrandID).Error
if err != nil {
back.Err(c, err.Error())
return
}
}
var firCate goods.Category
var secCate goods.Category
dbc.DB.Select("name").First(&firCate, goodsInfo.FirstCategoryID)
dbc.DB.Select("name").First(&secCate, goodsInfo.SecondCategoryID)
vendorName := "自营"
var vendor vend.Information
{
if goodsInfo.VendorID > 0 {
err = dbc.DB.Select("id, username").First(&vendor, "id = ?", goodsInfo.VendorID).Error
if err != nil {
back.Err(c, err.Error())
return
}
vendorName = vendor.Username
}
}
actualAmount = unitPrice.Mul(decimal.NewFromInt(int64(p.Quantity))).Add(expressFee)
4 years ago
tx := dbc.DB.Begin()
{
{
preOrderInfo.AncestorID = ancestorID
preOrderInfo.ParentID = myInfo.ParentID
preOrderInfo.SharerID = sharerId
4 years ago
preOrderInfo.LiveId = p.LiveId
preOrderInfo.UserID = p.UserID
preOrderInfo.Title = goodsInfo.GoodsName
preOrderInfo.BrandCouponTotalAmount = brandCouponReducePrice
preOrderInfo.UniverseCouponTotalAmount = universeCouponReducePrice
preOrderInfo.CoinTotalAmount = coinReducePrice
preOrderInfo.ExpressTotalFee = expressFee
preOrderInfo.GoodsTotalAmount = unitPrice.Mul(decimal.NewFromInt(int64(p.Quantity)))
preOrderInfo.GoodsTotalCommission = commission.Mul(decimal.NewFromInt(int64(p.Quantity)))
preOrderInfo.ActualTotalAmount = actualAmount
preOrderInfo.Cost = cost
4 years ago
err = tx.Create(&preOrderInfo).Error
if err != nil {
back.Err(c, err.Error())
tx.Rollback()
return
}
}
// 地址
{
preOrderAddr.OrderID = preOrderInfo.ID
preOrderAddr.Province = defaultAddr.Province
preOrderAddr.City = defaultAddr.City
preOrderAddr.District = defaultAddr.District
preOrderAddr.ReceiverName = defaultAddr.Name
preOrderAddr.Mobile = defaultAddr.Mobile
preOrderAddr.AddressID = defaultAddr.ID
preOrderAddr.Address = defaultAddr.Address
err = tx.Create(&preOrderAddr).Error
if err != nil {
back.Err(c, err.Error())
tx.Rollback()
return
}
}
{
preOrderGoods.OrderID = preOrderInfo.ID
preOrderGoods.VendorID = goodsInfo.VendorID
preOrderGoods.VendorName = vendorName
preOrderGoods.BrandID = brandInfo.ID
preOrderGoods.BrandName = brandInfo.Name
preOrderGoods.CategoryName = firCate.Name + "/" + secCate.Name
preOrderGoods.GoodsID = goodsInfo.ID
preOrderGoods.GoodsName = goodsInfo.GoodsName
preOrderGoods.IsJoinTeamPerformance = goodsInfo.IsJoinTeamPerformance
preOrderGoods.Hash = goodsInfo.Hash
preOrderGoods.SkuID = sku.ID
preOrderGoods.SkuName = sku.Name
preOrderGoods.SkuCode = sku.Code
preOrderGoods.MainPhotoURL = mainPhotoURL
preOrderGoods.Quantity = p.Quantity
preOrderGoods.FreightID = goodsInfo.FreightID
preOrderGoods.Weight = goodsInfo.Weight
preOrderGoods.PromotionSkuId = promotionSku.ID
preOrderGoods.PromotionGoodsId = promotionGoods.ID
preOrderGoods.PromotionName = promotionGoods.PromotionName
preOrderGoods.PromotionStartTime = promotionGoods.StartTime
preOrderGoods.PromotionEndTime = promotionGoods.EndTime
preOrderGoods.UnitPrice = unitPrice
preOrderGoods.PurchasePrice = sku.PurchasePrice
preOrderGoods.TotalCommission = preOrderInfo.GoodsTotalCommission
preOrderGoods.BrandCouponAmount = brandCouponReducePrice
preOrderGoods.UniverseCouponAmount = universeCouponReducePrice
preOrderGoods.CoinAmount = coinReducePrice
preOrderGoods.GoodsAmount = unitPrice.Mul(decimal.NewFromInt(int64(p.Quantity)))
preOrderGoods.ExpressFee = expressFee
preOrderGoods.ActualAmount = actualAmount
preOrderGoods.IsImport = goodsInfo.IsImport
preOrderGoods.Storehouse = goodsInfo.Storehouse
preOrderGoods.IsFerme = goodsInfo.IsFerme
err = tx.Create(&preOrderGoods).Error
if err != nil {
back.Err(c, err.Error())
tx.Rollback()
return
}
}
}
tx.Commit()
back.Suc(c, "操作成功", queryPreviewOrderGroup(preOrderInfo.ID))
}
func computeExpressFeeWithGoods(quantity uint, goodsInfo *goods.Information, province, city string) (bool, decimal.Decimal, error) {
var freightTemplateInfo freight.Information
// 只有用户有默认地址才去计算运费价格
err := dbc.DB.First(&freightTemplateInfo, "id = ?", goodsInfo.FreightID).Error
if err != nil {
return false, decimal.NewFromFloat(0.0), err
}
// 检测是否属于不发货地区
// 不发货的省
var nonDeliveryProvince freight.NoProvince
err = dbc.DB.First(&nonDeliveryProvince, "freight_id = ? AND province_name = ?", goodsInfo.FreightID, province).Error
if err != nil && false == gorm.IsRecordNotFoundError(err) {
return false, decimal.Zero, err
}
if nonDeliveryProvince.ID > 0 {
return false, decimal.NewFromFloat(0.0), nil
}
// 不发货的市
var noCitys freight.NoCitys
err = dbc.DB.First(&noCitys, "freight_id = ? AND province_name = ? and city_name = ?", goodsInfo.FreightID, province, city).Error
if err != nil && gorm.IsRecordNotFoundError(err) == false {
return false, decimal.Zero, err
}
if noCitys.ID > 0 {
return false, decimal.NewFromFloat(0.0), nil
}
// 进入该分支代表该地址可以发货 需要查询运费信息
// 先判断是不是所有地方包邮
var freightInfo freight.Information
err = dbc.DB.First(&freightInfo, "id = ?", goodsInfo.FreightID).Error
if err != nil {
return false, decimal.NewFromFloat(0.0), nil
}
if freightInfo.AllFree == 1 {
return true, decimal.NewFromFloat(0.0), nil
}
// 先找到该收货省市的信息 然后找到对应的价格表
var priceDetailID uint
// 市价格表
var deliveryCity freight.Citys
err = dbc.DB.First(&deliveryCity, "freight_id = ? AND province_name = ? and city_name = ?", goodsInfo.FreightID, province, city).Error
if deliveryCity.ID == 0 {
// 省价格表
var deliveryProvince freight.Province
err = dbc.DB.First(&deliveryProvince, "freight_id = ? AND province_name = ?", goodsInfo.FreightID, province).Error
if err != nil {
return true, decimal.Zero, nil
}
priceDetailID = deliveryProvince.PriceDetailID
} else {
priceDetailID = deliveryCity.PriceDetailID
}
var freightPrice freight.Price
dbc.DB.First(&freightPrice, "id = ?", priceDetailID)
expressFee := decimal.NewFromFloat(0.0)
if freightPrice.Type == 0 { // 按照件数计算
if quantity <= freightPrice.FirstNumber {
expressFee = freightPrice.FirstNumberFee
} else {
baseNumber := math.Ceil(float64((quantity - freightPrice.FirstNumber) / freightPrice.AdditionalNumber)) // 向上取整 意思是不满一斤算一斤
expressFee = freightPrice.FirstNumberFee.Add(decimal.NewFromFloat(baseNumber).Mul(freightPrice.AdditionalNumberFee))
}
} else if freightPrice.Type == 3 { // 固定计费
return true, freightPrice.Amount, nil
//if goodsInfo.Weight.LessThanOrEqual(freightPrice.FirstWeight) { // 小于首重
// expressFee = freightPrice.FirstWeightFee
//} else {
// baseWeight := (goodsInfo.Weight.Sub(freightPrice.FirstWeight)).Div(freightPrice.AdditionalWeight).Ceil() // 向上取整 意思是不满一斤算一斤
// expressFee = freightPrice.FirstWeightFee.Sub(baseWeight.Mul(freightPrice.AdditionalWeightFee))
//}
4 years ago
} else { // 按照重量计算
4 years ago
if goodsInfo.Weight.LessThanOrEqual(freightPrice.FirstWeight) { // 小于首重
expressFee = freightPrice.FirstWeightFee
} else {
baseWeight := (goodsInfo.Weight.Sub(freightPrice.FirstWeight)).Div(freightPrice.AdditionalWeight).Ceil() // 向上取整 意思是不满一斤算一斤
expressFee = freightPrice.FirstWeightFee.Sub(baseWeight.Mul(freightPrice.AdditionalWeightFee))
}
}
if quantity >= freightPrice.FreeNumberThreshold {
expressFee = decimal.NewFromFloat(0.0)
}
return true, expressFee, nil
}
func IfSecKill(now time.Time, skuID uint) (flashsale.RecookSecKillGoodsModel, flashsale.RecookSecKillSortModel) {
var seckill flashsale.RecookSecKillModel
dbc.DB.Table(seckill.TableName()).Where("activity_start_time<?", now).Where("activity_end_time>?", now).Where("status=2").First(&seckill)
//获取当前时间段的商品
now2 := time.Date(0, 1, 1, now.Hour(), now.Minute(), now.Second(), 0, time.Local)
var secgoods flashsale.RecookSecKillSortModel
dbc.DB.Table((&flashsale.RecookSecKillSortModel{}).TableName()).Where("show_time_start<?", now2).Where("show_time_end>?", now2).Where("sec_kill_activity_id=?", seckill.Id).Where("sku_id=?", skuID).First(&secgoods)
var gs flashsale.RecookSecKillGoodsModel
dbc.DB.Table(gs.TableName()).Where("sec_kill_activity_id=?", seckill.Id).Where("goods_sku_id=?", secgoods.SkuId).First(&gs)
return gs, secgoods
}