feat(v2): 多币种 product(ProductPrice 分币价目 + v1 元回退)+ 结算币种由渠道能力驱动

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
wangjia
2026-07-10 14:20:12 +08:00
parent abf6a43b8c
commit 585133532c
8 changed files with 128 additions and 54 deletions
+25 -20
View File
@@ -9,33 +9,38 @@ import (
"github.com/wangjia/pay/internal/money"
)
// DBProductResolver resolves a SKU (product biz_code) against the products table.
// v1 Product.Price is a "元" string; we parse it into int64 minor units for the
// given settlement currency. 加币种维度到 product 是 P3+ 的事;P2 用单一默认币种。
type DBProductResolver struct {
db *gorm.DB
currency string
}
// DBProductResolver 按 biz_code 解析套餐,金额取给定结算币种的权威价。
// 优先查 ProductPrice(分币种 int64 价);该币种无行且币种=CNY 时回退 Product.Price(v1 元 string)。
type DBProductResolver struct{ db *gorm.DB }
func NewDBProductResolver(db *gorm.DB, currency string) *DBProductResolver {
if currency == "" {
currency = "CNY"
}
return &DBProductResolver{db: db, currency: currency}
}
func NewDBProductResolver(db *gorm.DB) *DBProductResolver { return &DBProductResolver{db: db} }
func (r *DBProductResolver) Resolve(sku string) (int64, string, string, string, error) {
func (r *DBProductResolver) Resolve(sku, currency string) (int64, string, string, error) {
var p model.Product
err := r.db.Where("biz_code = ? AND active = ?", sku, true).First(&p).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return 0, "", "", "", ErrProductNotFound
return 0, "", "", ErrProductNotFound
}
if err != nil {
return 0, "", "", "", err
return 0, "", "", err
}
minor, err := money.Parse(p.Price, r.currency)
if err != nil {
return 0, "", "", "", err
// 1) 分币种权威价
var pp model.ProductPrice
err = r.db.Where("product_id = ? AND currency = ?", p.ID, currency).First(&pp).Error
if err == nil {
return pp.AmountMinor, p.Name, p.BizCode, nil
}
return minor, r.currency, p.Name, p.BizCode, nil
if !errors.Is(err, gorm.ErrRecordNotFound) {
return 0, "", "", err
}
// 2) 回退:仅 CNY 用 v1 Product.Price(元 string)
if currency == "CNY" && p.Price != "" {
minor, perr := money.Parse(p.Price, "CNY")
if perr != nil {
return 0, "", "", perr
}
return minor, p.Name, p.BizCode, nil
}
// 该套餐不支持此结算币种
return 0, "", "", ErrProductNotFound
}