new
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
finance_services "tyapi-server/internal/domains/finance/services"
|
||||
user_repositories "tyapi-server/internal/domains/user/repositories"
|
||||
"tyapi-server/internal/shared/database"
|
||||
"tyapi-server/internal/shared/export"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
"tyapi-server/internal/shared/payment"
|
||||
|
||||
@@ -30,6 +31,7 @@ type FinanceApplicationServiceImpl struct {
|
||||
alipayOrderRepo finance_repositories.AlipayOrderRepository
|
||||
userRepo user_repositories.UserRepository
|
||||
txManager *database.TransactionManager
|
||||
exportManager *export.ExportManager
|
||||
logger *zap.Logger
|
||||
config *config.Config
|
||||
}
|
||||
@@ -45,6 +47,7 @@ func NewFinanceApplicationService(
|
||||
txManager *database.TransactionManager,
|
||||
logger *zap.Logger,
|
||||
config *config.Config,
|
||||
exportManager *export.ExportManager,
|
||||
) FinanceApplicationService {
|
||||
return &FinanceApplicationServiceImpl{
|
||||
aliPayClient: aliPayClient,
|
||||
@@ -54,6 +57,7 @@ func NewFinanceApplicationService(
|
||||
alipayOrderRepo: alipayOrderRepo,
|
||||
userRepo: userRepo,
|
||||
txManager: txManager,
|
||||
exportManager: exportManager,
|
||||
logger: logger,
|
||||
config: config,
|
||||
}
|
||||
@@ -344,6 +348,290 @@ func (s *FinanceApplicationServiceImpl) GetAdminWalletTransactions(ctx context.C
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportAdminWalletTransactions 导出管理端钱包交易记录
|
||||
func (s *FinanceApplicationServiceImpl) ExportAdminWalletTransactions(ctx context.Context, filters map[string]interface{}, format string) ([]byte, error) {
|
||||
const batchSize = 1000 // 每批处理1000条记录
|
||||
var allTransactions []*finance_entities.WalletTransaction
|
||||
var productNameMap map[string]string
|
||||
|
||||
// 分批获取数据
|
||||
page := 1
|
||||
for {
|
||||
// 查询当前批次的数据
|
||||
batchProductNameMap, transactions, _, err := s.walletTransactionRepository.ListWithFiltersAndProductName(ctx, filters, interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: batchSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("查询导出钱包交易记录失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 合并产品名称映射
|
||||
if productNameMap == nil {
|
||||
productNameMap = batchProductNameMap
|
||||
} else {
|
||||
for k, v := range batchProductNameMap {
|
||||
productNameMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到总数据中
|
||||
allTransactions = append(allTransactions, transactions...)
|
||||
|
||||
// 如果当前批次数据少于批次大小,说明已经是最后一批
|
||||
if len(transactions) < batchSize {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
// 检查是否有数据
|
||||
if len(allTransactions) == 0 {
|
||||
return nil, fmt.Errorf("没有找到符合条件的数据")
|
||||
}
|
||||
|
||||
// 批量获取企业名称映射,避免N+1查询问题
|
||||
companyNameMap, err := s.batchGetCompanyNames(ctx, allTransactions)
|
||||
if err != nil {
|
||||
companyNameMap = make(map[string]string)
|
||||
}
|
||||
|
||||
// 准备导出数据
|
||||
headers := []string{"交易ID", "企业名称", "产品名称", "消费金额", "消费时间"}
|
||||
columnWidths := []float64{20, 25, 20, 15, 20}
|
||||
|
||||
data := make([][]interface{}, len(allTransactions))
|
||||
for i, transaction := range allTransactions {
|
||||
companyName := companyNameMap[transaction.UserID]
|
||||
if companyName == "" {
|
||||
companyName = "未知企业"
|
||||
}
|
||||
|
||||
productName := productNameMap[transaction.ProductID]
|
||||
if productName == "" {
|
||||
productName = "未知产品"
|
||||
}
|
||||
|
||||
data[i] = []interface{}{
|
||||
transaction.TransactionID,
|
||||
companyName,
|
||||
productName,
|
||||
transaction.Amount.String(),
|
||||
transaction.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// 创建导出配置
|
||||
config := &export.ExportConfig{
|
||||
SheetName: "消费记录",
|
||||
Headers: headers,
|
||||
Data: data,
|
||||
ColumnWidths: columnWidths,
|
||||
}
|
||||
|
||||
// 使用导出管理器生成文件
|
||||
return s.exportManager.Export(ctx, config, format)
|
||||
}
|
||||
|
||||
// batchGetCompanyNames 批量获取企业名称映射
|
||||
func (s *FinanceApplicationServiceImpl) batchGetCompanyNames(ctx context.Context, transactions []*finance_entities.WalletTransaction) (map[string]string, error) {
|
||||
// 收集所有唯一的用户ID
|
||||
userIDSet := make(map[string]bool)
|
||||
for _, transaction := range transactions {
|
||||
userIDSet[transaction.UserID] = true
|
||||
}
|
||||
|
||||
// 转换为切片
|
||||
userIDs := make([]string, 0, len(userIDSet))
|
||||
for userID := range userIDSet {
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
|
||||
// 批量查询用户信息
|
||||
users, err := s.userRepo.BatchGetByIDsWithEnterpriseInfo(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建企业名称映射
|
||||
companyNameMap := make(map[string]string)
|
||||
for _, user := range users {
|
||||
companyName := "未知企业"
|
||||
if user.EnterpriseInfo != nil {
|
||||
companyName = user.EnterpriseInfo.CompanyName
|
||||
}
|
||||
companyNameMap[user.ID] = companyName
|
||||
}
|
||||
|
||||
return companyNameMap, nil
|
||||
}
|
||||
|
||||
// ExportAdminRechargeRecords 导出管理端充值记录
|
||||
func (s *FinanceApplicationServiceImpl) ExportAdminRechargeRecords(ctx context.Context, filters map[string]interface{}, format string) ([]byte, error) {
|
||||
const batchSize = 1000 // 每批处理1000条记录
|
||||
var allRecords []finance_entities.RechargeRecord
|
||||
|
||||
// 分批获取数据
|
||||
page := 1
|
||||
for {
|
||||
// 查询当前批次的数据
|
||||
records, err := s.rechargeRecordService.GetAll(ctx, filters, interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: batchSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("查询导出充值记录失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 添加到总数据中
|
||||
allRecords = append(allRecords, records...)
|
||||
|
||||
// 如果当前批次数据少于批次大小,说明已经是最后一批
|
||||
if len(records) < batchSize {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
// 批量获取企业名称映射,避免N+1查询问题
|
||||
companyNameMap, err := s.batchGetCompanyNamesForRechargeRecords(ctx, convertToRechargeRecordPointers(allRecords))
|
||||
if err != nil {
|
||||
s.logger.Warn("批量获取企业名称失败,使用默认值", zap.Error(err))
|
||||
companyNameMap = make(map[string]string)
|
||||
}
|
||||
|
||||
// 准备导出数据
|
||||
headers := []string{"企业名称", "充值金额", "充值类型", "状态", "支付宝订单号", "转账订单号", "备注", "充值时间"}
|
||||
columnWidths := []float64{25, 15, 15, 10, 20, 20, 20, 20}
|
||||
|
||||
data := make([][]interface{}, len(allRecords))
|
||||
for i, record := range allRecords {
|
||||
// 从映射中获取企业名称
|
||||
companyName := companyNameMap[record.UserID]
|
||||
if companyName == "" {
|
||||
companyName = "未知企业"
|
||||
}
|
||||
|
||||
// 获取订单号
|
||||
alipayOrderID := ""
|
||||
if record.AlipayOrderID != nil && *record.AlipayOrderID != "" {
|
||||
alipayOrderID = *record.AlipayOrderID
|
||||
}
|
||||
transferOrderID := ""
|
||||
if record.TransferOrderID != nil && *record.TransferOrderID != "" {
|
||||
transferOrderID = *record.TransferOrderID
|
||||
}
|
||||
|
||||
// 获取备注
|
||||
notes := ""
|
||||
if record.Notes != "" {
|
||||
notes = record.Notes
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
createdAt := record.CreatedAt.Format("2006-01-02 15:04:05")
|
||||
|
||||
data[i] = []interface{}{
|
||||
companyName,
|
||||
record.Amount.String(),
|
||||
translateRechargeType(record.RechargeType),
|
||||
translateRechargeStatus(record.Status),
|
||||
alipayOrderID,
|
||||
transferOrderID,
|
||||
notes,
|
||||
createdAt,
|
||||
}
|
||||
}
|
||||
|
||||
// 创建导出配置
|
||||
config := &export.ExportConfig{
|
||||
SheetName: "充值记录",
|
||||
Headers: headers,
|
||||
Data: data,
|
||||
ColumnWidths: columnWidths,
|
||||
}
|
||||
|
||||
// 使用导出管理器生成文件
|
||||
return s.exportManager.Export(ctx, config, format)
|
||||
}
|
||||
|
||||
// translateRechargeType 翻译充值类型为中文
|
||||
func translateRechargeType(rechargeType finance_entities.RechargeType) string {
|
||||
switch rechargeType {
|
||||
case finance_entities.RechargeTypeAlipay:
|
||||
return "支付宝充值"
|
||||
case finance_entities.RechargeTypeTransfer:
|
||||
return "对公转账"
|
||||
case finance_entities.RechargeTypeGift:
|
||||
return "赠送"
|
||||
default:
|
||||
return "未知类型"
|
||||
}
|
||||
}
|
||||
|
||||
// translateRechargeStatus 翻译充值状态为中文
|
||||
func translateRechargeStatus(status finance_entities.RechargeStatus) string {
|
||||
switch status {
|
||||
case finance_entities.RechargeStatusPending:
|
||||
return "待处理"
|
||||
case finance_entities.RechargeStatusSuccess:
|
||||
return "成功"
|
||||
case finance_entities.RechargeStatusFailed:
|
||||
return "失败"
|
||||
case finance_entities.RechargeStatusCancelled:
|
||||
return "已取消"
|
||||
default:
|
||||
return "未知状态"
|
||||
}
|
||||
}
|
||||
|
||||
// convertToRechargeRecordPointers 将RechargeRecord切片转换为指针切片
|
||||
func convertToRechargeRecordPointers(records []finance_entities.RechargeRecord) []*finance_entities.RechargeRecord {
|
||||
pointers := make([]*finance_entities.RechargeRecord, len(records))
|
||||
for i := range records {
|
||||
pointers[i] = &records[i]
|
||||
}
|
||||
return pointers
|
||||
}
|
||||
|
||||
// batchGetCompanyNamesForRechargeRecords 批量获取企业名称映射(用于充值记录)
|
||||
func (s *FinanceApplicationServiceImpl) batchGetCompanyNamesForRechargeRecords(ctx context.Context, records []*finance_entities.RechargeRecord) (map[string]string, error) {
|
||||
// 收集所有唯一的用户ID
|
||||
userIDSet := make(map[string]bool)
|
||||
for _, record := range records {
|
||||
userIDSet[record.UserID] = true
|
||||
}
|
||||
|
||||
// 转换为切片
|
||||
userIDs := make([]string, 0, len(userIDSet))
|
||||
for userID := range userIDSet {
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
|
||||
// 批量查询用户信息
|
||||
users, err := s.userRepo.BatchGetByIDsWithEnterpriseInfo(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建企业名称映射
|
||||
companyNameMap := make(map[string]string)
|
||||
for _, user := range users {
|
||||
companyName := "未知企业"
|
||||
if user.EnterpriseInfo != nil {
|
||||
companyName = user.EnterpriseInfo.CompanyName
|
||||
}
|
||||
companyNameMap[user.ID] = companyName
|
||||
}
|
||||
|
||||
return companyNameMap, nil
|
||||
}
|
||||
|
||||
// HandleAlipayCallback 处理支付宝回调
|
||||
func (s *FinanceApplicationServiceImpl) HandleAlipayCallback(ctx context.Context, r *http.Request) error {
|
||||
@@ -402,7 +690,7 @@ func (s *FinanceApplicationServiceImpl) processAlipayPaymentSuccess(ctx context.
|
||||
// 该服务内部会处理所有必要的检查、事务和更新操作
|
||||
err = s.rechargeRecordService.HandleAlipayPaymentSuccess(ctx, outTradeNo, amount, tradeNo)
|
||||
if err != nil {
|
||||
s.logger.Error("处理支付宝支付成功失败",
|
||||
s.logger.Error("处理支付宝支付成功失败",
|
||||
zap.String("out_trade_no", outTradeNo),
|
||||
zap.Error(err),
|
||||
)
|
||||
@@ -665,14 +953,14 @@ func (s *FinanceApplicationServiceImpl) GetAdminRechargeRecords(ctx context.Cont
|
||||
var items []responses.RechargeRecordResponse
|
||||
for _, record := range records {
|
||||
item := responses.RechargeRecordResponse{
|
||||
ID: record.ID,
|
||||
UserID: record.UserID,
|
||||
Amount: record.Amount,
|
||||
RechargeType: string(record.RechargeType),
|
||||
Status: string(record.Status),
|
||||
Notes: record.Notes,
|
||||
CreatedAt: record.CreatedAt,
|
||||
UpdatedAt: record.UpdatedAt,
|
||||
ID: record.ID,
|
||||
UserID: record.UserID,
|
||||
Amount: record.Amount,
|
||||
RechargeType: string(record.RechargeType),
|
||||
Status: string(record.Status),
|
||||
Notes: record.Notes,
|
||||
CreatedAt: record.CreatedAt,
|
||||
UpdatedAt: record.UpdatedAt,
|
||||
}
|
||||
|
||||
// 根据充值类型设置相应的订单号
|
||||
@@ -719,8 +1007,8 @@ func (s *FinanceApplicationServiceImpl) GetRechargeConfig(ctx context.Context) (
|
||||
})
|
||||
}
|
||||
return &responses.RechargeConfigResponse{
|
||||
MinAmount: s.config.Wallet.MinAmount,
|
||||
MaxAmount: s.config.Wallet.MaxAmount,
|
||||
MinAmount: s.config.Wallet.MinAmount,
|
||||
MaxAmount: s.config.Wallet.MaxAmount,
|
||||
AlipayRechargeBonus: bonus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user