feat 优惠活动可编辑
This commit is contained in:
parent
e7fa9e7dd2
commit
3490bc7e57
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
||||
github.com/bytedance/sonic v1.11.6
|
||||
github.com/cloudwego/hertz v0.9.1
|
||||
github.com/corpix/uarand v0.2.0
|
||||
github.com/expr-lang/expr v1.16.9
|
||||
github.com/go-resty/resty/v2 v2.13.1
|
||||
github.com/golang/glog v1.2.1
|
||||
github.com/metacubex/mihomo v1.18.4
|
||||
|
2
go.sum
2
go.sum
@ -81,6 +81,8 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE
|
||||
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4=
|
||||
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA=
|
||||
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok=
|
||||
github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
|
||||
github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
|
@ -2,6 +2,7 @@ package productv1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/expr-lang/expr"
|
||||
"gorm.io/gorm"
|
||||
"math"
|
||||
"strings"
|
||||
@ -35,21 +36,20 @@ type Product struct {
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
|
||||
Name string `gorm:"index" json:"name"`
|
||||
Pid string `gorm:"unique;not null" json:"pid"`
|
||||
Pid string `gorm:"index:,unique,composite:product_pid_website_idx;not null" json:"pid"`
|
||||
Color string `json:"color"`
|
||||
Link string `json:"link"`
|
||||
Image string `json:"image"`
|
||||
Orderable bool `json:"orderable"`
|
||||
|
||||
USPrice float64 `json:"usPrice"`
|
||||
Website Website `json:"website" gorm:"index"`
|
||||
OriginalPrice float64 `json:"originalPrice"`
|
||||
Website Website `json:"website" gorm:"index:,unique,composite:product_pid_website_idx"`
|
||||
DiscPercent int `json:"discPercent" gorm:"index"` //折扣力度
|
||||
CNYPrice float64 `json:"cnyPrice"`
|
||||
CNYPrice float64 `json:"cnyPrice"` // 最终的价格
|
||||
CalMark string `json:"calMark"` //计算价格的过程
|
||||
DWPrice float64 `json:"dwPrice"`
|
||||
Freight float64 `json:"freight"` //运费
|
||||
ExchangeRate float64 `json:"exchangeRate" gorm:"-"` //汇率
|
||||
Discount int `json:"discount" gorm:"-"` //折扣
|
||||
Rate float64 `json:"rate" gorm:"index"` //利润率
|
||||
PriceStatus PriceStatus `json:"priceStatus"` //价格状态
|
||||
Remark string `json:"remark"` //备注
|
||||
@ -62,29 +62,29 @@ func (p *Product) TableName() string {
|
||||
return "products"
|
||||
}
|
||||
|
||||
func (p *Product) Env() map[string]any {
|
||||
return map[string]any{
|
||||
"originalPrice": p.OriginalPrice,
|
||||
"dwPrice": p.DWPrice,
|
||||
"freight": p.Freight,
|
||||
"exchangeRate": p.ExchangeRate,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Product) BeforeSave(tx *gorm.DB) (err error) {
|
||||
p.CalRate()
|
||||
p.fillPriceStatus(tx)
|
||||
p.CalRate()
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Product) fillPriceStatus(tx *gorm.DB) {
|
||||
switch p.Website {
|
||||
case WebSite_US_Coach_Outlet:
|
||||
p.fillUSCoachPriceStatus(tx)
|
||||
case WebSite_CN_Coach:
|
||||
p.fillCNCoachPriceStatus(tx)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Product) fillUSCoachPriceStatus(tx *gorm.DB) {
|
||||
var lastPrice float64
|
||||
tx.Model(&HistoryPrice{}).Where("pid = ?", p.Pid).Order("created_at desc").Limit(1).Pluck("us_price", &lastPrice)
|
||||
if p.USPrice != lastPrice {
|
||||
tx.Model(&HistoryPrice{}).Where("pid = ?", p.Pid).Order("created_at desc").Limit(1).Pluck("original_price", &lastPrice)
|
||||
if p.OriginalPrice != lastPrice {
|
||||
p.HistoryPrices = append(p.HistoryPrices, HistoryPrice{
|
||||
USPrice: p.USPrice,
|
||||
OriginalPrice: p.OriginalPrice,
|
||||
})
|
||||
if p.USPrice > lastPrice {
|
||||
if p.OriginalPrice > lastPrice {
|
||||
p.PriceStatus = PriceStatus_UP
|
||||
} else {
|
||||
p.PriceStatus = PriceStatus_DOWN
|
||||
@ -92,81 +92,83 @@ func (p *Product) fillUSCoachPriceStatus(tx *gorm.DB) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Product) fillCNCoachPriceStatus(tx *gorm.DB) {
|
||||
var lastPrice float64
|
||||
tx.Model(&HistoryPrice{}).Where("pid = ?", p.Pid).Order("created_at desc").Limit(1).Pluck("us_price", &lastPrice)
|
||||
if p.CNYPrice != lastPrice {
|
||||
p.HistoryPrices = append(p.HistoryPrices, HistoryPrice{
|
||||
USPrice: p.CNYPrice,
|
||||
})
|
||||
if p.CNYPrice > lastPrice {
|
||||
p.PriceStatus = PriceStatus_UP
|
||||
} else {
|
||||
p.PriceStatus = PriceStatus_DOWN
|
||||
func (p *Product) CalCNY(calculateProcess []CalculateProcess) {
|
||||
env := p.Env()
|
||||
var calculateStrings = make([]string, 0, len(calculateProcess))
|
||||
for _, c := range calculateProcess {
|
||||
process, price := c.Calculate(env)
|
||||
if process != "" {
|
||||
calculateStrings = append(calculateStrings, process)
|
||||
p.CNYPrice = min(p.CNYPrice, price)
|
||||
}
|
||||
}
|
||||
p.CalMark = strings.Join(calculateStrings, "\n")
|
||||
}
|
||||
|
||||
//func (p *Product) CalRate() {
|
||||
// switch p.Website {
|
||||
// case WebSite_US_Coach_Outlet:
|
||||
// p.CalRateUSCoach()
|
||||
// case WebSite_CN_Coach:
|
||||
// p.CalRateCNCoach()
|
||||
// }
|
||||
//}
|
||||
|
||||
//func (p *Product) CalRateUSCoach() {
|
||||
// calculationProcess := make([]string, 0, 2) //存放计算过程
|
||||
// if p.ExchangeRate == 0 {
|
||||
// p.ExchangeRate = defaultExchangeRate
|
||||
// }
|
||||
// if p.Freight == 0 {
|
||||
// p.Freight = defaultFreight
|
||||
// }
|
||||
// if p.Discount == 0 {
|
||||
// p.Discount = 100
|
||||
// }
|
||||
//
|
||||
// //先计算打九折的价格
|
||||
// tmpPrice := p.USPrice * 0.9 // 这是打九折的价格
|
||||
// p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
// calculationProcess = append(calculationProcess, fmt.Sprintf("【九折】%.2f * 0.9 * %.2f + %.2f = %.2f", p.USPrice, p.ExchangeRate, p.Freight, p.CNYPrice))
|
||||
// var discountPrice = p.USPrice
|
||||
// if 0 < p.Discount && p.Discount < 100 {
|
||||
// discountPrice = p.USPrice * float64(p.Discount) / 100
|
||||
// }
|
||||
// if discountPrice >= 150 {
|
||||
// calculationProcess = append(calculationProcess, fmt.Sprintf("【150 -20】(%.2f * %d%% - 20) * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, (discountPrice-20)*p.ExchangeRate+p.Freight))
|
||||
// if discountPrice-20 < tmpPrice {
|
||||
// // 符合满150-20,而且比九折便宜
|
||||
// tmpPrice = discountPrice - 20
|
||||
// p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
// }
|
||||
// } else if discountPrice >= 100 {
|
||||
// calculationProcess = append(calculationProcess, fmt.Sprintf("【100 -10】(%.2f * %d%% - 10) * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, (discountPrice-10)*p.ExchangeRate+p.Freight))
|
||||
// if discountPrice-10 < tmpPrice {
|
||||
// // 符合满100 -10,而且比九折便宜
|
||||
// tmpPrice = discountPrice - 10
|
||||
// p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
// }
|
||||
// } else if p.Discount < 90 {
|
||||
// calculationProcess = append(calculationProcess, fmt.Sprintf("【打折扣】%.2f * %d%% * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, p.USPrice*float64(p.Discount)/100*p.ExchangeRate+p.Freight))
|
||||
// p.CNYPrice = p.USPrice*float64(p.Discount)/100*p.ExchangeRate + p.Freight
|
||||
// }
|
||||
// p.CalMark = strings.Join(calculationProcess, "\n")
|
||||
// if p.DWPrice > 0 {
|
||||
// // 如果有得物价格,就计算收益率
|
||||
// p.Rate = Decimal((p.DWPrice - p.CNYPrice) / p.CNYPrice * 100)
|
||||
// }
|
||||
//
|
||||
// p.CNYPrice = Decimal(p.CNYPrice)
|
||||
//}
|
||||
|
||||
// CalRate 计算收益率
|
||||
func (p *Product) CalRate() {
|
||||
switch p.Website {
|
||||
case WebSite_US_Coach_Outlet:
|
||||
p.CalRateUSCoach()
|
||||
case WebSite_CN_Coach:
|
||||
p.CalRateCNCoach()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Product) CalRateUSCoach() {
|
||||
calculationProcess := make([]string, 0, 2) //存放计算过程
|
||||
if p.ExchangeRate == 0 {
|
||||
p.ExchangeRate = defaultExchangeRate
|
||||
}
|
||||
if p.Freight == 0 {
|
||||
p.Freight = defaultFreight
|
||||
}
|
||||
if p.Discount == 0 {
|
||||
p.Discount = 100
|
||||
}
|
||||
|
||||
//先计算打九折的价格
|
||||
tmpPrice := p.USPrice * 0.9 // 这是打九折的价格
|
||||
p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
calculationProcess = append(calculationProcess, fmt.Sprintf("【九折】%.2f * 0.9 * %.2f + %.2f = %.2f", p.USPrice, p.ExchangeRate, p.Freight, p.CNYPrice))
|
||||
var discountPrice = p.USPrice
|
||||
if 0 < p.Discount && p.Discount < 100 {
|
||||
discountPrice = p.USPrice * float64(p.Discount) / 100
|
||||
}
|
||||
if discountPrice >= 150 {
|
||||
calculationProcess = append(calculationProcess, fmt.Sprintf("【150 -20】(%.2f * %d%% - 20) * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, (discountPrice-20)*p.ExchangeRate+p.Freight))
|
||||
if discountPrice-20 < tmpPrice {
|
||||
// 符合满150-20,而且比九折便宜
|
||||
tmpPrice = discountPrice - 20
|
||||
p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
}
|
||||
} else if discountPrice >= 100 {
|
||||
calculationProcess = append(calculationProcess, fmt.Sprintf("【100 -10】(%.2f * %d%% - 10) * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, (discountPrice-10)*p.ExchangeRate+p.Freight))
|
||||
if discountPrice-10 < tmpPrice {
|
||||
// 符合满100 -10,而且比九折便宜
|
||||
tmpPrice = discountPrice - 10
|
||||
p.CNYPrice = tmpPrice*p.ExchangeRate + p.Freight
|
||||
}
|
||||
} else if p.Discount < 90 {
|
||||
calculationProcess = append(calculationProcess, fmt.Sprintf("【打折扣】%.2f * %d%% * %.2f + %.2f = %.2f", p.USPrice, p.Discount, p.ExchangeRate, p.Freight, p.USPrice*float64(p.Discount)/100*p.ExchangeRate+p.Freight))
|
||||
p.CNYPrice = p.USPrice*float64(p.Discount)/100*p.ExchangeRate + p.Freight
|
||||
}
|
||||
p.CalMark = strings.Join(calculationProcess, "\n")
|
||||
if p.DWPrice > 0 {
|
||||
// 如果有得物价格,就计算收益率
|
||||
p.Rate = Decimal((p.DWPrice - p.CNYPrice) / p.CNYPrice * 100)
|
||||
}
|
||||
|
||||
p.CNYPrice = Decimal(p.CNYPrice)
|
||||
}
|
||||
|
||||
func (p *Product) CalRateCNCoach() {
|
||||
if p.DWPrice > 0 {
|
||||
// 如果有得物价格,就计算收益率
|
||||
p.Rate = Decimal((p.DWPrice - p.CNYPrice) / p.CNYPrice * 100)
|
||||
} else if p.Rate > 0 {
|
||||
// 如果得物价格为0, 收益率应该设置为0
|
||||
p.Rate = 0
|
||||
}
|
||||
|
||||
p.CNYPrice = Decimal(p.CNYPrice)
|
||||
@ -182,7 +184,7 @@ type HistoryPrice struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
Pid string `gorm:"index" json:"pid"`
|
||||
USPrice float64 `json:"usPrice"`
|
||||
OriginalPrice float64 `json:"originalPrice"`
|
||||
}
|
||||
|
||||
type DWHistoryPrice struct {
|
||||
@ -192,3 +194,46 @@ type DWHistoryPrice struct {
|
||||
Pid string `gorm:"index" json:"pid"`
|
||||
DWPrice float64 `json:"dwPrice"`
|
||||
}
|
||||
|
||||
// CalculateProcess 计算过程
|
||||
type CalculateProcess struct {
|
||||
ID uint `gorm:"primary_key" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
|
||||
Pid string
|
||||
Website Website
|
||||
Condition string
|
||||
Process string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *CalculateProcess) Calculate(env map[string]any) (string, float64) {
|
||||
if c.Condition != "" {
|
||||
condition, err := expr.Compile(c.Condition, expr.AsBool())
|
||||
if err != nil {
|
||||
return fmt.Sprintf("【%s】 condition compile error: %v", c.Name, err), 0
|
||||
}
|
||||
if ok, err := expr.Run(condition, env); err != nil {
|
||||
return fmt.Sprintf("【%s】 condition run error: %v", c.Name, err), 0
|
||||
} else if !ok.(bool) {
|
||||
return "", 0
|
||||
}
|
||||
}
|
||||
program, err := expr.Compile(c.Process, expr.AsFloat64())
|
||||
if err != nil {
|
||||
return fmt.Sprintf("【%s】 process compile error: %v", c.Name, err), 0
|
||||
}
|
||||
|
||||
output, err := expr.Run(program, env)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("【%s】 process run error: %v", c.Name, err), 0
|
||||
}
|
||||
var replaceList = make([]string, 0, 2*len(env))
|
||||
for k, v := range env {
|
||||
replaceList = append(replaceList, k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
replacer := strings.NewReplacer(replaceList...)
|
||||
return replacer.Replace(fmt.Sprintf("【%s】 %s = %.2f", c.Name, c.Process, output.(float64))), output.(float64)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func TestUpsert(t *testing.T) {
|
||||
Link: "www.baidu.com",
|
||||
Image: "image",
|
||||
Orderable: false,
|
||||
USPrice: 123,
|
||||
OriginalPrice: 123,
|
||||
DWPrice: 3000,
|
||||
Freight: 130,
|
||||
},
|
||||
@ -50,7 +50,7 @@ func TestUpdate(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var p = Product{Pid: "CJ575-QBO4G", DWPrice: 3000, Freight: 150, Remark: "test", USPrice: 209.3, ExchangeRate: 7.3}
|
||||
var p = Product{Pid: "CJ575-QBO4G", DWPrice: 3000, Freight: 150, Remark: "test", OriginalPrice: 209.3, ExchangeRate: 7.3}
|
||||
err = db.Model(&p).Where("pid = ?", p.Pid).Select("dw_price", "freight", "remark", "rate", "cal_mark", "cny_price").Updates(&p).Error
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -72,3 +72,18 @@ func TestGetConfig(t *testing.T) {
|
||||
db.Table("options").Select("exchange_rate").Where("id = ?", 1).Scan(&exchangeRate)
|
||||
t.Log(exchangeRate)
|
||||
}
|
||||
|
||||
func TestCalculateProcess_Calculate(t *testing.T) {
|
||||
p := Product{
|
||||
OriginalPrice: 160.9,
|
||||
Freight: 100,
|
||||
ExchangeRate: 7.3,
|
||||
PriceStatus: 0,
|
||||
}
|
||||
cal := CalculateProcess{
|
||||
Condition: "usPrice >= 150",
|
||||
Process: "(usPrice - 20) * exchangeRate + freight",
|
||||
Name: "满150 - 20",
|
||||
}
|
||||
t.Log(cal.Calculate(p.Env()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user