feat: 新增多密码验证支持及架构文档
Build docker and publish / build (20.15.1) (push) Has been cancelled

refactor: 重构用户模型和密码验证逻辑
feat(epay): 添加支付类型支持
docs: 添加安装和配置指南文档
fix: 修复优惠券过期检查逻辑
perf: 优化设备解绑缓存清理流程
test: 添加密码验证测试用例
chore: 更新依赖版本
This commit is contained in:
2025-10-27 18:54:07 -07:00
parent fde3210a88
commit 00255a7118
65 changed files with 1523 additions and 504 deletions
@@ -29,6 +29,43 @@ func NewGetSubscriptionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G
}
}
func (l *GetSubscriptionLogic) GetSubscription1(req *types.GetSubscriptionRequest) (resp *types.GetSubscriptionResponse, err error) {
resp = &types.GetSubscriptionResponse{
List: make([]types.Subscribe, 0),
}
// Get the subscription list
_, data, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{
Page: 1,
Size: 9999,
Show: true,
Language: req.Language,
DefaultLanguage: true,
})
if err != nil {
l.Errorw("[Site GetSubscription]", logger.Field("err", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscription list error: %v", err.Error())
}
list := make([]types.Subscribe, len(data))
for i, item := range data {
var sub types.Subscribe
tool.DeepCopy(&sub, item)
if item.Discount != "" {
var discount []types.SubscribeDiscount
_ = json.Unmarshal([]byte(item.Discount), &discount)
sub.Discount = discount
list[i] = sub
}
list[i] = sub
}
resp.List = list
return
}
// CountNodesByIdsAndTags 根据节点ID和标签计算启用的节点数量
func (l *GetSubscriptionLogic) CountNodesByIdsAndTags(ctx context.Context, nodeIds []int64, tags []string) (int64, error) {
return l.svcCtx.NodeModel.CountNodesByIdsAndTags(ctx, nodeIds, tags)
}
func (l *GetSubscriptionLogic) GetSubscription(req *types.GetSubscriptionRequest) (resp *types.GetSubscriptionResponse, err error) {
resp = &types.GetSubscriptionResponse{
List: make([]types.Subscribe, 0),
@@ -54,7 +91,7 @@ func (l *GetSubscriptionLogic) GetSubscription(req *types.GetSubscriptionRequest
_ = json.Unmarshal([]byte(item.Discount), &discount)
sub.Discount = discount
}
// 计算节点数量
nodeIds := tool.StringToInt64Slice(item.Nodes)
var nodeTags []string
@@ -66,7 +103,7 @@ func (l *GetSubscriptionLogic) GetSubscription(req *types.GetSubscriptionRequest
}
}
}
nodeCount, err := l.svcCtx.NodeModel.CountNodesByIdsAndTags(l.ctx, nodeIds, nodeTags)
if err != nil {
l.Logger.Error("[GetSubscription] count nodes failed: ", logger.Field("error", err.Error()))
@@ -74,7 +111,7 @@ func (l *GetSubscriptionLogic) GetSubscription(req *types.GetSubscriptionRequest
} else {
sub.NodeCount = nodeCount
}
list[i] = sub
}
resp.List = list
@@ -267,7 +267,7 @@ func (l *PurchaseCheckoutLogic) epayPayment(config *payment.Payment, info *order
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error())
}
// Initialize EPay client with merchant credentials
client := epay.NewClient(epayConfig.Pid, epayConfig.Url, epayConfig.Key)
client := epay.NewClient(epayConfig.Pid, epayConfig.Url, epayConfig.Key, epayConfig.Type)
// Convert order amount to CNY using current exchange rate
amount, err := l.queryExchangeRate("CNY", info.Amount)
@@ -309,7 +309,7 @@ func (l *PurchaseCheckoutLogic) CryptoSaaSPayment(config *payment.Payment, info
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error())
}
// Initialize EPay client with merchant credentials
client := epay.NewClient(epayConfig.AccountID, epayConfig.Endpoint, epayConfig.SecretKey)
client := epay.NewClient(epayConfig.AccountID, epayConfig.Endpoint, epayConfig.SecretKey, epayConfig.Type)
// Convert order amount to CNY using current exchange rate
amount, err := l.queryExchangeRate("CNY", info.Amount)
@@ -347,6 +347,11 @@ func (l *PurchaseCheckoutLogic) queryExchangeRate(to string, src int64) (amount
// Convert cents to decimal amount
amount = float64(src) / float64(100)
if l.svcCtx.ExchangeRate != 0 && to == "CNY" {
amount = amount * l.svcCtx.ExchangeRate
return amount, nil
}
// Retrieve system currency configuration
currency, err := l.svcCtx.SystemModel.GetCurrencyConfig(l.ctx)
if err != nil {
@@ -83,6 +83,12 @@ func (l *PurchaseLogic) Purchase(req *types.PortalPurchaseRequest) (resp *types.
if couponInfo.Count != 0 && couponInfo.Count <= couponInfo.UsedCount {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon used")
}
// Check expiration time
expireTime := time.Unix(couponInfo.ExpireTime, 0)
if time.Now().After(expireTime) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponExpired), "coupon expired")
}
couponSub := tool.StringToInt64Slice(couponInfo.Subscribe)
if len(couponSub) > 0 && !tool.Contains(couponSub, req.SubscribeId) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponNotApplicable), "coupon not match")
+2 -2
View File
@@ -7,14 +7,14 @@ import (
)
func getDiscount(discounts []types.SubscribeDiscount, inputMonths int64) float64 {
var finalDiscount float64 = 1.0
var finalDiscount int64 = 100
for _, discount := range discounts {
if inputMonths >= discount.Quantity && discount.Discount < finalDiscount {
finalDiscount = discount.Discount
}
}
return finalDiscount
return float64(finalDiscount) / float64(100)
}
func calculateCoupon(amount int64, couponInfo *coupon.Coupon) int64 {