Commit 6313d9f2 authored by zhengyaoqiu's avatar zhengyaoqiu

feat(colorway): 加价率、运费、跨境运费等及其依赖

parent 6bc3863e
...@@ -3,8 +3,9 @@ module git.chillcy.com/golang/colorway ...@@ -3,8 +3,9 @@ module git.chillcy.com/golang/colorway
go 1.24.3 go 1.24.3
require ( require (
git.chillcy.com/golang/chillcy/pkg v0.0.0-20250627035541-7956996f27ce git.chillcy.com/golang/chillcy/pkg v0.0.0-20250703141544-f63c5883c3d1
git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f
github.com/pkg/errors v0.9.1
github.com/zeromicro/go-zero v1.8.4 github.com/zeromicro/go-zero v1.8.4
go.mongodb.org/mongo-driver v1.17.4 go.mongodb.org/mongo-driver v1.17.4
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
...@@ -37,6 +38,7 @@ require ( ...@@ -37,6 +38,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/grafana/pyroscope-go v1.2.2 // indirect github.com/grafana/pyroscope-go v1.2.2 // indirect
......
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.chillcy.com/golang/chillcy/pkg v0.0.0-20250627035541-7956996f27ce h1:JBhBnnNR7DCqi67fxfLC7ZIJJXJP4jMTtP8DeW9XcJQ= git.chillcy.com/golang/chillcy/pkg v0.0.0-20250703141544-f63c5883c3d1 h1:YKPXnj98Z+pQms4d9JetiHRgA4OmX9ksOBspauGXsPU=
git.chillcy.com/golang/chillcy/pkg v0.0.0-20250627035541-7956996f27ce/go.mod h1:1N8ux+rPaW+/OT74EGSz2oX51NvsEK3H4nlBZ+5Xx0M= git.chillcy.com/golang/chillcy/pkg v0.0.0-20250703141544-f63c5883c3d1/go.mod h1:1N8ux+rPaW+/OT74EGSz2oX51NvsEK3H4nlBZ+5Xx0M=
git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f h1:08l02ihb9QCINdg2o202kclqEQK4gaqxYo0H7kz6/p8= git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f h1:08l02ihb9QCINdg2o202kclqEQK4gaqxYo0H7kz6/p8=
git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f/go.mod h1:+oGrruo/MyXkrh5VPjDu/jvHN7tZGNkdZiKMJ/gIi4c= git.chillcy.com/golang/chillcy/project/pc4 v0.0.0-20250630145511-385ed232051f/go.mod h1:+oGrruo/MyXkrh5VPjDu/jvHN7tZGNkdZiKMJ/gIi4c=
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
...@@ -61,9 +61,12 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= ...@@ -61,9 +61,12 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
......
...@@ -2,23 +2,39 @@ package mongo ...@@ -2,23 +2,39 @@ package mongo
import ( import (
"context" "context"
siteGroupMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/SiteGroupMarginConfig"
brandDataModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/brand_data"
productModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product" productModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product"
siteComboMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_combo_margin_config"
siteFloatMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_float_margin_config"
sitePlatformPriceConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_platform_price_config" sitePlatformPriceConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_platform_price_config"
subjectModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/subject"
reflect2 "git.chillcy.com/golang/colorway/pkg/reflect" reflect2 "git.chillcy.com/golang/colorway/pkg/reflect"
"reflect" "reflect"
) )
const DatabaseColorWay = "color_way" const DatabaseColorWay = "color_way"
const DatabaseMpc = "mpc"
type Manager struct { type Manager struct {
ProductModel productModel.ProductModel ProductModel productModel.ProductModel
SitePlatformPriceConfigModel sitePlatformPriceConfigModel.SitePlatformPriceConfigModel SitePlatformPriceConfigModel sitePlatformPriceConfigModel.SitePlatformPriceConfigModel
SubjectModel subjectModel.SubjectModel
SiteComboMarginConfigModel siteComboMarginConfigModel.SiteComboMarginConfigModel
SiteFloatMarginConfigModel siteFloatMarginConfigModel.SiteFloatMarginConfigModel
BrandDataModel brandDataModel.BrandDataModel
SiteGroupMarginConfigModel siteGroupMarginConfigModel.SiteGroupMarginConfigModel
} }
func NewManager(mongoUrl string) *Manager { func NewManager(mongoUrl string) *Manager {
return &Manager{ return &Manager{
ProductModel: productModel.NewProductModel(mongoUrl, DatabaseColorWay, productModel.Collection), ProductModel: productModel.NewProductModel(mongoUrl, DatabaseColorWay, productModel.Collection),
SitePlatformPriceConfigModel: sitePlatformPriceConfigModel.NewSitePlatformPriceConfigModel(mongoUrl, DatabaseColorWay, sitePlatformPriceConfigModel.Collection), SitePlatformPriceConfigModel: sitePlatformPriceConfigModel.NewSitePlatformPriceConfigModel(mongoUrl, DatabaseMpc, sitePlatformPriceConfigModel.Collection),
SubjectModel: subjectModel.NewSubjectModel(mongoUrl, DatabaseMpc, subjectModel.Collection),
SiteComboMarginConfigModel: siteComboMarginConfigModel.NewSiteComboMarginConfigModel(mongoUrl, DatabaseMpc, siteComboMarginConfigModel.Collection),
SiteFloatMarginConfigModel: siteFloatMarginConfigModel.NewSiteFloatMarginConfigModel(mongoUrl, DatabaseMpc, siteFloatMarginConfigModel.Collection),
BrandDataModel: brandDataModel.NewBrandDataModel(mongoUrl, DatabaseMpc, brandDataModel.Collection),
SiteGroupMarginConfigModel: siteGroupMarginConfigModel.NewSiteGroupMarginConfigModel(mongoUrl, DatabaseMpc, brandDataModel.Collection),
} }
} }
......
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)
package model
import (
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo/cache"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var _ SiteGroupMarginConfigModel = (*customSiteGroupMarginConfigModel)(nil)
type (
// SiteGroupMarginConfigModel is an interface to be customized, add more methods here,
// and implement the added methods in customSiteGroupMarginConfigModel.
SiteGroupMarginConfigModel interface {
siteGroupMarginConfigModel
cache.Cache[SiteGroupMarginConfig]
cache.ChangeStream[SiteGroupMarginConfig]
}
customSiteGroupMarginConfigModel struct {
*defaultSiteGroupMarginConfigModel
*cache.Base[SiteGroupMarginConfig]
}
)
// NewSiteGroupMarginConfigModel returns a model for the mongo.
func NewSiteGroupMarginConfigModel(url, db, collection string) SiteGroupMarginConfigModel {
conn := mon.MustNewModel(url, db, collection)
defaultModel := newDefaultSiteGroupMarginConfigModel(conn)
customModel := &customSiteGroupMarginConfigModel{
defaultSiteGroupMarginConfigModel: defaultModel,
}
customModel.Base = cache.NewBase[SiteGroupMarginConfig](defaultModel, customModel)
return customModel
}
func (receiver *customSiteGroupMarginConfigModel) DocumentEqual(a, b SiteGroupMarginConfig) bool {
return a.Id.Hex() == b.Id.Hex()
}
// Code generated by goctl. DO NOT EDIT.
package model
import (
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/base"
"github.com/zeromicro/go-zero/core/stores/mon"
)
type siteGroupMarginConfigModel interface {
model.Model[SiteGroupMarginConfig]
}
type defaultSiteGroupMarginConfigModel struct {
conn *mon.Model
model.Base[SiteGroupMarginConfig]
}
func newDefaultSiteGroupMarginConfigModel(conn *mon.Model) *defaultSiteGroupMarginConfigModel {
return &defaultSiteGroupMarginConfigModel{
conn: conn,
Base: model.NewBase[SiteGroupMarginConfig](conn),
}
}
package model
import (
"git.chillcy.com/golang/chillcy/pkg/slice"
"git.chillcy.com/golang/colorway/pkg/types"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const Collection = "site_group_margin_config"
type SiteGroupMarginConfig struct {
Id *primitive.ObjectID `bson:"_id,omitempty"`
Seller types.Seller `bson:"seller"`
GroupName string `bson:"groupName"`
SiteIds []string `bson:"siteIds"`
Margin float64 `bson:"margin"`
Memos types.Memos `bson:"memos"`
Enable bool `bson:"enable"` // 是否启用
}
func (c *SiteGroupMarginConfig) IsMatch(site string) bool {
if !c.Enable {
return false
}
if len(c.SiteIds) > 0 && !slice.Contains(c.SiteIds, site) {
return false
}
return true
}
package model
import "github.com/zeromicro/go-zero/core/stores/mon"
var _ BrandDataModel = (*customBrandDataModel)(nil)
type (
// BrandDataModel is an interface to be customized, add more methods here,
// and implement the added methods in customBrandDataModel.
BrandDataModel interface {
brandDataModel
}
customBrandDataModel struct {
*defaultBrandDataModel
}
)
// NewBrandDataModel returns a model for the mongo.
func NewBrandDataModel(url, db, collection string) BrandDataModel {
conn := mon.MustNewModel(url, db, collection)
return &customBrandDataModel{
defaultBrandDataModel: newDefaultBrandDataModel(conn),
}
}
// Code generated by goctl. DO NOT EDIT.
package model
import (
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/base"
"github.com/zeromicro/go-zero/core/stores/mon"
)
type brandDataModel interface {
model.Model[BrandData]
}
type defaultBrandDataModel struct {
conn *mon.Model
model.Base[BrandData]
}
func newDefaultBrandDataModel(conn *mon.Model) *defaultBrandDataModel {
return &defaultBrandDataModel{
conn: conn,
Base: model.NewBase[BrandData](conn),
}
}
package model
const Collection = "brand_data"
type BrandData struct {
Id string `bson:"_id"`
BrandName string `bson:"brandName"`
Count int `bson:"count"`
SearchWord string `bson:"searchWord"`
PriceRangeCounts []PriceRangeCount `bson:"priceRangeCounts"`
ProductSellCounts []ProductSellCount `bson:"productSellCounts"`
PlatformOrderCount map[string]PlatformOrderCount `bson:"platformOrderCount"` // key platform
PlatformPayAmount map[string]PlatformPayAmount `bson:"platformPayAmount"`
}
type BrandDataList []BrandData
type PriceRangeCount struct {
Min float64 `bson:"min"`
Max float64 `bson:"max"`
Count int `bson:"count"`
}
type PlatformPayAmount struct {
DayRange map[int]float64 `bson:"dayRange"`
}
type PlatformOrderCount struct {
DayRange map[int]int `bson:"dayRange"`
OrderCount int `json:"orderCount"`
}
type ProductSellCount struct {
Mid string `bson:"mid"`
Count int `bson:"count"`
}
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)
...@@ -3,3 +3,13 @@ package model ...@@ -3,3 +3,13 @@ package model
//go:generate goctl model mongo --type Product --dir product --home ../templates --style go_zero //go:generate goctl model mongo --type Product --dir product --home ../templates --style go_zero
//go:generate goctl model mongo --type SitePlatformPriceConfig --dir site_platform_price_config --home ../templates --style go_zero //go:generate goctl model mongo --type SitePlatformPriceConfig --dir site_platform_price_config --home ../templates --style go_zero
//go:generate goctl model mongo --type Subject --dir subject --home ../templates --style go_zero
//go:generate goctl model mongo --type SiteComboMarginConfig --dir site_combo_margin_config --home ../templates --style go_zero
//go:generate goctl model mongo --type SiteFloatMarginConfig --dir site_float_margin_config --home ../templates --style go_zero
//go:generate goctl model mongo --type BrandData --dir brand_data --home ../templates --style go_zero
//go:generate goctl model mongo --type SiteGroupMarginConfig --dir SiteGroupMarginConfig --home ../templates --style go_zero
package model package model
import ( import (
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo/types" "git.chillcy.com/golang/chillcy/pkg/gender"
"git.chillcy.com/golang/colorway/pkg/types"
"time" "time"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
...@@ -11,7 +12,8 @@ const Collection = "product" ...@@ -11,7 +12,8 @@ const Collection = "product"
type Product struct { type Product struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
StyleNumber string `bson:"styleNumber"` StyleId string `bson:"styleId"` // 可以是分割形式出来的主款号,也可以是品牌官网同款组的 ID
StyleNumber string `bson:"styleNumber"` // 源款号
Title ProductTitle `bson:"title"` Title ProductTitle `bson:"title"`
Description string `bson:"description"` Description string `bson:"description"`
Season string `bson:"season"` Season string `bson:"season"`
...@@ -24,7 +26,7 @@ type Product struct { ...@@ -24,7 +26,7 @@ type Product struct {
Category ProductCategory `bson:"category"` Category ProductCategory `bson:"category"`
Compositions ProductCompositions `bson:"compositions"` Compositions ProductCompositions `bson:"compositions"`
Fits []string `bson:"fits"` Fits []string `bson:"fits"`
Genders ProductGenders `bson:"genders"` Genders gender.Genders `bson:"genders"`
Models []string `bson:"models"` Models []string `bson:"models"`
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
...@@ -32,18 +34,6 @@ type Product struct { ...@@ -32,18 +34,6 @@ type Product struct {
type Products []Product type Products []Product
type ProductGender string
type ProductGenders []ProductGender
const (
GenderMan ProductGender = "man"
GenderWoman ProductGender = "woman"
GenderBaby ProductGender = "baby"
GenderGirl ProductGender = "girl"
GenderBoy ProductGender = "boy"
)
type ProductComposition struct { type ProductComposition struct {
Part string `bson:"part"` Part string `bson:"part"`
Material string `bson:"material"` Material string `bson:"material"`
...@@ -66,8 +56,15 @@ func (receiver ProductCategory) GetIds() []string { ...@@ -66,8 +56,15 @@ func (receiver ProductCategory) GetIds() []string {
return ids return ids
} }
// Style 记录原始款号信息
type Style struct {
Number string `bson:"number"`
ColorCode string `bson:"colorCode"`
}
type ProductColor struct { type ProductColor struct {
ColorCode string `bson:"colorCode"` ColorId string `bson:"colorId"` // 可以是分割出来的色号,也可以是品牌官网同款组的唯一确定颜色的款号
ColorCode string `bson:"colorCode"` // 源色号
Id string `bson:"id"` Id string `bson:"id"`
Name string `bson:"name"` Name string `bson:"name"`
BasicId string `bson:"basicId"` BasicId string `bson:"basicId"`
...@@ -88,6 +85,7 @@ type ProductColorSku struct { ...@@ -88,6 +85,7 @@ type ProductColorSku struct {
Stock int `bson:"stock"` Stock int `bson:"stock"`
Price float64 `bson:"price"` Price float64 `bson:"price"`
Currency string `bson:"currency"` Currency string `bson:"currency"`
SubjectIds []string `bson:"subjectIds"`
ProductColorSkuPlatformStoreSkus []ProductColorSkuPlatformStoreSkus `bson:"productColorSkuPlatformStoreSkus"` ProductColorSkuPlatformStoreSkus []ProductColorSkuPlatformStoreSkus `bson:"productColorSkuPlatformStoreSkus"`
} }
...@@ -104,31 +102,27 @@ type ProductBrand struct { ...@@ -104,31 +102,27 @@ type ProductBrand struct {
} }
type ProductColorSkuPlatformStoreSku struct { type ProductColorSkuPlatformStoreSku struct {
Platform string `bson:"platform"` // 销售平台 Platform types.Platform `bson:"platform"` // 销售平台
Store string `bson:"store"` // 销售平台具体店铺 Store types.Store `bson:"store"` // 销售平台具体店铺
Qty int `bson:"qty"` // 库存 Route types.Route `bson:"route"` // 线路
FixedQty *int `bson:"fixedQty,omitempty"` // 虚拟库存 Currency string `bson:"currency"` // 销售平台的币种
Route string `bson:"route"` // 线路 OriginCurrency string `bson:"originCurrency"` // 原始币种
Currency string `bson:"currency"` // 销售平台的币种 Price float64 `bson:"price"` // 最终价格
OriginCurrency string `bson:"originCurrency"` // 原始币种 FixPrice *float64 `bson:"fixPrice,omitempty"` // 固定价格
Price float64 `bson:"price"` // 最终价格 FixMargin *float64 `bson:"fixMargin,omitempty"` // 固定加价率(影响计价)
FixPrice *float64 `bson:"fixPrice,omitempty"` // 固定价格 Rate float64 `bson:"rate"` // OriginCurrency -> Currency 的汇率
FixMargin *float64 `bson:"fixMargin,omitempty"` // 固定加价率(影响计价) CnyRate float64 `bson:"cnyRate"` // Currency -> CNY 的汇率
Rate float64 `bson:"rate"` // OriginCurrency -> Currency 的汇率 Margin float64 `bson:"margin"` // 加价率
CnyRate float64 `bson:"cnyRate"` // Currency -> CNY 的汇率 SubjectRate float64 `bson:"subjectRate"` // 专题系数
Margin float64 `bson:"margin"` // 加价率 Subject string `bson:"subject"` // 绑定的专题id
SubjectRate float64 `bson:"subjectRate"` // 专题系数 DiscountRate float64 `bson:"discountRate"` // 商家系数
Subject *primitive.ObjectID `bson:"subject"` // 绑定的专题id TotalDiscount float64 `bson:"totalDiscount"` // 总折扣
DiscountRate float64 `bson:"discountRate"` // 商家系数 TaxRate float64 `bson:"taxRate"` // 税率
TotalDiscount float64 `bson:"totalDiscount"` // 总折扣 Freight float64 `bson:"freight"` // 商家运费
TaxRate float64 `bson:"taxRate"` // 税率 Express float64 `bson:"express"` // 跨境费
Freight float64 `bson:"freight"` // 商家运费 ChangeRate *float64 `bson:"changeRate,omitempty"` // 价格变动率, 0.1表示涨价10%, -0.1表示降价10%
Express float64 `bson:"express"` // 跨境费 ChangeAt *time.Time `bson:"changeAt,omitempty"` // 价格变动时间,方便筛选
ChangeRate *float64 `bson:"changeRate,omitempty"` // 价格变动率, 0.1表示涨价10%, -0.1表示降价10% Memos types.Memos `bson:"memos,omitempty"` // 操作备注
ChangeAt *time.Time `bson:"changeAt,omitempty"` // 价格变动时间,方便筛选
Memos types.Memos `bson:"memos,omitempty"` // 操作备注
// todo 有固定价格固定库存等操作就是有固定操作
IsFixed *bool `bson:"isFixed,omitempty"` // 是否有固定操作
} }
type ProductColorSkuPlatformStoreSkus []ProductColorSkuPlatformStoreSku type ProductColorSkuPlatformStoreSkus []ProductColorSkuPlatformStoreSku
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)
package model
import (
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo/cache"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var _ SiteComboMarginConfigModel = (*customSiteComboMarginConfigModel)(nil)
type (
// SiteComboMarginConfigModel is an interface to be customized, add more methods here,
// and implement the added methods in customSiteComboMarginConfigModel.
SiteComboMarginConfigModel interface {
siteComboMarginConfigModel
cache.Cache[SiteComboMarginConfig]
cache.ChangeStream[SiteComboMarginConfig]
}
customSiteComboMarginConfigModel struct {
*defaultSiteComboMarginConfigModel
*cache.Base[SiteComboMarginConfig]
}
)
// NewSiteComboMarginConfigModel returns a model for the mongo.
func NewSiteComboMarginConfigModel(url, db, collection string) SiteComboMarginConfigModel {
conn := mon.MustNewModel(url, db, collection)
defaultModel := newDefaultSiteComboMarginConfigModel(conn)
customModel := &customSiteComboMarginConfigModel{
defaultSiteComboMarginConfigModel: defaultModel,
}
customModel.Base = cache.NewBase[SiteComboMarginConfig](defaultModel, customModel)
return customModel
}
func (receiver *customSiteComboMarginConfigModel) DocumentEqual(a, b SiteComboMarginConfig) bool {
return a.Id.Hex() == b.Id.Hex()
}
// Code generated by goctl. DO NOT EDIT.
package model
import (
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/base"
"github.com/zeromicro/go-zero/core/stores/mon"
)
type siteComboMarginConfigModel interface {
model.Model[SiteComboMarginConfig]
}
type defaultSiteComboMarginConfigModel struct {
conn *mon.Model
model.Base[SiteComboMarginConfig]
}
func newDefaultSiteComboMarginConfigModel(conn *mon.Model) *defaultSiteComboMarginConfigModel {
return &defaultSiteComboMarginConfigModel{
conn: conn,
Base: model.NewBase[SiteComboMarginConfig](conn),
}
}
package model
import (
"git.chillcy.com/golang/chillcy/pkg/gender"
"git.chillcy.com/golang/chillcy/pkg/slice"
"git.chillcy.com/golang/colorway/pkg/types"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const Collection = "site_combo_margin_config"
type SiteComboMarginConfig struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
Seller types.Seller `bson:"seller"`
SiteId string `bson:"siteId"`
Brands []string `bson:"brands"`
Genders gender.Genders `bson:"genders"`
Categories []string `bson:"categories"`
Margin float64 `bson:"margin"`
Memos types.Memos `bson:"memos"`
Enable bool `bson:"enable"` // 是否启用`
}
func (receiver SiteComboMarginConfig) IsGenderMatch(genders gender.Genders) bool {
if len(receiver.Genders) <= 0 {
return true
}
genders = slice.RemoveDuplicateItem(genders)
for _, g := range receiver.Genders {
if g == gender.GenderAdult {
v := slice.ContainsElems(genders, []gender.Gender{
gender.GenderMan,
gender.GenderWoman,
}) || onlyHave(genders, g)
if v {
return true
}
}
if g == gender.GenderChild {
v := slice.ContainsElems(genders, []gender.Gender{
gender.GenderBoy,
gender.GenderGirl,
}) || onlyHave(genders, g)
if v {
return true
}
}
if onlyHave(genders, g) {
return true
}
}
return false
}
func onlyHave(arr []gender.Gender, v gender.Gender) bool {
if len(arr) == 1 && arr[0] == v {
return true
}
return false
}
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)
package model
import (
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo/cache"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var _ SiteFloatMarginConfigModel = (*customSiteFloatMarginConfigModel)(nil)
type (
// SiteFloatMarginConfigModel is an interface to be customized, add more methods here,
// and implement the added methods in customSiteFloatMarginConfigModel.
SiteFloatMarginConfigModel interface {
siteFloatMarginConfigModel
cache.Cache[SiteFloatMarginConfig]
cache.ChangeStream[SiteFloatMarginConfig]
}
customSiteFloatMarginConfigModel struct {
*defaultSiteFloatMarginConfigModel
*cache.Base[SiteFloatMarginConfig]
}
)
// NewSiteFloatMarginConfigModel returns a model for the mongo.
func NewSiteFloatMarginConfigModel(url, db, collection string) SiteFloatMarginConfigModel {
conn := mon.MustNewModel(url, db, collection)
defaultModel := newDefaultSiteFloatMarginConfigModel(conn)
customModel := &customSiteFloatMarginConfigModel{
defaultSiteFloatMarginConfigModel: defaultModel,
}
customModel.Base = cache.NewBase[SiteFloatMarginConfig](defaultModel, customModel)
return customModel
}
func (receiver *customSiteFloatMarginConfigModel) DocumentEqual(a, b SiteFloatMarginConfig) bool {
return a.Id.Hex() == b.Id.Hex()
}
// Code generated by goctl. DO NOT EDIT.
package model
import (
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/base"
"github.com/zeromicro/go-zero/core/stores/mon"
)
type siteFloatMarginConfigModel interface {
model.Model[SiteFloatMarginConfig]
}
type defaultSiteFloatMarginConfigModel struct {
conn *mon.Model
model.Base[SiteFloatMarginConfig]
}
func newDefaultSiteFloatMarginConfigModel(conn *mon.Model) *defaultSiteFloatMarginConfigModel {
return &defaultSiteFloatMarginConfigModel{
conn: conn,
Base: model.NewBase[SiteFloatMarginConfig](conn),
}
}
package model
import (
"encoding/json"
"git.chillcy.com/golang/colorway/pkg/types"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const Collection = "site_float_margin_config"
type SiteFloatMarginConfig struct {
Id *primitive.ObjectID `bson:"_id,omitempty"`
Seller types.Seller `bson:"seller"`
Season string `bson:"season"`
Category string `bson:"category"`
Brand string `bson:"brand"`
Enable bool `bson:"enable"` // 是否启用
Memos types.Memos `bson:"memos"`
}
type ConditionRule struct {
Type string `bson:"type"`
Params []ConditionKv `bson:"params"`
}
func (cr ConditionRule) Get(k string) string {
for _, p := range cr.Params {
if p.Key == k {
return p.Value
}
}
return ""
}
const ConditionKeySeasonCO = "season_co" // CO经典款
const ConditionKeySeasonNow = "season_now" // 当季款
const ConditionKeySeasonOld = "season_old" // 过季款
const ConditionKeyBrandTop = "brand_top" // 头部品牌
const ConditionKeyBrandMiddle = "brand_middle" // 腰部品牌
const ConditionKeyBrandTail = "brand_tail" // 尾部品牌
const ConditionKeyCategoryClothing = "category_clothing" // 服装品类
const ConditionKeyCategoryShoes = "category_shoes" // 鞋靴品类
const ConditionKeyCategoryBags = "category_bag" // 包袋品类
const ConditionKeyCategoryAccessories = "category_accessory" // 配饰品类
type ConditionKv struct {
Key string `bson:"key"`
Value string `bson:"value"`
}
func (c *SiteFloatMarginConfig) Explain() ([]ConditionRule, error) {
rules := make([]ConditionRule, 0)
if c.Season != "" {
rule, err := convertToRule("season", c.Season)
if err != nil {
return nil, err
}
rules = append(rules, *rule)
}
if c.Category != "" {
rule, err := convertToRule("category", c.Category)
if err != nil {
return nil, err
}
rules = append(rules, *rule)
}
if c.Brand != "" {
rule, err := convertToRule("brand", c.Brand)
if err != nil {
return nil, err
}
rules = append(rules, *rule)
}
return rules, nil
}
func convertToRule(_type, content string) (*ConditionRule, error) {
var jsonContent map[string]interface{}
err := json.Unmarshal([]byte(content), &jsonContent)
if err != nil {
return nil, err
}
rule := ConditionRule{
Type: _type,
}
for key, value := range jsonContent {
rule.Params = append(rule.Params, ConditionKv{
Key: key,
Value: value.(string),
})
}
return &rule, nil
}
...@@ -29,7 +29,17 @@ type RoutePriceConfig struct { ...@@ -29,7 +29,17 @@ type RoutePriceConfig struct {
ExpressConfig ExpressConfig `json:"expressConfig" bson:"expressConfig"` // 跨境快递配置,默认是0 ExpressConfig ExpressConfig `json:"expressConfig" bson:"expressConfig"` // 跨境快递配置,默认是0
} }
func (rc *RoutePriceConfig) IsValid() bool { func (mc MarginConfig) FormatLadders() {
if mc.MarginStyle == MarginStyleLadder {
for i := range mc.Ladders {
if i == len(mc.Ladders)-1 {
mc.Ladders[i].LastOne = true
}
}
}
}
func (rc RoutePriceConfig) IsValid() bool {
// 路线价格配置校验-加价率 // 路线价格配置校验-加价率
if rc.MarginConfig.MarginStyle == MarginStyleFixed && (rc.MarginConfig.Margin <= 0 || rc.MarginConfig.Margin > 1) { if rc.MarginConfig.MarginStyle == MarginStyleFixed && (rc.MarginConfig.Margin <= 0 || rc.MarginConfig.Margin > 1) {
return false return false
...@@ -91,7 +101,14 @@ type MarginConfig struct { ...@@ -91,7 +101,14 @@ type MarginConfig struct {
Ladders []Ladder `json:"ladders" bson:"ladders"` // 阶梯加价,加价方式为阶梯加价时使用 Ladders []Ladder `json:"ladders" bson:"ladders"` // 阶梯加价,加价方式为阶梯加价时使用
} }
func (mc *MarginConfig) IsValidLadders() bool { func (l Ladder) IsMatch(price float64) bool {
if l.LastOne && l.Max == 0 {
return price >= l.Min
}
return price >= l.Min && price < l.Max
}
func (mc MarginConfig) IsValidLadders() bool {
if mc.MarginStyle == MarginStyleLadder { if mc.MarginStyle == MarginStyleLadder {
if len(mc.Ladders) <= 0 { if len(mc.Ladders) <= 0 {
return false return false
......
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)
package model
import (
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo/cache"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var _ SubjectModel = (*customSubjectModel)(nil)
type (
// SubjectModel is an interface to be customized, add more methods here,
// and implement the added methods in customSubjectModel.
SubjectModel interface {
subjectModel
cache.Cache[Subject]
cache.ChangeStream[Subject]
}
customSubjectModel struct {
*defaultSubjectModel
*cache.Base[Subject]
}
)
// NewSubjectModel returns a model for the mongo.
func NewSubjectModel(url, db, collection string) SubjectModel {
conn := mon.MustNewModel(url, db, collection)
defaultModel := newDefaultSubjectModel(conn)
customModel := &customSubjectModel{
defaultSubjectModel: defaultModel,
}
customModel.Base = cache.NewBase[Subject](defaultModel, customModel)
return customModel
}
func (receiver *customSubjectModel) DocumentEqual(a, b Subject) bool {
return a.Id.Hex() == b.Id.Hex()
}
// Code generated by goctl. DO NOT EDIT.
package model
import (
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/base"
"github.com/zeromicro/go-zero/core/stores/mon"
)
type subjectModel interface {
model.Model[Subject]
}
type defaultSubjectModel struct {
conn *mon.Model
model.Base[Subject]
}
func newDefaultSubjectModel(conn *mon.Model) *defaultSubjectModel {
return &defaultSubjectModel{
conn: conn,
Base: model.NewBase[Subject](conn),
}
}
package model
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const Collection = "subject"
type Subject struct {
Id primitive.ObjectID `bson:"_id,omitempty"` // 从pc3同步过来的专题ID
Title string `bson:"title"`
PriceRate float64 `bson:"priceRate"`
Platforms []Platform `bson:"platforms"`
StartAt *time.Time `bson:"startAt"`
ExpiredAt *time.Time `bson:"expiredAt"`
Created time.Time `bson:"created"`
Updated time.Time `bson:"updated"`
}
type Platform struct {
Name string `bson:"name" `
VoTag string `bson:"voTag" `
Count int `bson:"count" `
IsSync bool `bson:"isSync" `
ExpiredAt *time.Time `bson:"expiredAt" `
}
...@@ -11,8 +11,8 @@ type ColorSpu struct { ...@@ -11,8 +11,8 @@ type ColorSpu struct {
// 外键 // 外键
// 多对一 // 多对一
Skus Skus `gorm:"foreignKey:ColorSpuStyleNumber,ColorSpuColorCode; references:CompleteSpuStyleNumber,ColorCode; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Skus Skus `gorm:"foreignKey:ColorSpuStyleNumber,ColorSpuColorCode; references:CompleteSpuStyleNumber,ColorId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
Images Images `gorm:"foreignKey:ColorSpuStyleNumber,ColorSpuColorCode; references:CompleteSpuStyleNumber,ColorCode; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Images Images `gorm:"foreignKey:ColorSpuStyleNumber,ColorSpuColorCode; references:CompleteSpuStyleNumber,ColorId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
} }
type ColorSpus []ColorSpu type ColorSpus []ColorSpu
......
...@@ -16,13 +16,13 @@ type CompleteSpu struct { ...@@ -16,13 +16,13 @@ type CompleteSpu struct {
// 外键 // 外键
// 多对一 // 多对一
ColorSpus ColorSpus `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleNumber; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` ColorSpus ColorSpus `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
Compositions Compositions `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleNumber; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` Compositions Compositions `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
Models Models `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleNumber; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` Models Models `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
Fits Fits `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleNumber; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` Fits Fits `gorm:"foreignKey:CompleteSpuStyleNumber; references:StyleId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
// 多对多 // 多对多
Genders Genders `gorm:"many2many:completespu_genders;foreignKey:StyleNumber; References:Code;"` Genders Genders `gorm:"many2many:completespu_genders;foreignKey:StyleId; References:Code;"`
Categories Categories `gorm:"many2many:completespu_categories;foreignKey:StyleNumber; References:Code;"` Categories Categories `gorm:"many2many:completespu_categories;foreignKey:StyleId; References:Code;"`
} }
type CompleteSpus []CompleteSpu type CompleteSpus []CompleteSpu
......
...@@ -38,7 +38,7 @@ func upsertCompleteSpus(db *gorm.DB, completeSpus model.CompleteSpus) error { ...@@ -38,7 +38,7 @@ func upsertCompleteSpus(db *gorm.DB, completeSpus model.CompleteSpus) error {
return result.Error return result.Error
} }
// OnConflict 导致的更新操作不会回填 ID,即使外键 StyleNumber 存在,也会报错 WHERE conditions required,所以重新读取出来 // OnConflict 导致的更新操作不会回填 ID,即使外键 StyleId 存在,也会报错 WHERE conditions required,所以重新读取出来
styleNumbers := completeSpus.GetStyleNumbers() styleNumbers := completeSpus.GetStyleNumbers()
var reloadedSpus []model.CompleteSpu var reloadedSpus []model.CompleteSpu
err := db.Where("style_number IN ?", styleNumbers).Find(&reloadedSpus).Error err := db.Where("style_number IN ?", styleNumbers).Find(&reloadedSpus).Error
......
...@@ -35,7 +35,7 @@ func (l *UploadLogic) Upload(in *colorway.ProductUploadRequest) (*colorway.Produ ...@@ -35,7 +35,7 @@ func (l *UploadLogic) Upload(in *colorway.ProductUploadRequest) (*colorway.Produ
var writeModels []mongo.WriteModel var writeModels []mongo.WriteModel
for _, p := range ps { for _, p := range ps {
filter := bson.M{ filter := bson.M{
"style_number": p.StyleNumber, "style_number": p.StyleId,
} }
update := bson.D{ update := bson.D{
{"$set", p}, {"$set", p},
......
package cache
import (
"context"
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/brand_data"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
"sync"
"time"
)
type BrandRank struct {
brandDataModel model.BrandDataModel
rwMutex *sync.RWMutex
topBrands []string
middleBrands []string
}
func NewBrandData(brandDataModel model.BrandDataModel) *BrandRank {
return &BrandRank{brandDataModel: brandDataModel, rwMutex: new(sync.RWMutex)}
}
func (receiver *BrandRank) Refresh(ctx context.Context) error {
opt := options.Find()
opt.SetProjection(bson.D{{"_id", 1}})
opt.SetSort(bson.D{{"platformPayAmount.all.dayRange.90", -1}})
opt.SetLimit(100)
brandDataList, _, err := receiver.brandDataModel.Find(ctx, bson.M{}, opt)
if err != nil {
return err
}
top := brandDataList[:30]
topIds := make([]string, 0)
for _, data := range top {
topIds = append(topIds, data.Id)
}
middleIds := make([]string, 0)
if len(brandDataList) > 30 {
middle := brandDataList[30:]
for _, data := range middle {
middleIds = append(middleIds, data.Id)
}
}
receiver.setBrandRankIds(topIds, middleIds)
return nil
}
func (receiver *BrandRank) setBrandRankIds(topBrands, middleBrands []string) {
receiver.rwMutex.Lock()
defer receiver.rwMutex.Unlock()
receiver.topBrands = topBrands
receiver.middleBrands = middleBrands
}
func (receiver *BrandRank) GetBrandRankIds() ([]string, []string) {
receiver.rwMutex.RLock()
defer receiver.rwMutex.RUnlock()
return receiver.topBrands, receiver.middleBrands
}
func (receiver *BrandRank) Interval() time.Duration {
return time.Hour
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"git.chillcy.com/golang/chillcy/project/pc4/pkg/rpc/client/source" "git.chillcy.com/golang/chillcy/project/pc4/pkg/rpc/client/source"
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/brand_data"
"github.com/zeromicro/go-zero/core/logc" "github.com/zeromicro/go-zero/core/logc"
"go.uber.org/multierr" "go.uber.org/multierr"
"log" "log"
...@@ -19,13 +20,17 @@ type Cache struct { ...@@ -19,13 +20,17 @@ type Cache struct {
func InitCache(config Config) { func InitCache(config Config) {
s := NewSource(config.Source) s := NewSource(config.Source)
bd := NewBrandData(config.BrandDataModel)
// 注册缓存刷新 Map
_cache = &Cache{ _cache = &Cache{
refreshMap: map[RefreshKey]Refresh{ refreshMap: map[RefreshKey]Refresh{
RefreshKeySource: s, RefreshKeySource: s,
RefreshKeyRankBrandIds: bd,
}, },
Source: s, Source: s,
} }
err := _cache.Notify(RefreshKeySource) // 初始化第一次加载缓存
err := _cache.Notify(RefreshKeySource, RefreshKeyRankBrandIds)
if err != nil { if err != nil {
panic(err) panic(err)
} }
...@@ -68,11 +73,13 @@ func (receiver *Cache) startRefresh() { ...@@ -68,11 +73,13 @@ func (receiver *Cache) startRefresh() {
type RefreshKey string type RefreshKey string
const ( const (
RefreshKeySource = "source" RefreshKeySource = "source"
RefreshKeyRankBrandIds = "rankBrandIds"
) )
type Config struct { type Config struct {
Source source.Source Source source.Source
BrandDataModel model.BrandDataModel
} }
func GetCache() *Cache { func GetCache() *Cache {
......
package convert package convert
import ( import (
"errors"
"fmt" "fmt"
"git.chillcy.com/golang/chillcy/pkg/currency"
math2 "git.chillcy.com/golang/chillcy/pkg/math"
"git.chillcy.com/golang/chillcy/pkg/platform"
"git.chillcy.com/golang/chillcy/pkg/sdk/pc3" "git.chillcy.com/golang/chillcy/pkg/sdk/pc3"
"git.chillcy.com/golang/chillcy/pkg/slice"
"git.chillcy.com/golang/colorway/internal/pkg/database/mongo" "git.chillcy.com/golang/colorway/internal/pkg/database/mongo"
siteGroupMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/SiteGroupMarginConfig"
productModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product" productModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product"
siteComboMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_combo_margin_config"
siteFloatMarginConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_float_margin_config"
sitePlatformPriceConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_platform_price_config" sitePlatformPriceConfigModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/site_platform_price_config"
"github.com/zeromicro/go-zero/core/logx" subjectModel "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/subject"
"log" "git.chillcy.com/golang/colorway/internal/rpc/internal/svc/cache"
"git.chillcy.com/golang/colorway/internal/rpc/internal/svc/priceRouteAdapter"
"git.chillcy.com/golang/colorway/internal/rpc/internal/svc/rate"
"git.chillcy.com/golang/colorway/pkg/types"
"math" "math"
"regexp"
"slices"
"strconv"
"time" "time"
) )
type PlatformStoreSku struct { type PlatformStoreSku struct {
mongoManager *mongo.Manager mongoManager *mongo.Manager
rate rate.Rate
brandRankCache cache.BrandRank
} }
func (receiver *PlatformStoreSku) Convert(p productModel.Product) productModel.ProductColorSkuPlatformStoreSkus { func (receiver *PlatformStoreSku) Convert(p productModel.Product) (productModel.ProductColorSkuPlatformStoreSkus, error) {
var platformStoreSkus []productModel.ProductColorSkuPlatformStoreSkus var platformStoreSkus productModel.ProductColorSkuPlatformStoreSkus
for _, color := range p.Colors { for _, color := range p.Colors {
for _, sku := range color.Skus { for _, sku := range color.Skus {
sitePlatformPriceConfigs := receiver.mongoManager.SitePlatformPriceConfigModel.GetCacheMany(func(document sitePlatformPriceConfigproductModel.SitePlatformPriceConfig) bool { sitePlatformPriceConfigs := receiver.mongoManager.SitePlatformPriceConfigModel.GetCacheMany(func(document sitePlatformPriceConfigModel.SitePlatformPriceConfig) bool {
return document.Site == sku.SiteId return document.Site == sku.SiteId
}) })
categoryIds := p.Category.GetIds() categoryIds := p.Category.GetIds()
for _, sitePlatformPriceConfig := range sitePlatformPriceConfigs { for _, sitePlatformPriceConfig := range sitePlatformPriceConfigs {
platformPriceDetail, err := r.calculatePlatformPrice(ctx, localSkuModel, pc3SkuModel, categories, priceConfig, svcProductModel) // todo fixMargin
// todo pc3SkuModel
var pc3SkuModel pc3.ModelSku
platformPriceSku, err := receiver.calculatePlatformPrice(p, sku, 1, pc3SkuModel, categoryIds, sitePlatformPriceConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if platformPriceDetail != nil { platformStoreSkus = append(platformStoreSkus, platformPriceSku)
skuPriceList = append(skuPriceList, *platformPriceDetail)
}
} }
} }
} }
err = r.dataRepo.BatchUpsertSkuPrice(ctx, skuPriceList)
if err != nil { return platformStoreSkus, nil
return nil, fmt.Errorf("BatchUpsertSkuPrice:%w", err)
}
} }
func (receiver *PlatformStoreSku) calculatePlatformPrice(localSkuModel *productModel.Sku, pc3SkuModel pc3.ModelSku, categories []string, priceConfig sitePlatformPriceConfigModel.SitePlatformPriceConfig, svcProductModel *ProductModel) (productModel.ProductColorSkuPlatformStoreSku, error) { func (receiver *PlatformStoreSku) calculatePlatformPrice(product productModel.Product, productColorSku productModel.ProductColorSku, fixMargin float64, pc3SkuModel pc3.ModelSku, categories []string, priceConfig sitePlatformPriceConfigModel.SitePlatformPriceConfig) (productModel.ProductColorSkuPlatformStoreSku, error) {
var sku productModel.ProductColorSkuPlatformStoreSku var sku productModel.ProductColorSkuPlatformStoreSku
if !priceConfig.IsValid() { if !priceConfig.IsValid() {
return sku, fmt.Errorf("路线价格配置不合法") return sku, fmt.Errorf("路线价格配置不合法")
} }
sku, err := r.calculateRoutePrice(ctx, svcProductModel, localSkuModel, pc3SkuModel, categories, priceConfig.RoutePriceConfig, priceConfig.Seller) sku, err := receiver.calculateRoutePrice(product, productColorSku, fixMargin, pc3SkuModel, categories, priceConfig.RoutePriceConfig, priceConfig.Seller)
if err != nil { if err != nil {
return sku, err return sku, err
} }
return sku, nil return sku, nil
} }
func (receiver *PlatformStoreSku) calculateRoutePrice(svcProductModel *ProductModel, localSkuModel *model.Sku, pc3SkuModel pc3.ModelSku, categories []string, routeConfig embed.RoutePriceConfig, seller embed.Seller) (*model.SkuPrice, error) { func (receiver *PlatformStoreSku) calculateRoutePrice(product productModel.Product, productColorSku productModel.ProductColorSku, fixMargin float64, pc3SkuModel pc3.ModelSku, categories []string, routeConfig sitePlatformPriceConfigModel.RoutePriceConfig, seller types.Seller) (productModel.ProductColorSkuPlatformStoreSku, error) {
var platformStoreSku productModel.ProductColorSkuPlatformStoreSku
adapter, err := priceRouteAdapter.SelectAdapter(routeConfig.Route) adapter, err := priceRouteAdapter.SelectAdapter(routeConfig.Route)
if err != nil { if err != nil {
return nil, err return platformStoreSku, err
} }
rateKey := pc3SkuModel.PriceDetail.Currency + "_" + string(routeConfig.Currency) currencyRate, err := receiver.rate.GetRate(seller.Store, pc3SkuModel.PriceDetail.Currency, routeConfig.Currency.String())
currencyRate, err := r.rateConfig.GetRate(rateKey, seller.Platform) if err != nil {
if err != nil || currencyRate == 0 { return platformStoreSku, err
currencyRate, err = r.updateOrSetRate(rateKey, seller.Platform)
if err != nil {
return nil, errors.New("无法获取汇率信息")
}
} }
oldSkuPriceRecord, err := r.dataRepo.GetOneSkuPrice(ctx, localSkuModel.Id, seller.Platform, seller.Store, routeConfig.Route) subjects := receiver.mongoManager.SubjectModel.GetCacheMany(func(document subjectModel.Subject) bool {
if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { return slices.Contains(productColorSku.SubjectIds, document.Id.Hex())
return nil, err })
var subjectRate, subjectId = float64(1), ""
for _, subject := range subjects {
if subject.PriceRate < subjectRate {
subjectRate = subject.PriceRate
subjectId = subject.Id.Hex()
}
} }
subjectRate, subjectId, err := r.getSubjectRateAndSubject(pc3SkuModel, svcProductModel, seller.Platform)
if err != nil {
return nil, err
}
// 固定毛利 // 固定毛利
margin := 1.0 margin := 1.0
if oldSkuPriceRecord != nil && oldSkuPriceRecord.FixMargin != nil && *oldSkuPriceRecord.FixMargin != 0 { if fixMargin != 0 {
margin = 1 + (*oldSkuPriceRecord.FixMargin / 100) margin = 1 + (fixMargin / 100)
} else { } else {
margin, err = r.calculateMargin(routeConfig, svcProductModel, pc3SkuModel, seller) margin, err = receiver.calculateMargin(product, productColorSku, routeConfig, pc3SkuModel, seller)
if err != nil { if err != nil {
return nil, err return platformStoreSku, err
} }
} }
margin = math2.Round(math.Max(1.0, margin), 3) // 保底1.0 margin = math2.Round(math.Max(1.0, margin), 3) // 保底1.0
freight, err := r.calculateFreight(pc3SkuModel, categories, routeConfig.FreightConfig, seller.Platform) freight, err := receiver.calculateFreight(pc3SkuModel, categories, routeConfig.FreightConfig, seller.Store)
if err != nil { if err != nil {
return nil, err return platformStoreSku, err
} }
priceDetail := embed.RoutePriceDetail{ priceDetail := priceRouteAdapter.RoutePriceDetail{
Route: routeConfig.Route, Route: routeConfig.Route,
Currency: string(routeConfig.Currency), Currency: string(routeConfig.Currency),
OriginCurrency: pc3SkuModel.PriceDetail.Currency, OriginCurrency: pc3SkuModel.PriceDetail.Currency,
...@@ -107,55 +119,314 @@ func (receiver *PlatformStoreSku) calculateRoutePrice(svcProductModel *ProductMo ...@@ -107,55 +119,314 @@ func (receiver *PlatformStoreSku) calculateRoutePrice(svcProductModel *ProductMo
TotalDiscount: pc3SkuModel.PriceDetail.Discount * subjectRate, TotalDiscount: pc3SkuModel.PriceDetail.Discount * subjectRate,
TaxRate: 1 + routeConfig.TaxRate, TaxRate: 1 + routeConfig.TaxRate,
Freight: freight, Freight: freight,
Express: r.calculateExpress(categories, routeConfig.ExpressConfig), Express: receiver.calculateExpress(categories, routeConfig.ExpressConfig),
} }
// 计算最终价格 // 计算最终价格
priceDetail.Price, err = adapter.GetPrice(pc3SkuModel.PriceDetail.Now, priceDetail, platform.Platform(seller.Platform)) priceDetail.Price, err = adapter.GetPrice(pc3SkuModel.PriceDetail.Now, priceDetail, platform.Platform(seller.Platform))
if err != nil { if err != nil {
return nil, err return platformStoreSku, err
} }
rateKey = priceDetail.Currency + "_" + string(embed.CurrencyCNY) cnyRate, err := receiver.rate.GetRate(seller.Store, priceDetail.Currency, currency.CNY.String())
cnyRate, err := r.rateConfig.GetRate(rateKey, seller.Platform) if err != nil {
if err != nil || cnyRate == 0 { return platformStoreSku, err
cnyRate, err = r.updateOrSetRate(rateKey, seller.Platform)
if err != nil {
log.Println(rateKey+"无法获取汇率信息:", err)
}
} }
record := model.SkuPrice{ platformStoreSku = productModel.ProductColorSkuPlatformStoreSku{
SkuId: localSkuModel.Id,
Mid: svcProductModel.Id,
Platform: seller.Platform, Platform: seller.Platform,
Store: seller.Store, Store: seller.Store,
Qty: localSkuModel.Quantity,
Route: priceDetail.Route, Route: priceDetail.Route,
Currency: priceDetail.Currency, Currency: priceDetail.Currency,
OriginCurrency: priceDetail.OriginCurrency, OriginCurrency: priceDetail.OriginCurrency,
Price: priceDetail.Price, Price: priceDetail.Price,
Rate: priceDetail.Rate, //FixPrice: priceDetail,
CnyRate: cnyRate, //FixMargin: nil,
Margin: priceDetail.Margin, Rate: priceDetail.Rate,
SubjectRate: priceDetail.SubjectRate, CnyRate: cnyRate,
Subject: priceDetail.Subject, Margin: priceDetail.Margin,
DiscountRate: priceDetail.DiscountRate, SubjectRate: priceDetail.SubjectRate,
TotalDiscount: priceDetail.TotalDiscount, Subject: priceDetail.Subject,
TaxRate: priceDetail.TaxRate, DiscountRate: priceDetail.DiscountRate,
Freight: priceDetail.Freight, TotalDiscount: priceDetail.TotalDiscount,
Express: priceDetail.Express, TaxRate: priceDetail.TaxRate,
} Freight: priceDetail.Freight,
Express: priceDetail.Express,
if oldSkuPriceRecord != nil { //ChangeRate: nil,
now := time.Now() //ChangeAt: nil,
change := math2.Round((priceDetail.Price-oldSkuPriceRecord.Price)/oldSkuPriceRecord.Price, 4) //Memos: nil,
record.Id = oldSkuPriceRecord.Id }
record.FixedQty = oldSkuPriceRecord.FixedQty
if math.Abs(change) > 0.0001 { // todo
record.ChangeRate = &change //if oldSkuPriceRecord != nil {
record.ChangeAt = &now // now := time.Now()
} // change := math2.Round((priceDetail.Price-oldSkuPriceRecord.Price)/oldSkuPriceRecord.Price, 4)
} // record.Id = oldSkuPriceRecord.Id
return &record, nil // record.FixedQty = oldSkuPriceRecord.FixedQty
// if math.Abs(change) > 0.0001 {
// record.ChangeRate = &change
// record.ChangeAt = &now
// }
//}
return platformStoreSku, nil
}
func (receiver *PlatformStoreSku) calculateExpress(categoryIds []string, config sitePlatformPriceConfigModel.ExpressConfig) float64 {
if config.ExpressStyle == sitePlatformPriceConfigModel.ExpressStyleDefault {
return config.Express
} else if config.ExpressStyle == sitePlatformPriceConfigModel.ExpressStyleCategory {
opt := 50.0 // 操作费
fee := 0.0 + opt
// 没有分类的定为 30
if len(categoryIds) <= 0 {
return fee + 30
}
if receiver.isSuitcases(categoryIds) {
return fee + 299 // 箱包固定 299
}
if receiver.isUmbrellasBoots(categoryIds) {
fee = 25 // 雨伞多收 25
}
// 按重量计算
weight := receiver.getWeightByCategory(categoryIds)
if weight >= 4 {
fee += 70
} else if weight == 3 {
fee += 55
} else if weight == 2 {
fee += 42
} else {
fee += 30
}
return fee
}
return 0
}
// 特别细分品类预估重量,优先级比上面的一级要高
var specialWeightMapping = map[string]int{
"boots": 3, // 靴子
"sneaker": 3, // 运动鞋
"coat": 2, // 外套
"jumpsuits-playsuits": 2, // 连身裤
"suit": 2, // 西装
"hat": 2, // 帽子
"denim": 2, //牛仔服装
}
// 一级分类基本预估重量
var basicWeightMapping = map[string]int{
"accessory": 1, // 配饰
"bag": 2, // 包袋
"clothing": 1, // 服装
"gear": 1, // 装备
"shoes": 2, // 鞋类
"home": 1, // 居家日用
}
func (receiver *PlatformStoreSku) getWeightByCategory(categoryIds []string) int {
for _, categoryId := range categoryIds {
if weight, ok := specialWeightMapping[categoryId]; ok {
return weight
}
}
for _, categoryId := range categoryIds {
if weight, ok := basicWeightMapping[categoryId]; ok {
return weight
}
}
return 1
}
// 长柄雨伞
var umbrellas = []string{
"umbrella", // 雨伞
}
func (receiver *PlatformStoreSku) isUmbrellasBoots(categoryIds []string) bool {
for _, categoryId := range categoryIds {
if slice.Contains(umbrellas, categoryId) {
return true
}
}
return false
}
// 行李箱
var suitCases = []string{
"suitcase", // 拉杆箱
}
func (receiver *PlatformStoreSku) isSuitcases(categoryIds []string) bool {
for _, categoryId := range categoryIds {
if slice.Contains(suitCases, categoryId) {
return true
}
}
return false
}
func (receiver *PlatformStoreSku) calculateFreight(pc3Sku pc3.ModelSku, categoryIds []string, config sitePlatformPriceConfigModel.FreightConfig, store types.Store) (float64, error) {
switch config.FreightStyle {
case sitePlatformPriceConfigModel.FreightStyleDefault:
return config.Freight, nil
case sitePlatformPriceConfigModel.FreightStyleCategory:
// 配饰 或者(服装下不属于 外套、礼服、针织衫)的分类
if slice.Contains(categoryIds, "accessory") ||
(slice.Contains(categoryIds, "clothing") &&
!slice.Contains(categoryIds, "outwear") &&
!slice.Contains(categoryIds, "dress") &&
!slice.Contains(categoryIds, "knitwear")) {
return 80, nil
}
// 其他分类就用250
return 100, nil
case sitePlatformPriceConfigModel.FreightStylePrice:
if pc3Sku.PriceDetail.Price < 1500 {
return 30, nil
} else if pc3Sku.PriceDetail.Price < 2500 {
return 50, nil
} else if pc3Sku.PriceDetail.Price < 3500 {
return 80, nil
} else {
return 100, nil
}
case sitePlatformPriceConfigModel.FreightStyleMinPrice:
// 统一转成人民币价格后再计算
currencyRate, err := receiver.rate.GetRate(store, config.OverFreightCurrency.String(), currency.CNY.String())
if err != nil {
return 0, err
}
limitPrice := float64(config.OverFreight) * currencyRate
goodCnyPrice := pc3Sku.PriceDetail.Price * pc3Sku.PriceDetail.SubjectRate
if goodCnyPrice >= limitPrice {
return 0, nil
}
return config.Freight, nil
}
return 0, nil
}
func (receiver *PlatformStoreSku) calculateMargin(product productModel.Product, productColorSku productModel.ProductColorSku, routeConfig sitePlatformPriceConfigModel.RoutePriceConfig, pc3Sku pc3.ModelSku, seller types.Seller) (float64, error) {
floatMargin := 1.0
if routeConfig.Route == types.RouteComplex {
// 尝试获取品牌性别品类组合加价配置
comboMarginConfig, ok := receiver.mongoManager.SiteComboMarginConfigModel.GetCacheOne(func(document siteComboMarginConfigModel.SiteComboMarginConfig) bool {
return document.Seller.Platform == seller.Platform &&
document.Seller.Store == seller.Store && !document.Enable &&
document.SiteId == productColorSku.SiteId &&
slices.Contains(document.Brands, product.Brand.Id) &&
document.IsGenderMatch(product.Genders) &&
slices.Contains(document.Categories, product.Category.Id)
})
if ok {
return 1 + (comboMarginConfig.Margin / 100), nil
}
// 尝试解析浮动加价率配置
siteFloatMarginConfig, ok := receiver.mongoManager.SiteFloatMarginConfigModel.GetCacheOne(func(document siteFloatMarginConfigModel.SiteFloatMarginConfig) bool {
return document.Seller.Platform == seller.Platform && document.Seller.Store == seller.Store
})
if ok {
rules, err := siteFloatMarginConfig.Explain()
if err != nil {
return 0, err
}
for _, rule := range rules {
if ok, v := receiver.IsFloatMarginConfigMatch(rule, product); ok {
if v != "" {
intValue, _ := strconv.Atoi(v)
flotV := 1 + (float64(intValue) / 100)
floatMargin *= flotV
//log.Println("命中浮动加价率配置:", rule.Type, flotV)
}
}
}
}
// 尝试获取站点分组加价配置
siteGroupMarginConfig, ok := receiver.mongoManager.SiteGroupMarginConfigModel.GetCacheOne(func(document siteGroupMarginConfigModel.SiteGroupMarginConfig) bool {
return document.Seller.Platform == seller.Platform && document.Seller.Store == seller.Store &&
document.IsMatch(productColorSku.SiteId)
})
if ok {
return (1 + (siteGroupMarginConfig.Margin / 100)) * floatMargin, nil
}
}
// 保底站点加价率 * 浮动
marginConfig := routeConfig.MarginConfig
switch marginConfig.MarginStyle {
case sitePlatformPriceConfigModel.MarginStyleFixed:
return (1 + marginConfig.Margin) * floatMargin, nil
case sitePlatformPriceConfigModel.MarginStyleLadder:
if marginConfig.IsValidLadders() {
marginConfig.FormatLadders()
for _, ladder := range marginConfig.Ladders {
if ladder.IsMatch(pc3Sku.PriceDetail.Price) {
return (1 + ladder.Margin) * floatMargin, nil
}
}
}
return 0, fmt.Errorf("阶梯加价未能找到合适的价格区间匹配加价率")
default:
return 1, nil
}
}
func (receiver *PlatformStoreSku) IsFloatMarginConfigMatch(cr siteFloatMarginConfigModel.ConditionRule, p productModel.Product) (bool, string) {
if cr.Type == "season" && p.Season != "" {
if p.Season == "CO" {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeySeasonCO)
}
reg := "(FW|SS)(\\d{2})"
if ok, _ := regexp.MatchString(reg, p.Season); ok {
nowMonth := time.Now().Month()
nowYear := time.Now().Year() - 2000
prefix := "SS"
if nowMonth > 6 {
prefix = "FW"
}
yearInSeason, _ := strconv.Atoi(p.Season[2:])
prefixInSeason := p.Season[:2]
if yearInSeason > nowYear {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeySeasonNow)
}
if yearInSeason == nowYear && (prefixInSeason == prefix || prefixInSeason == "FW") {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeySeasonNow)
}
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeySeasonOld)
}
}
if cr.Type == "brand" {
if p.Brand.Id == "" {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeyBrandTail)
} else {
topBrands, middleBrands := receiver.brandRankCache.GetBrandRankIds()
if slice.Contains(topBrands, p.Brand.Id) {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeyBrandTop)
}
if slice.Contains(middleBrands, p.Brand.Id) {
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeyBrandMiddle)
}
return true, cr.Get(siteFloatMarginConfigModel.ConditionKeyBrandTail)
}
}
if cr.Type == "category" && p.Category.Id != "" {
if slice.Contains([]string{"clothing", "bag", "shoes", "accessory"}, p.Category.Id) {
return true, cr.Get("category_" + p.Category.Id)
}
}
return false, ""
} }
package convert package convert
import ( import (
"git.chillcy.com/golang/chillcy/pkg/gender"
"git.chillcy.com/golang/chillcy/pkg/slice" "git.chillcy.com/golang/chillcy/pkg/slice"
"git.chillcy.com/golang/chillcy/project/pc4/pkg/rpc/pb/pc4" "git.chillcy.com/golang/chillcy/project/pc4/pkg/rpc/pb/pc4"
model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product" model "git.chillcy.com/golang/colorway/internal/pkg/database/mongo/model/product"
...@@ -28,6 +29,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model. ...@@ -28,6 +29,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model.
for _, productAndSkus := range colorProduct.GetProductAndSkusList() { for _, productAndSkus := range colorProduct.GetProductAndSkusList() {
product := productAndSkus.GetProduct() product := productAndSkus.GetProduct()
once.Do(func() { once.Do(func() {
p.StyleId = styleNumber
p.StyleNumber = styleNumber p.StyleNumber = styleNumber
p.Title = model.ProductTitle{ p.Title = model.ProductTitle{
En: product.GetTitleEn(), En: product.GetTitleEn(),
...@@ -53,7 +55,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model. ...@@ -53,7 +55,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model.
} }
p.Fits = product.GetDetail().GetFits() p.Fits = product.GetDetail().GetFits()
for _, g := range product.GetGenders() { for _, g := range product.GetGenders() {
p.Genders = append(p.Genders, model.ProductGender(g)) p.Genders = append(p.Genders, gender.Gender(g))
} }
p.Models = product.GetDetail().GetModels() p.Models = product.GetDetail().GetModels()
}) })
...@@ -92,7 +94,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model. ...@@ -92,7 +94,7 @@ func (receiver *Product) Convert(designerProducts []*pc4.DesignerProduct) model.
} }
} }
} }
p.Colors = buildProductColors(designerProduct.GetColorProducts(), designerProduct.GetDesignerId(), ws) p.Colors = buildProductColors(designerProduct.GetColorProducts(), ws, designerProduct.GetDesignerId())
ps = append(ps, p) ps = append(ps, p)
} }
return ps return ps
...@@ -111,20 +113,21 @@ func getCategory(category *pc4.CategoryV2) model.ProductCategory { ...@@ -111,20 +113,21 @@ func getCategory(category *pc4.CategoryV2) model.ProductCategory {
return pc return pc
} }
func buildProductColors(colorProducts []*pc4.ColorProduct, styleNumber string, ws weightSelect) model.ProductColors { func buildProductColors(colorProducts []*pc4.ColorProduct, ws weightSelect, styleNumber string) model.ProductColors {
var pcs model.ProductColors var pcs model.ProductColors
for _, colorProduct := range colorProducts { for _, colorProduct := range colorProducts {
pcs = append(pcs, buildProductColor(colorProduct, styleNumber, ws)) pcs = append(pcs, buildProductColor(colorProduct, ws, styleNumber))
} }
return pcs return pcs
} }
func buildProductColor(colorProduct *pc4.ColorProduct, styleNumber string, ws weightSelect) model.ProductColor { func buildProductColor(colorProduct *pc4.ColorProduct, ws weightSelect, styleNumber string) model.ProductColor {
pc := model.ProductColor{} pc := model.ProductColor{}
once := &sync.Once{} once := &sync.Once{}
for _, productAndSkus := range colorProduct.GetProductAndSkusList() { for _, productAndSkus := range colorProduct.GetProductAndSkusList() {
product := productAndSkus.GetProduct() product := productAndSkus.GetProduct()
once.Do(func() { once.Do(func() {
pc.ColorId = colorProduct.GetColorNumber()
pc.ColorCode = colorProduct.GetColorNumber() pc.ColorCode = colorProduct.GetColorNumber()
pc.Id = product.GetColor().GetId() pc.Id = product.GetColor().GetId()
pc.Name = product.GetColor().GetName() pc.Name = product.GetColor().GetName()
...@@ -148,6 +151,7 @@ func buildProductColor(colorProduct *pc4.ColorProduct, styleNumber string, ws we ...@@ -148,6 +151,7 @@ func buildProductColor(colorProduct *pc4.ColorProduct, styleNumber string, ws we
Stock: int(sku.GetStock()), Stock: int(sku.GetStock()),
Price: sku.GetPriceDetail().GetNow(), Price: sku.GetPriceDetail().GetNow(),
Currency: sku.GetPriceDetail().GetCurrency(), Currency: sku.GetPriceDetail().GetCurrency(),
SubjectIds: product.Subjects,
}) })
} }
} }
......
package priceRouteAdapter package priceRouteAdapter
import "go.mongodb.org/mongo-driver/bson/primitive" import (
"git.chillcy.com/golang/colorway/pkg/types"
)
type RoutePriceDetail struct { type RoutePriceDetail struct {
Route string `bson:"route"` // 线路 Route types.Route `bson:"route"` // 线路
Currency string `bson:"currency"` // 销售平台的币种 Currency string `bson:"currency"` // 销售平台的币种
OriginCurrency string `bson:"originCurrency"` // 原始币种 OriginCurrency string `bson:"originCurrency"` // 原始币种
Price float64 `bson:"price"` // 最终价格 Price float64 `bson:"price"` // 最终价格
Rate float64 `bson:"rate"` // OriginCurrency -> Currency 的汇率 Rate float64 `bson:"rate"` // OriginCurrency -> Currency 的汇率
Margin float64 `bson:"margin"` // 加价率 Margin float64 `bson:"margin"` // 加价率
SubjectRate float64 `bson:"subjectRate"` // 专题系数 SubjectRate float64 `bson:"subjectRate"` // 专题系数
Subject *primitive.ObjectID `bson:"subjectID"` // 绑定的专题id Subject string `bson:"subjectID"` // 绑定的专题id
DiscountRate float64 `bson:"discountRate"` // 商家系数 DiscountRate float64 `bson:"discountRate"` // 商家系数
TotalDiscount float64 `bson:"totalDiscount"` // 总折扣 TotalDiscount float64 `bson:"totalDiscount"` // 总折扣
TaxRate float64 `bson:"taxRate"` // 税率 TaxRate float64 `bson:"taxRate"` // 税率
Freight float64 `bson:"freight"` // 商家运费 Freight float64 `bson:"freight"` // 商家运费
Express float64 `bson:"express"` // 跨境费 Express float64 `bson:"express"` // 跨境费
} }
package rate
import (
"fmt"
"git.chillcy.com/golang/chillcy/pkg/sdk/rate"
"git.chillcy.com/golang/colorway/pkg/types"
)
type Rate struct {
rateClient *rate.Client
}
func (receiver *Rate) GetRate(store types.Store, from, to string) (float64, error) {
switch store {
case types.StoreTmall2cStore1, types.StoreJDStoreGongxiao:
return receiver.rateClient.Sell(from, to)
case types.StoreTmall2bHK, types.StoreTmall2bEUR, types.StoreTmall2bUS:
return receiver.rateClient.Net(from, to)
}
return 0, fmt.Errorf("未配置店铺汇率 %s", store)
}
...@@ -40,7 +40,8 @@ func NewServiceContext(c config.Config) *ServiceContext { ...@@ -40,7 +40,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
}, },
} }
cache.InitCache(cache.Config{ cache.InitCache(cache.Config{
Source: svc.Pc4RpcService.Source, Source: svc.Pc4RpcService.Source,
BrandDataModel: mongoManager.BrandDataModel,
}) })
svc.Cache = cache.GetCache() svc.Cache = cache.GetCache()
svc.SpuConvert = convert.NewSpu(svc.Cache) svc.SpuConvert = convert.NewSpu(svc.Cache)
......
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 to comment