package service import ( "encoding/json" "go_sku_server/model" c "go_sku_server/pkg/common" "go_sku_server/pkg/gredis" "go_sku_server/pkg/logger" _ "go_sku_server/pkg/mongo" "go_sku_server/service/sorter" "strconv" "strings" "github.com/gomodule/redigo/redis" _ "github.com/iancoleman/orderedmap" "github.com/syyongx/php2go" "github.com/tidwall/gjson" _ "gopkg.in/mgo.v2/bson" ) //获取图片信息 func (ls *LyService) GetGoodsImages(sku model.LySku, spu string) model.LySku { //图片 spuLargeImage := gjson.Get(spu, "images_l").String() sku.ImagesL = spuLargeImage if spuLargeImage != "" && php2go.Strlen(spuLargeImage) < 5 { sku.ImagesL = "" } //商品图片不存在用大图代替 if sku.GoodsImages == "" && spuLargeImage != "" { sku.GoodsImages = spuLargeImage } //加上是否是rocelec图片的判断,如果是的话,就将图片设置为空 if strings.Contains(sku.GoodsImages, "rocelec") { sku.GoodsImages = "" } sku.GoodsImages = strings.Replace(sku.GoodsImages, "http://img.ichunt.com", "https://img.ichunt.com", 1) sku.ImagesL = strings.Replace(sku.ImagesL, "http://img.ichunt.com", "https://img.ichunt.com", 1) return sku } //获取分类信息 func (ls *LyService) GetGoodsClass(sku model.LySku, spu string) model.LySku { //仅提供价格和库存 spuClassId1 := gjson.Get(spu, "class_id1").Int() spuClassId2 := gjson.Get(spu, "class_id2").Int() spuClassId3 := gjson.Get(spu, "class_id3").Int() if spuClassId2 != 0 { sku.ClassName = ls.GetCacheClass(spuClassId2) sku.ClassName3 = ls.GetCacheClass(spuClassId3) sku.ClassName2 = ls.GetCacheClass(spuClassId2) sku.ClassName1 = ls.GetCacheClass(spuClassId1) } else { sku.ClassName = "其他" } return sku } //获取税务信息,对接税务系统 func (ls *LyService) GetErpTax(goodsName, brandName string) interface{} { redisCon := gredis.Conn("default_r") defer redisCon.Close() key := php2go.Md5(strings.ToUpper(goodsName + brandName)) info, _ := redis.String(redisCon.Do("HGET", "tax_customs_info", key)) data := make(map[string]interface{}) if gjson.Get(info, "tax_rate_low").String() != "" || gjson.Get(info, "supervision_con").Int() > 0 { data["tariffRate"] = gjson.Get(info, "tax_rate_low").String() data["types"] = gjson.Get(info, "supervision_con").String() return data } else { return false } } //获取联营供应商的名字 func (ls *LyService) GetPoolSupplierName(supplierId int64) (supplierName string) { redisCon := gredis.Conn("default_r") defer redisCon.Close() supplier, _ := redis.String(redisCon.Do("HGET", "supplier", supplierId)) return supplier } //从缓存获取分类 func (ls *LyService) GetCacheClass(classId int64) string { redisCon := gredis.Conn("default_r") defer redisCon.Close() classStr, _ := redis.String(redisCon.Do("HGET", "pool_class_info", classId)) className := gjson.Get(classStr, "class_name").String() return className } type SpuAttr struct { SpuId string `bson:"spu_id"` AttrsExtend []AttrsExtend `bson:"attrs_extend"` Attrs string `bson:"attrs"` } type AttrsExtend struct { AttrName string `bson:"attr_name" json:"attr_name"` AttrValue string `bson:"attr_value" json:"attr_value"` AttrUnit string `bson:"attr_unit" json:"attr_unit,omitempty"` } //H获取供应链标准品牌 func (ls *LyService) GetScmBrand(brandId int64) (res interface{}) { redisCon := gredis.Conn("default_r") defer redisCon.Close() scmBrandId, _ := redis.Int(redisCon.Do("HGET", "pool_scm_brand_mapping", brandId)) if scmBrandId != 0 { scmBrandData, err := redis.String(redisCon.Do("HGET", "pool_scm_brand", scmBrandId)) if err != nil { logger.Select("sku_query").Error(err.Error()) } scmBrand := make(map[string]interface{}) scmBrand["erp_brand_name"] = gjson.Get(scmBrandData, "erp_brand_name").String() scmBrand["erp_brand_id"] = gjson.Get(scmBrandData, "erp_brand_id").String() scmBrand["scm_brand_id"] = c.ToString(scmBrandId) return scmBrand } else { return []string{} } } //获取新版标准品牌 func (ls *LyService) GetStandardBrand(brandId int64) (standardBrand model.StandardBrand) { redisCon := gredis.Conn("default_r") defer redisCon.Close() standardBrandId, _ := redis.Int(redisCon.Do("HGET", "standard_brand_mapping", brandId)) if standardBrandId != 0 { standardBrandStr, err := redis.String(redisCon.Do("HGET", "standard_brand", standardBrandId)) if err != nil { logger.Select("sku_query").Error(err.Error()) } standardBrand.BrandName = gjson.Get(standardBrandStr, "brand_name").String() standardBrand.StandardBrandId = int(gjson.Get(standardBrandStr, "standard_brand_id").Int()) standardBrand.BrandLogo = gjson.Get(standardBrandStr, "brandLogo").String() } return standardBrand } type ExtendFee struct { Cn struct { Max interface{} `json:"max"` Price interface{} `json:"price"` } `json:"cn"` Hk struct { Max interface{} `json:"max"` Price interface{} `json:"price"` } `json:"hk"` } //获取附加费 func (ls *LyService) GetExtendFee(supplierId int64, canal string) interface{} { redisCon := gredis.Conn("default_r") defer redisCon.Close() if supplierId == 17 { //为什么专卖的redis键会不一样,专卖的附加费管理在供应商系统,其它的在基石 value, _ := redis.String(redisCon.Do("HGET", "supp_extend_fee", "17."+canal)) if value == "" { return false } //专卖的存了两种形式的数据,真是搞人心态 if strings.Contains(value, "cn") { var extendFee ExtendFee json.Unmarshal([]byte(value), &extendFee) return extendFee } else { var extendFee []map[string]interface{} json.Unmarshal([]byte(value), &extendFee) return extendFee } } else { value, _ := redis.String(redisCon.Do("HGET", "supp_extend_fee", supplierId)) if value == "" { return false } var extendFee ExtendFee json.Unmarshal([]byte(value), &extendFee) return extendFee } } //获取系数 func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku { if len(sku.LadderPrice) == 0 { sku.Original = nil return sku } flag := 0 data := make([]model.LadderPrice, len(sku.LadderPrice)) var originalPrice []model.OriginPrice //专卖 if sku.SupplierId == 17 { ladderPrice := sku.LadderPrice for key, price := range ladderPrice { if price.Purchases == 0 { continue } data[key].Purchases = price.Purchases if price.PriceUs != 0 { data[key].PriceUs = c.MyRound(price.PriceUs, 4) } 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) data[key].PriceAc = tempAcPrice data[key].PriceAcUs = c.MyRound(c.MulFloat(price.PriceUs, (sku.RatioUs/100)), 4) //优惠价后等于0,就代表没有搞活动 if tempAcPrice <= 0 { sku.AcType = 0 } //价格与原价一样 if data[key].PriceCn == tempAcPrice && key < 2 { flag++ if flag >= 2 || (len(ladderPrice) < 2) { sku.AcType = 0 } } } } } else { //去获取各种系数(成本折扣系数,售价组系数,供应商系数) redisCon := gredis.Conn("default_r") defer redisCon.Close() //先去读取成本折扣系数 //找一个标志位,因为默认的全局折扣系数的数据格式和非全局的是不一样的 isDefaultDiscoutRatio := false discountRatio, _ := redis.String(redisCon.Do("HGET", "magic_cube_channel_discount_daigou", sku.SupplierId)) checkNullRation := gjson.Get(discountRatio, "ration").String() //如果这个渠道没有对应的折扣系数,那么就去读取全局的 if discountRatio == "" || checkNullRation == "{}" { isDefaultDiscoutRatio = true discountRatio, _ = redis.String(redisCon.Do("GET", "magic_cube_channel_discount_default_daigou")) } var cnDiscountRatio float64 var usDiscountRatio float64 //是否找到对应的折扣系数,找不到就去找默认 findedDiscountRatio := false //如果有默认系数,那么就去找默认系数 if isDefaultDiscoutRatio { } else { //拿到系数以后,就要去计算 //拿出里面的所有排序,以人民币系数为准 ration := gjson.Get(discountRatio, "ration").Map() var sortNumbers []int for sortNumberString, _ := range ration { sortNumber, _ := strconv.Atoi(sortNumberString) sortNumbers = append(sortNumbers, sortNumber) } //然后确定排序 sortNumbers = sorter.IntSliceSortDesc(sortNumbers) //确定排序以后,就可以进行按排序(从大到小)取系数 for _, sortNumber := range sortNumbers { sortString := strconv.Itoa(sortNumber) cnDiscountRatio = gjson.Get(discountRatio, "ration."+sortString).Float() usDiscountRatio = gjson.Get(discountRatio, "ration_usd."+sortString).Float() var hasSpecialCheck = false //判断是否有符合的商品名称 goodsNames := gjson.Get(discountRatio, "goods_name."+sortString).String() if goodsNames != "" { hasSpecialCheck = true goodsNameList := strings.Split(goodsNames, "@€@") //找到有对应的商品名称,那么优先级肯定是最高的了 if php2go.InArray(sku.GoodsName, goodsNameList) { findedDiscountRatio = true break } } //判断是否有符合的品牌名称 brandIds := gjson.Get(discountRatio, "brand."+sortString).String() if brandIds != "" { hasSpecialCheck = true standardBrandIdList := strings.Split(brandIds, ",") standardBrandId := strconv.Itoa(sku.StandardBrand.StandardBrandId) //找到有对应的品牌,那么优先级肯定是最高的了 if php2go.InArray(standardBrandId, standardBrandIdList) { findedDiscountRatio = true break } } //如果没有设置品牌和商品,那么这个优先级高的就会覆盖下面的了,不需要再去判断品牌和型号了 if hasSpecialCheck { continue } findedDiscountRatio = true break } } //如果上面都没找到折扣系数,那么就去找全局的 if !findedDiscountRatio { discountRatio, _ = redis.String(redisCon.Do("GET", "magic_cube_channel_discount_default_daigou")) cnDiscountRatio = gjson.Get(discountRatio, "ration").Float() usDiscountRatio = gjson.Get(discountRatio, "ration_usd").Float() } sku.DiscountRatio.Ratio = cnDiscountRatio sku.DiscountRatio.RatioUsd = usDiscountRatio //再去找售价组系数 //找一个标志位,因为默认的全局折扣系数的数据格式和非全局的是不一样的 isDefaultPriceRatio := false priceRatioCache, _ := redis.String(redisCon.Do("HGET", "magic_cube_price_rule_channel", sku.SupplierId)) checkNullRation = gjson.Get(priceRatioCache, "ladder_price").String() //如果这个渠道没有对应的折扣系数,那么就去读取全局的 if priceRatioCache == "" || checkNullRation == "{}" { isDefaultPriceRatio = true priceRatioCache, _ = redis.String(redisCon.Do("GET", "magic_cube_price_rule_channel_default")) } var priceRatioSort int //这个就是最终要获取到的价格系数 var priceRatioList []model.PriceRatio //是否找到系数的标志位 findedRatio := false //如果只有默认系数,那么就去找默认系数 if isDefaultPriceRatio { } else { //拿到系数以后,就要去计算 //拿出里面的所有排序 priceRatioSortMap := gjson.Get(priceRatioCache, "ladder_price").Map() var sortNumbers []int for sortNumberString, _ := range priceRatioSortMap { sortNumber, _ := strconv.Atoi(sortNumberString) sortNumbers = append(sortNumbers, sortNumber) } //然后确定排序 sortNumbers = sorter.IntSliceSortDesc(sortNumbers) //确定排序以后,就可以进行按排序(从大到小)取系数 outerLoop: for _, sortNumber := range sortNumbers { priceRatioSort = sortNumber priceRatioList = nil sortString := strconv.Itoa(sortNumber) priceRatioArr := gjson.Get(priceRatioCache, "ladder_price."+sortString).Array() for _, value := range priceRatioArr { var priceRatio model.PriceRatio priceRatio.Ratio = gjson.Get(value.String(), "ratio").Float() priceRatio.RatioUsd = gjson.Get(value.String(), "ratio_usd").Float() priceRatioList = append(priceRatioList, priceRatio) } var hasSpecialCheck = false //判断是否有符合的商品名称 goodsNames := gjson.Get(priceRatioCache, "goods_name."+sortString).String() if goodsNames != "" { hasSpecialCheck = true goodsNameList := strings.Split(goodsNames, "@€@") //找到有对应的商品名称,那么优先级肯定是最高的了 if php2go.InArray(sku.GoodsName, goodsNameList) { findedRatio = true break } } //判断是否有符合的标准品牌ID brandIds := gjson.Get(priceRatioCache, "brand."+sortString).String() if brandIds != "" { hasSpecialCheck = true standardBrandIdList := strings.Split(brandIds, ",") standardBrandId := strconv.Itoa(sku.StandardBrand.StandardBrandId) //找到有对应的品牌,那么优先级肯定是最高的了 if php2go.InArray(standardBrandId, standardBrandIdList) { findedRatio = true break } } //判断是否有符合的eccn eccns := gjson.Get(priceRatioCache, "eccn."+sortString).String() if eccns != "" { hasSpecialCheck = true eccnList := strings.Split(eccns, ",") //找到有对应的eccn,那么优先级肯定是最高的了 for _, eccn := range eccnList { //判断是否有百分号匹配 //如果是纯%,那就是不对的,要跳过 if strings.Replace(eccn, "%", "", 10) == "" { continue } if strings.Contains(eccn, "%") { hasPrefix := strings.HasPrefix(eccn, "%") hasSuffix := strings.HasSuffix(eccn, "%") if hasPrefix && hasSuffix { eccn = strings.Replace(eccn, "%", "", 10) if strings.Contains(sku.Eccn, eccn) { findedRatio = true break outerLoop } } if hasPrefix && !hasSuffix { eccn = strings.Replace(eccn, "%", "", 10) if strings.HasSuffix(sku.Eccn, eccn) { findedRatio = true break outerLoop } } if !hasPrefix && hasSuffix { eccn = strings.Replace(eccn, "%", "", 10) if strings.HasPrefix(sku.Eccn, eccn) { findedRatio = true break outerLoop } } } else { if sku.Eccn == eccn { findedRatio = true break outerLoop } } } } //如果没有设置品牌和商品,那么这个优先级高的就会覆盖下面的了,不需要再去判断品牌和型号了 if hasSpecialCheck { continue } findedRatio = true break } } //找不到特定的系数,那就去找全局的 if !findedRatio { priceRatioCache, _ = redis.String(redisCon.Do("GET", "magic_cube_price_rule_channel_default")) priceRatioArr := gjson.Get(priceRatioCache, "ladder_price").Array() priceRatioList = nil for _, value := range priceRatioArr { var priceRatio model.PriceRatio priceRatio.Ratio = gjson.Get(value.String(), "ratio").Float() priceRatio.RatioUsd = gjson.Get(value.String(), "ratio_usd").Float() priceRatioList = append(priceRatioList, priceRatio) } priceRatioSort = -1 } sku.PriceRatio = priceRatioList sku.PriceRatioSort = priceRatioSort //这里是供应商系数,先保留这块逻辑 ratio, _ := redis.String(redisCon.Do("HGET", "pool_supplier_ratio", sku.SupplierId)) if ratio == "" { logger.Select("sku_query").Error("系数获取异常,供应商:" + c.ToString(sku.SupplierId)) return sku } ratios := gjson.Parse(ratio).Array() var defaultCoefficient, coefficient model.Coefficient var hasDefault, hasCoefficient bool //查找使用哪个系数 for _, ratio := range ratios { ratioInfo := model.Coefficient{ Cn: ratio.Get("cn").Float(), Hk: ratio.Get("hk").Float(), ExtraRatio: ratio.Get("extra_ratio").Float(), Ratio: ratio.Get("ratio").Float(), } isDefault := ratio.Get("is_default").Int() if isDefault == 2 { defaultCoefficient = ratioInfo hasDefault = true continue } goodsName := ratio.Get("goods_name").String() brandName := ratio.Get("brand_name").String() if goodsName == "" && brandName == "" { continue } if brandName != "" && strings.Contains(brandName, sku.BrandName) { coefficient = ratioInfo hasCoefficient = true break } //存在goods_name的对比吗,为什么,因为系数可以单独针对型号配置,所以要去判断型号 //http://footstone.ichunt.net/web/SavePoolCoefficient?id=1 if goodsName != "" && strings.Contains(goodsName, sku.GoodsName) { coefficient = ratioInfo hasCoefficient = true break } } if !hasCoefficient && !hasDefault { logger.Select("sku_query").Error("系数获取异常,供应商:" + c.ToString(sku.SupplierId)) return sku } if !hasCoefficient { coefficient = defaultCoefficient } //下面是计算价格 //价格计算文档 https://docs.qq.com/doc/DR3RJcnNPeUNkWHRk // 为何是固定的1.13,关税基本不会变,有变的话跟产品沟通手动修改即可 //$tax = config('website.tax'); tax := 1.13 for key, price := range sku.LadderPrice { //这里有个前置条件处理美金价,因为element(6)存到美金字段里面的是港币,rs(21)存到美金字段里的是人民币,buerklin(1676)是欧元 //所以要全部先转成正确的美金价才能显示,目前先写死汇率,因为目前没有地方能获取实时的各种转美金的汇率 price.PriceUs = ls.TransformSpecialSupplierPrice(sku.SupplierId, price.PriceUs, coefficient.Ratio) originalPrice = append(originalPrice, model.OriginPrice{ PriceUs: price.PriceUs, Purchases: price.Purchases, PriceCn: price.PriceCn, }) if price.Purchases == 0 { continue } data[key].Purchases = price.Purchases //找出对应的阶梯,从$priceRatioList找到对应的售价组系数 //这个是为了怕后台存的数据格式不对导致无法获取到对应的系数 //这里去取对应的售价利润阶梯的时候,是往下匹配的,比如 阶梯价是 1,2,3 售价组利润是 1,2,3,4,5,那么123对应的是售价组利润的345 //而且当原始阶梯价为10个的时候,超过了售价利润组的9个,就要去取第9个售价利润组 var priceRatio model.PriceRatio //先找出一共有多少个阶梯 ladderCount := len(sku.LadderPrice) ratioCount := len(priceRatioList) if ladderCount > key && key < ratioCount { margin := ratioCount - ladderCount if margin < 0 { margin = 0 } priceRatio = priceRatioList[key+margin] } else if key >= ratioCount { priceRatio = priceRatioList[ratioCount-1] } else { priceRatio = model.PriceRatio{ Ratio: 1, RatioUsd: 1, } } //美金成本价 priceCostUs := c.MulFloat(price.PriceUs, usDiscountRatio) priceCostUs = c.MyRound(priceCostUs, 4) //美金售价 priceUs := c.MulFloat(priceCostUs, priceRatio.RatioUsd) //人民币成本价 priceCostCn := c.MulFloat(price.PriceUs, coefficient.Ratio, tax) priceCostCn = c.MulFloat(c.MyRound(priceCostCn, 4), cnDiscountRatio) priceCostCn = c.MyRound(priceCostCn, 4) //人民币售价 priceCn := c.MulFloat(priceCostCn, priceRatio.Ratio) data[key].PriceUs = c.MyRound(priceUs, 4) data[key].PriceCostUs = priceCostUs //处理人民币 data[key].PriceCn = c.MyRound(priceCn, 4) data[key].PriceCostCn = priceCostCn //处理活动价和原价相同的情况 if (sku.GoodsType == 1 || sku.GoodsType == 2) && sku.AcType > 1 && sku.Ratio > 0 { priceAc := c.MyRound(c.MulFloat(data[key].PriceCn, (sku.Ratio/100)), 4) data[key].PriceAc = priceAc if sku.RatioUs > 0 { priceAcUs := c.MyRound(c.MulFloat(data[key].PriceUs, (sku.RatioUs/100)), 4) data[key].PriceAcUs = priceAcUs } if priceAc <= 0 { sku.AcType = 0 break } else { if sku.AcType == 4 { data[key].PriceCn = priceAc sku.AcType = 0 } } //为什么$kp < 2,如果第一阶梯或第二阶梯价格和活动价一样,就不输出活动价了 //活动价都是有样式的和平时不一样,如果价格一样,但是样子是活动价,客户会迷惑,所以不输出即可,保持原来的样式 if data[key].PriceCn == priceAc && key < 2 { flag++ if flag >= 2 { sku.AcType = 0 } if len(data) > 1 { if data[1].PriceCn == 0 { sku.AcType = 0 } } } } } //判断原始价格有变化,那就要覆盖 if len(originalPrice) > 0 { sku.Original = originalPrice } //输出税费到前端 coefficient.Tax = tax sku.Coefficient = coefficient } if len(data) > 0 { sku.LadderPrice = data } return sku } //获取供应商货期 func (ls *LyService) GetDelivery(supplierId int64, canal string) (delivery map[string]string) { delivery = make(map[string]string) redisCon := gredis.Conn("default_r") defer redisCon.Close() if canal != "" { supplierRatio, _ := redis.String(redisCon.Do("HGET", "supp_ratio", canal)) if supplierRatio != "" { cnDeliveryTime := gjson.Get(supplierRatio, "cn_delivery_time").String() usDeliveryTime := gjson.Get(supplierRatio, "us_delivery_time").String() //为了兼容供应商修改的问题 if cnDeliveryTime != "周" && cnDeliveryTime != "天" { delivery["cn_delivery"] = gjson.Get(supplierRatio, "cn_delivery_time").String() } else { delivery["cn_delivery"] = "" } if usDeliveryTime != "周" && usDeliveryTime != "天" { delivery["hk_delivery"] = gjson.Get(supplierRatio, "us_delivery_time").String() } else { delivery["hk_delivery"] = "" } } return } info, _ := redis.String(redisCon.Do("HGET", "SUPPLIER_REDIS_INFO_", supplierId)) cnDelivery := gjson.Get(info, "cn_delivery").String() hkDelivery := gjson.Get(info, "hk_delivery").String() if cnDelivery != "" || hkDelivery != "" { delivery["cn_delivery"] = cnDelivery delivery["hk_delivery"] = hkDelivery return } return } //判断能否购买 func (ls *LyService) GetIsBuy(sku model.LySku) (isBuy int) { if sku.GoodsStatus != 1 { return } if sku.Moq > sku.Stock { return } if len(sku.LadderPrice) == 0 { return } if sku.Stock == 0 { return } return 1 } //合并spu的信息 func (ls *LyService) CombineSup(sku model.LySku, spuStr string) model.LySku { sku.UpdateTime = gjson.Get(spuStr, "update_time").Int() sku.ClassID1 = int(gjson.Get(spuStr, "class_id1").Int()) sku.ClassID2 = int(gjson.Get(spuStr, "class_id2").Int()) sku.SpuName = gjson.Get(spuStr, "spu_name").String() sku.SpuBrief = gjson.Get(spuStr, "spu_brief").String() sku.SpuDetail = gjson.Get(spuStr, "spu_detail").String() sku.Status = int(gjson.Get(spuStr, "status").Int()) sku.Encap = gjson.Get(spuStr, "encap").String() return sku }