@@ -2,6 +2,7 @@ package product
import (
"context"
"fmt"
"github.com/shopspring/decimal"
"go.uber.org/zap"
@@ -45,6 +46,22 @@ func (s *SubscriptionApplicationServiceImpl) UpdateSubscriptionPrice(ctx context
// BatchUpdateSubscriptionPrices 一键改价
// 业务流程: 1. 获取用户所有订阅 2. 根据范围筛选 3. 批量更新价格
func ( s * SubscriptionApplicationServiceImpl ) BatchUpdateSubscriptionPrices ( ctx context . Context , cmd * commands . BatchUpdateSubscriptionPricesCommand ) error {
// 记录请求参数
s . logger . Info ( "开始批量更新订阅价格" ,
zap . String ( "user_id" , cmd . UserID ) ,
zap . String ( "adjustment_type" , cmd . AdjustmentType ) ,
zap . Float64 ( "discount" , cmd . Discount ) ,
zap . Float64 ( "cost_multiple" , cmd . CostMultiple ) ,
zap . String ( "scope" , cmd . Scope ) )
// 验证调整方式对应的参数
if cmd . AdjustmentType == "discount" && cmd . Discount <= 0 {
return fmt . Errorf ( "按售价折扣调整时, 折扣比例必须大于0" )
}
if cmd . AdjustmentType == "cost_multiple" && cmd . CostMultiple <= 0 {
return fmt . Errorf ( "按成本价倍数调整时, 倍数必须大于0" )
}
subscriptions , _ , err := s . productSubscriptionService . ListSubscriptions ( ctx , & repoQueries . ListSubscriptionsQuery {
UserID : cmd . UserID ,
Page : 1 ,
@@ -54,6 +71,9 @@ func (s *SubscriptionApplicationServiceImpl) BatchUpdateSubscriptionPrices(ctx c
return err
}
s . logger . Info ( "获取到订阅列表" ,
zap . Int ( "total_subscriptions" , len ( subscriptions ) ) )
// 根据范围筛选订阅
var targetSubscriptions [ ] * entities . Subscription
for _ , sub := range subscriptions {
@@ -69,24 +89,64 @@ func (s *SubscriptionApplicationServiceImpl) BatchUpdateSubscriptionPrices(ctx c
}
// 批量更新价格
updatedCount := 0
skippedCount := 0
for _ , sub := range targetSubscriptions {
if sub . Product ! = nil {
// 计算折扣后的价格
dis cou ntRatio := cmd . Discount / 10
newPrice := sub . Product . Price . Mul ( decimal . NewFromFloat ( discountRatio ) )
// 四舍五入到2位小数
newPrice = newPrice . Round ( 2 )
if sub . Product = = nil {
skippedCount ++
continue
}
err := s . productSubscriptionService . UpdateSubscriptionPrice ( ctx , sub . ID , newPrice . InexactFloat64 ( ) )
if err != nil {
s . logger . Error ( "批量更新订阅价格失败" ,
var newPrice decimal . Decimal
if cmd . AdjustmentType == "discount" {
// 按售价折扣调整
discountRatio := cmd . Discount / 10
newPrice = sub . Product . Price . Mul ( decimal . NewFromFloat ( discountRatio ) )
} else if cmd . AdjustmentType == "cost_multiple" {
// 按成本价倍数调整
// 检查成本价是否有效( 必须大于0)
// 使用严格检查: 成本价必须大于0
if ! sub . Product . CostPrice . GreaterThan ( decimal . Zero ) {
// 跳过没有成本价或成本价为0的产品
skippedCount ++
s . logger . Info ( "跳过未设置成本价或成本价为0的订阅" ,
zap . String ( "subscription_id" , sub . ID ) ,
zap . Error ( err ) )
// 继续处理其他订阅,不中断整个流程
zap . String ( "product_id" , sub . ProductID ) ,
zap . String ( "product_name" , sub . Product . Name ) ,
zap . String ( "cost_price" , sub . Product . CostPrice . String ( ) ) )
continue
}
// 计算成本价倍数后的价格
newPrice = sub . Product . CostPrice . Mul ( decimal . NewFromFloat ( cmd . CostMultiple ) )
} else {
s . logger . Warn ( "未知的调整方式" ,
zap . String ( "adjustment_type" , cmd . AdjustmentType ) ,
zap . String ( "subscription_id" , sub . ID ) )
skippedCount ++
continue
}
// 四舍五入到2位小数
newPrice = newPrice . Round ( 2 )
err := s . productSubscriptionService . UpdateSubscriptionPrice ( ctx , sub . ID , newPrice . InexactFloat64 ( ) )
if err != nil {
s . logger . Error ( "批量更新订阅价格失败" ,
zap . String ( "subscription_id" , sub . ID ) ,
zap . Error ( err ) )
skippedCount ++
// 继续处理其他订阅,不中断整个流程
} else {
updatedCount ++
}
}
s . logger . Info ( "批量更新订阅价格完成" ,
zap . Int ( "total" , len ( targetSubscriptions ) ) ,
zap . Int ( "updated" , updatedCount ) ,
zap . Int ( "skipped" , skippedCount ) )
return nil
}
@@ -129,7 +189,7 @@ func (s *SubscriptionApplicationServiceImpl) ListSubscriptions(ctx context.Conte
}
items := make ( [ ] responses . SubscriptionInfoResponse , len ( subscriptions ) )
for i := range subscriptions {
resp := s . convertToSubscriptionInfoResponse ( subscriptions [ i ] )
resp := s . convertToSubscriptionInfoResponseForAdmin ( subscriptions [ i ] )
if resp != nil {
items [ i ] = * resp // 解引用指针
}
@@ -300,6 +360,65 @@ func (s *SubscriptionApplicationServiceImpl) convertToProductSimpleResponse(prod
}
}
// convertToSubscriptionInfoResponseForAdmin 转换为订阅信息响应(管理员端,包含成本价)
func ( s * SubscriptionApplicationServiceImpl ) convertToSubscriptionInfoResponseForAdmin ( subscription * entities . Subscription ) * responses . SubscriptionInfoResponse {
// 查询用户信息
var userInfo * responses . UserSimpleResponse
if subscription . UserID != "" {
user , err := s . userRepo . GetByIDWithEnterpriseInfo ( context . Background ( ) , subscription . UserID )
if err == nil {
companyName := "未知公司"
if user . EnterpriseInfo != nil {
companyName = user . EnterpriseInfo . CompanyName
}
userInfo = & responses . UserSimpleResponse {
ID : user . ID ,
CompanyName : companyName ,
Phone : user . Phone ,
}
}
}
var productAdminResponse * responses . ProductSimpleAdminResponse
if subscription . Product != nil {
productAdminResponse = s . convertToProductSimpleAdminResponse ( subscription . Product )
}
return & responses . SubscriptionInfoResponse {
ID : subscription . ID ,
UserID : subscription . UserID ,
ProductID : subscription . ProductID ,
Price : subscription . Price . InexactFloat64 ( ) ,
User : userInfo ,
ProductAdmin : productAdminResponse ,
APIUsed : subscription . APIUsed ,
CreatedAt : subscription . CreatedAt ,
UpdatedAt : subscription . UpdatedAt ,
}
}
// convertToProductSimpleAdminResponse 转换为管理员产品简单信息响应(包含成本价)
func ( s * SubscriptionApplicationServiceImpl ) convertToProductSimpleAdminResponse ( product * entities . Product ) * responses . ProductSimpleAdminResponse {
var categoryResponse * responses . CategorySimpleResponse
if product . Category != nil {
categoryResponse = s . convertToCategorySimpleResponse ( product . Category )
}
return & responses . ProductSimpleAdminResponse {
ProductSimpleResponse : responses . ProductSimpleResponse {
ID : product . ID ,
OldID : product . OldID ,
Name : product . Name ,
Code : product . Code ,
Description : product . Description ,
Price : product . Price . InexactFloat64 ( ) ,
Category : categoryResponse ,
IsPackage : product . IsPackage ,
} ,
CostPrice : product . CostPrice . InexactFloat64 ( ) ,
}
}
// convertToCategorySimpleResponse 转换为分类简单信息响应
func ( s * SubscriptionApplicationServiceImpl ) convertToCategorySimpleResponse ( category * entities . ProductCategory ) * responses . CategorySimpleResponse {
if category == nil {