Commit a03eba7e by mushishixian

专营商品成本价构建逻辑

parent 9500c3c1
......@@ -52,7 +52,7 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
GoodsRes.Store(goodsId, false)
continue
}
//初始化有序map,拼接data 数据
//初始化有序map,拼接data数据,就是从redis取出初始数据
sku := model.InitSkuData(skuStr)
sku.GoodsId = goodsId
spu := spuList[sku.SpuId]
......@@ -65,7 +65,6 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku = ls.GetGoodsImages(sku, spu)
//pdf
pdf := gjson.Get(spu, "pdf").String()
// spuLargeImage := gjson.Get(spu, "images_l").String()
if pdf != "" {
pdf = strings.Replace(pdf, "http://img.ichunt.com", "https://img.ichunt.com", 1)
//还要针对如果是自己的上传服务的pdf文件,还要补上类型用于预览
......@@ -75,12 +74,6 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku.Pdf = pdf
}
//处理分类
//fast的参数含义,为了节省开销性能的参数,传1就不会去分类这些参数
if fast != "1" {
sku = ls.GetGoodsClass(sku, spu)
}
//获取商品名称
if sku.GoodsName == "" {
sku.GoodsName = gjson.Get(spu, "spu_name").String()
......@@ -90,8 +83,11 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
brandId := gjson.Get(spu, "brand_id").Int()
brandName, _ := redis.String(redisConn.Do("HGET", "brand", brandId))
sku.BrandName = brandName
//获取税务信息
if fast != "1" { //仅提供价格和库存
//判断是否要取精简信息
if fast != "1" {
sku = ls.GetGoodsClass(sku, spu)
//仅提供价格和库存
if sku.GoodsName != "" && brandId != 0 {
sku.ErpTax = ls.GetErpTax(sku.GoodsName, brandName)
}
......@@ -105,6 +101,7 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
}
}
//获取在途库存信息
if showStockInfo == "1" && sku.OldGoodsId != 0 {
sku.StockInfo = ls.getStockInfo(sku.SupplierId, sku.OldGoodsId)
}
......@@ -136,7 +133,7 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
//这里获取活动价格和活动类型
sku = ls.GetActivity(sku)
//处理阶梯价数据
//最小起订量要大于阶梯价的最小阶梯数量
if len(sku.LadderPrice) > 0 {
//排序
sort.Sort(sorter.LadderPriceSorter(sku.LadderPrice))
......@@ -146,6 +143,7 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku.Moq = purchases
}
}
//获取系数
sku = ls.GetCoefficientAndPrice(sku)
......@@ -176,11 +174,6 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku.LadderPriceResult = []int{}
}
//这边有个临时逻辑,如果供应商id是TI的,就库存为0
// if sku.SupplierId == 1679 {
// sku.Stock = 0
// }
//判断是否可以购买
sku.IsBuy = ls.GetIsBuy(sku)
......@@ -198,6 +191,7 @@ func (ls *LyService) LyGoodsDetail(ctx *gin.Context, goodsIds []string, ch chan
sku.Attrs = []int{}
}
//获取标签信息
var TagService TagsService
sku.GoodsTag = TagService.GetTags(sku.GoodsId, 0)
......
......@@ -2,6 +2,7 @@ package service
import (
"encoding/json"
"fmt"
"go_sku_server/model"
c "go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
......@@ -187,11 +188,22 @@ func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku {
return sku
}
flag := 0
data := make([]model.LadderPrice, len(sku.LadderPrice))
var data []model.LadderPrice
var originalPrice []model.OriginPrice
//专卖
//专卖价格获取
if sku.SupplierId == 17 {
ladderPrice := sku.LadderPrice
//判断redis里面是否有成本价,有的话,那就直接去取价格,不需要生成阶梯价
//如果没有成本价字段,就要去生成阶梯价格
if len(ladderPrice) > 0 {
if ladderPrice[0].PriceCostUs == 0 && ladderPrice[0].PriceCostCn == 0 {
var priceService PriceService
ladderPrice = priceService.GenerateLadderPrice(sku)
} else {
fmt.Println("不走成本价生成")
}
}
data = make([]model.LadderPrice, len(ladderPrice))
for key, price := range ladderPrice {
if price.Purchases == 0 {
continue
......@@ -203,15 +215,16 @@ func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku {
if price.PriceCn != 0 {
data[key].PriceCn = c.MyRound(price.PriceCn, 4)
}
//todo 2023.4.6 专卖成本价
//专卖成本价
data[key].PriceCostUs = price.PriceCostUs
data[key].PriceCostCn = price.PriceCostCn
//联营或者专卖 同时 存在活动价格
if (sku.GoodsType == 1 || sku.GoodsType == 2) && sku.AcType > 1 && sku.Ratio > 0 {
tempAcPrice := c.MyRound(c.MulFloat(price.PriceCn, (sku.Ratio/100)), 4)
tempAcPrice := c.MyRound(c.MulFloat(price.PriceCn, sku.Ratio/100), 4)
data[key].PriceAc = tempAcPrice
data[key].PriceAcUs = c.MyRound(c.MulFloat(price.PriceUs, (sku.RatioUs/100)), 4)
data[key].PriceAcUs = c.MyRound(c.MulFloat(price.PriceUs, sku.RatioUs/100), 4)
//优惠价后等于0,就代表没有搞活动
if tempAcPrice <= 0 {
......@@ -227,6 +240,7 @@ func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku {
}
}
} else {
data = make([]model.LadderPrice, len(sku.LadderPrice))
//去获取各种系数(成本折扣系数,售价组系数,供应商系数)
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
......
package service
import (
"fmt"
"github.com/gomodule/redigo/redis"
"github.com/tidwall/gjson"
"go_sku_server/model"
c "go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"strconv"
"strings"
"time"
"github.com/gomodule/redigo/redis"
"github.com/syyongx/php2go"
"github.com/tidwall/gjson"
)
type PriceService struct {
}
//获取联营活动价
func (ls *LyService) GetActivityPrice(sku model.LySku, suffix string, power Power) model.LySku {
//没价格,直接返回
if len(sku.LadderPrice) == 0 {
return sku
}
// 这个是针对贸泽的活动价?如果有成本价就是代表有活动,而且活动模块没法设置mouse的活动价
if suffix == "" && sku.SupplierId == 14 {
return getMouserActivityPrice(sku)
}
//先获取活动信息,针对不同供应商不同活动类型做活动吗,每个活动只能针对一个供应商
//比如有 Self_ActivityPrice_2_Discount,Self_ActivityPrice_1_NewCustomer
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
supplierIdStr := strconv.Itoa(int(sku.SupplierId))
activityInfo, _ := redis.String(redisCon.Do("GET", "Self_ActivityPrice_"+supplierIdStr+suffix))
//找不到对应的活动价格信息,就直接返回空
if activityInfo == "" {
return sku
}
//判断是否在活动范围内
startTime := gjson.Get(activityInfo, "start_time").Int()
endTime := gjson.Get(activityInfo, "end_time").Int()
currentTime := time.Now().Unix()
if !(startTime < currentTime && endTime > currentTime) {
return sku
}
//获取redis里面存储的活动相关信息
brandIdArray := gjson.Get(activityInfo, "brand_id").Array()
var brandIds []int64
for _, brandId := range brandIdArray {
if brandId.String() != "" {
brandIds = append(brandIds, brandId.Int())
}
}
goodsNameArray := gjson.Get(activityInfo, "goods_name").Array()
var goodsNames []string
for _, goodsName := range goodsNameArray {
goodsNames = append(goodsNames, goodsName.String())
}
activityCanal := gjson.Get(activityInfo, "canal").String()
activityClassId := gjson.Get(activityInfo, "class_id").String()
//刚开始默认有活动
hasActivity := true
switch suffix {
//折扣价
case "_Discount":
//判断是否有参与折扣的品牌
if len(brandIds) > 0 {
//如果是不参与折扣的品牌
if php2go.InArray(sku.BrandName, brandIds) {
hasActivity = false
}
}
//判断是否有参与折扣的型号
if len(goodsNames) > 0 {
//如果是不参与折扣的型号
if php2go.InArray(sku.GoodsName, goodsNames) {
hasActivity = false
}
}
break
case "_NewCustomer":
//判断是否符合条件
activityGoodsId := gjson.Get(activityInfo, "goods_id").String()
if activityGoodsId != "" {
//为了用字符串匹配
activityGoodsId = activityGoodsId + ","
if !strings.Contains(activityGoodsId, sku.GoodsId) {
hasActivity = false
}
} else {
if len(brandIds) > 0 {
}
//专卖
//canal:渠道标签 为啥要判断专卖类型,只有专卖才有渠道标签和内部编码
if activityCanal != "" && sku.GoodsType == 2 {
activityCanal = activityCanal + ","
if !strings.Contains(activityCanal, sku.Canal) {
hasActivity = false
}
}
//3和4是? 联营和专卖为啥不需要判断分类呢,因为它们的分类没什么用,所以不需要判断
if activityClassId != "" && (sku.GoodsType == 0 || sku.GoodsType == 3 || sku.GoodsType == 4) {
activityClassId = activityClassId + ","
if !strings.Contains(activityClassId, "classId2") {
hasActivity = false
}
}
}
break
default:
//除了新客价和折扣价,剩下的价格活动
if len(brandIds) > 0 {
if !php2go.InArray(sku.BrandId, brandIds) {
hasActivity = false
}
}
if activityCanal != "" && sku.GoodsType == 2 {
canalArr := gjson.Parse(activityCanal).Array()
var canals []string
for _, canal := range canalArr {
canals = append(canals, canal.String())
}
if !php2go.InArray(sku.Canal, canals) {
hasActivity = false
}
}
//处理会员价的可见名单
// 这里整块逻辑不是很懂,is_part,visible_roster都是什么,由请求方来决定要不要会员价
//visible_roster在http://cube.ichunt.net/web/SaveMemberPrice?id=120里面设置可见会员
//只是在针对某一部分特定的会员去设置的会员价
visibleRoster := gjson.Get(activityInfo, "visible_roster").String()
if suffix == "_Member" && gjson.Get(activityInfo, "is_part").Int() == 1 &&
visibleRoster != "" {
//为了用字符串匹配
visibleRoster = "," + visibleRoster + ","
//提取出user_id、手机号、邮箱
userInfo := make(map[string]string)
userInfo["user_id"] = power.UserId
userInfo["mobile"] = power.Mobile
userInfo["email"] = power.Email
for _, value := range userInfo {
if value != "" {
hasActivity = false
continue
}
if strings.Contains(visibleRoster, ","+value+",") {
hasActivity = true
break
} else {
hasActivity = false
}
}
}
//处理黑名单,只有折扣活动才有黑名单,并且是下单页面
//tverify_blacklist是用来代表获取黑名单,由请求方决定
//是否验证黑名单,用于折扣活动提交订单页面与后台下单
blacklistType := gjson.Get(activityInfo, "blacklist_type").Int()
activityId := gjson.Get(activityInfo, "activity_id").String()
activityType := gjson.Get(activityInfo, "activity_type").Int()
if suffix == "" && blacklistType != 0 && hasActivity && activityId != "" && activityType == 2 &&
power.VerifyBlacklist == "true" {
}
}
//判断是否有活动
if !hasActivity {
return sku
}
sku.Ratio = gjson.Get(activityInfo, "ratio").Float()
switch suffix {
//会员价
case "_Member":
sku.AcType = 3
break
//新客价
case "_NewCustomer":
sku.AcType = 5
break
//折扣价
case "_Discount":
sku.AcType = 4
break
//活动价
default:
sku.AcType = 2
//折扣活动
//这里为何多了个ac_type = 8,活动价的基础上有折扣价,如果有折扣价,就要输出改成折扣价,折扣价和活动价的样式不一样
if gjson.Get(activityInfo, "activity_type").Int() == 2 {
var allowNotLogin int64
allowNotLogin = gjson.Get(activityInfo, "allow_not_login").Int()
if allowNotLogin == 0 {
allowNotLogin = 2
}
sku.AcType = 8
}
break
}
//是否允许使用优惠券
allCoupon := gjson.Get(activityInfo, "allow_coupon").Int()
if allCoupon == 0 {
allCoupon = 1
}
sku.AllowCoupon = int(allCoupon)
return sku
}
func getMouserActivityPrice(sku model.LySku) model.LySku {
//判断活动价
//mouser成本价添加时间为何要对比现在的时间 mouser的成本价格过期,过期就等于活动失效,斌哥会更新这个,根据贸泽给的接口
cpTime := sku.CpTime
twoDayTimeStamp := 60 * 60 * 48
if cpTime > 0 && ((cpTime + int64(twoDayTimeStamp)) > time.Now().Unix()) {
for _, price := range sku.LadderPrice {
// ladder_price字段有cost_price字段吗,贸泽的专属字段
if price.CostPrice != 0 {
sku.AcType = 2
return sku
}
}
}
return sku
}
//这里有个前置条件处理美金价,因为element(6)存到美金字段里面的是港币,rs(21)存到美金字段里的是人民币,buerklin(1676)是欧元
//所以要全部先转成正确的美金价才能显示,目前先写死汇率,因为目前没有地方能获取实时的各种转美金的汇率
func (ls *LyService) TransformSpecialSupplierPrice(supplierId int64, priceUs float64, usRatio float64) float64 {
......@@ -253,3 +37,157 @@ func (ls *LyService) TransformSpecialSupplierPrice(supplierId int64, priceUs flo
}
return priceUs
}
//构建专营的阶梯价,现在专营只会存一个简单的成本价,阶梯数量是1,所以我这边要根据专营的阶梯系数去构建具体的阶梯价
func (ps *PriceService) GenerateLadderPrice(sku model.LySku) (generatedLadderPrice []model.LadderPrice) {
//先直接获取成本价原始值,因为能走进来这个方法的,都是只有一个阶梯的成本价的
costPriceCn := sku.LadderPrice[0].PriceCn
costPriceUs := sku.LadderPrice[0].PriceUs
fmt.Println("人民币和美金的成本价分别为 : ", costPriceCn, costPriceUs)
//先去判断起订量,如果起订量小于50,就要走固定配置的阶梯价格系数
if sku.Moq <= 50 {
moq := int(sku.Moq)
fixedRatio := make(map[int]float64)
//var fixedRatioSlice map[int]float64
switch {
case sku.Moq < 10:
fixedRatio = map[int]float64{moq: 1.07, 30: 1.08, 100: 1.09, 300: 1.1, 1000: 1.11}
break
case sku.Moq < 30:
fixedRatio = map[int]float64{moq: 1.07, 50: 1.08, 200: 1.09, 500: 1.1, 1000: 1.11}
break
default:
fixedRatio = map[int]float64{moq: 1.07, 200: 1.08, 500: 1.09, 1000: 1.1, 2000: 1.11}
break
}
//然后根据一开始只有一个的阶梯价去生成阶梯价格
for purchases, ratio := range fixedRatio {
generatedLadderPrice = append(generatedLadderPrice, model.LadderPrice{
Purchases: int64(purchases),
PriceCn: c.MulFloat(costPriceCn, ratio),
PriceUs: c.MulFloat(costPriceUs, ratio),
})
}
return generatedLadderPrice
}
isCostPrice := true
//起订量大于50的,就要去读取对应的系数
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
priceRatio, _ := redis.String(redisCon.Do("HGET", "magic_cube_price_rule_v2", sku.Canal))
//是否有设置最低利润点阶梯,不足5个阶梯时,最高阶梯对应的最小利润点阶梯
//isSetLowestProfit := gjson.Get(priceRatio, "is_set_lowest_profit").Bool()
ladderPriceMiniProfitLevel := int(gjson.Get(priceRatio, "ladder_price_mini_profit_level").Int())
//判断是否走成本价判断还是走阶梯价判断,因为上传sku的时候,可以设置每个sku的成本价(人民币&&美金),也可以设置每个sku的阶梯价,如果有阶梯价,就要跳过设置的成本价(假设有设置的话)
if isCostPrice {
//判断最小起订量是属于哪个范围
ratioKey := ""
if sku.Moq >= 50 && sku.Moq < 200 {
ratioKey = "cost_ladder_price_egt50_lt200"
} else {
ratioKey = "cost_ladder_price_egt200"
}
costLadderPriceRatio := gjson.Get(priceRatio, ratioKey).Map()
// 成本价阶梯数 由最高库存计算得到
costLadderCount := 0
for i := 1; i <= len(costLadderPriceRatio); i++ {
costPurchases := costLadderPriceRatio[strconv.Itoa(i)].Get("purchases").Int()
if costPurchases*sku.Moq > sku.Stock {
break
}
costLadderCount++
}
fmt.Println("阶梯数量为 : ", costLadderCount)
fmt.Println("设置的利润阶梯为 : ", ladderPriceMiniProfitLevel)
if costLadderCount <= ladderPriceMiniProfitLevel {
for i := 1; i <= costLadderCount; i++ {
priceRatioAndPurchases := costLadderPriceRatio[strconv.Itoa(i)]
// 阶梯数量系数正序取
costPurchases := sku.Moq * priceRatioAndPurchases.Get("purchases").Int()
//fmt.Println(costPurchases, sku.Stock)
// 阶梯数量上限为库存量,超出则不再计算下级阶梯
if costPurchases > sku.Stock {
break
}
//利润阶梯索引
//计算出库存满足了n个价格阶梯之后 从最小利润点层级反向取n个层级,然后正序计算 如:库存满足1、2、3层阶梯,最小利润点层级是第5个层级,则利润点取3、4、5层级的
//最小利润点层级 - 库存满足多少个阶梯 + i
costMapIndex := ladderPriceMiniProfitLevel - costLadderCount + i
if costMapIndex <= 0 {
costMapIndex = 1
}
priceRatioAndPurchases = costLadderPriceRatio[strconv.Itoa(costMapIndex)]
fmt.Println("获取到的阶梯系数为 : ", priceRatioAndPurchases)
// 阶梯价格系数正序取
generatedLadderPrice = append(generatedLadderPrice, model.LadderPrice{
Purchases: costPurchases,
PriceCn: c.MulFloat(costPriceCn, priceRatioAndPurchases.Get("price").Float()),
PriceUs: c.MulFloat(costPriceUs, priceRatioAndPurchases.Get("price_usd").Float()),
})
}
} else {
//价格阶梯数量超过最利润点的层级的情况
for i := 1; i <= costLadderCount; i++ {
priceRatioAndPurchases := costLadderPriceRatio[strconv.Itoa(i)]
// 阶梯数量系数正序取
costPurchases := sku.Moq * priceRatioAndPurchases.Get("purchases").Int()
// 阶梯数量上限为库存量,超出则不再计算下级阶梯
if costPurchases > sku.Stock {
break
}
fmt.Println(costPriceCn)
// 阶梯价格系数正序取
generatedLadderPrice = append(generatedLadderPrice, model.LadderPrice{
Purchases: sku.Moq * priceRatioAndPurchases.Get("purchases").Int(),
PriceCn: c.MulFloat(costPriceCn, priceRatioAndPurchases.Get("price").Float()),
PriceUs: c.MulFloat(costPriceUs, priceRatioAndPurchases.Get("price_usd").Float()),
})
}
}
return generatedLadderPrice
} else {
ladderPriceRatio := gjson.Get(priceRatio, "ladder_price_egt50_lt200").Map()
ladderCount := len(sku.LadderPrice)
//走阶梯价
if ladderCount <= ladderPriceMiniProfitLevel {
for i := 1; i <= ladderCount; i++ {
ladder := sku.LadderPrice[i]
//利润阶梯索引
//计算出库存满足了n个价格阶梯之后 从最小利润点层级反向取n个层级,然后正序计算 如:库存满足1、2、3层阶梯,最小利润点层级是第5个层级,则利润点取3、4、5层级的
//最小利润点层级 - 库存满足多少个阶梯 + i
costMapIndex := ladderPriceMiniProfitLevel - ladderCount + i
if costMapIndex <= 0 {
costMapIndex = 1
}
priceRatio := ladderPriceRatio[strconv.Itoa(costMapIndex)]
fmt.Println("获取到的阶梯系数为 : ", priceRatio)
// 阶梯价格系数正序取
generatedLadderPrice = append(generatedLadderPrice, model.LadderPrice{
Purchases: ladder.Purchases,
PriceCn: c.MulFloat(ladder.PriceCn, priceRatio.Get("ratio").Float()),
PriceUs: c.MulFloat(ladder.PriceUs, priceRatio.Get("ratio_usd").Float()),
})
}
} else {
//价格阶梯数量超过最利润点的层级的情况
for i := 1; i <= 9; i++ {
ladder := sku.LadderPrice[i]
// 阶梯数量系数正序取
priceRatio := ladderPriceRatio[strconv.Itoa(i)]
// 阶梯价格系数正序取
generatedLadderPrice = append(generatedLadderPrice, model.LadderPrice{
Purchases: int64(ladder.Purchases),
PriceCn: c.MulFloat(ladder.PriceCn, priceRatio.Get("ratio").Float()),
PriceUs: c.MulFloat(ladder.PriceUs, priceRatio.Get("ratio_usd").Float()),
})
}
}
return generatedLadderPrice
}
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment