gomod引用

This commit is contained in:
2025-12-12 16:20:47 +08:00
parent 0393931e91
commit a4ba4dd715
27 changed files with 2886 additions and 87 deletions

View File

@@ -7,6 +7,7 @@ import (
"math/rand"
"time"
"github.com/gogf/gf/v2/util/gconv"
"go.mongodb.org/mongo-driver/v2/bson"
"order/consts"
"order/dao"
@@ -233,8 +234,8 @@ func (s *order) QueryOrder(ctx context.Context, req *dto.QueryOrderReq) (*dto.Qu
// convertPendingOrderToDetail 转换待支付订单为详情
func (s *order) convertPendingOrderToDetail(order *entity.OrderPending) dto.OrderDetail {
return dto.OrderDetail{
ID: order.ID.Hex(),
TenantID: order.TenantID,
ID: order.Id.Hex(),
TenantID: gconv.String(order.TenantId),
OrderNo: order.OrderNo,
UserID: order.UserID,
TotalAmount: order.TotalAmount,
@@ -271,7 +272,7 @@ func (s *order) convertPendingOrderToDetail(order *entity.OrderPending) dto.Orde
func (s *order) convertPaidOrderToDetail(order *entity.OrderPaid) dto.OrderDetail {
return dto.OrderDetail{
ID: order.ID.Hex(),
TenantID: order.TenantID,
TenantID: order.TenantId,
OrderNo: order.OrderNo,
UserID: order.UserID,
TotalAmount: order.TotalAmount,

439
service/order_statistics.go Normal file
View File

@@ -0,0 +1,439 @@
package service
import (
"context"
"fmt"
"time"
"order/dao"
"order/model/dto"
"github.com/gogf/gf/v2/frame/g"
)
// OrderStatistics 订单统计服务
type orderStatistics struct{}
// OrderStatistics 订单统计服务实例
var OrderStatistics = new(orderStatistics)
// GenerateDailyStatistics 生成日统计数据
func (s *orderStatistics) GenerateDailyStatistics(ctx context.Context, tenantID int64, date time.Time, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %s 的日统计数据", tenantID, date.Format("2006-01-02"))
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderDailyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, date)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %s 的日统计数据已存在,跳过生成", tenantID, date.Format("2006-01-02"))
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderDailyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, date)
if err != nil {
return fmt.Errorf("生成日统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderDailyStatisticsDAOInstance.Update(ctx, statistics)
if err != nil {
return fmt.Errorf("保存日统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %s 的日统计数据生成成功", tenantID, date.Format("2006-01-02"))
return nil
}
// GenerateMonthlyStatistics 生成月统计数据
func (s *orderStatistics) GenerateMonthlyStatistics(ctx context.Context, tenantID int64, year int, month int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年%d月 的月统计数据", tenantID, year, month)
// 计算月份的起止日期
startDate := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderMonthlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年%d月 的月统计数据已存在,跳过生成", tenantID, year, month)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderMonthlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year, month)
if err != nil {
return fmt.Errorf("生成月统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderMonthlyStatisticsDAOInstance.Update(ctx, statistics)
if err != nil {
return fmt.Errorf("保存月统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年%d月 的月统计数据生成成功", tenantID, year, month)
return nil
}
// GenerateQuarterlyStatistics 生成季度统计数据
func (s *orderStatistics) GenerateQuarterlyStatistics(ctx context.Context, tenantID int64, year int, quarter int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年第%d季度 的统计数据", tenantID, year, quarter)
// 计算季度的起止月份
startMonth := (quarter-1)*3 + 1
startDate := time.Date(year, time.Month(startMonth), 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderQuarterlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年第%d季度 的统计数据已存在,跳过生成", tenantID, year, quarter)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderQuarterlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year, quarter)
if err != nil {
return fmt.Errorf("生成季度统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderQuarterlyStatisticsDAOInstance.Save(ctx, statistics)
if err != nil {
return fmt.Errorf("保存季度统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年第%d季度 的统计数据生成成功", tenantID, year, quarter)
return nil
}
// GenerateYearlyStatistics 生成年统计数据
func (s *orderStatistics) GenerateYearlyStatistics(ctx context.Context, tenantID int64, year int, force bool) error {
g.Log().Infof(ctx, "开始生成租户 %d 在 %d年 的年统计数据", tenantID, year)
// 计算年的起止日期
startDate := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local)
// 检查是否已存在统计数据
if !force {
existing, err := dao.OrderYearlyStatisticsDAOInstance.GetByTenantAndDate(ctx, tenantID, startDate)
if err == nil && existing != nil {
g.Log().Infof(ctx, "租户 %d 在 %d年 的年统计数据已存在,跳过生成", tenantID, year)
return nil
}
}
// 调用DAO层生成统计数据
statistics, err := dao.OrderYearlyStatisticsDAOInstance.GenerateStatistics(ctx, tenantID, year)
if err != nil {
return fmt.Errorf("生成年统计数据失败: %v", err)
}
// 保存统计数据
err = dao.OrderYearlyStatisticsDAOInstance.Save(ctx, statistics)
if err != nil {
return fmt.Errorf("保存年统计数据失败: %v", err)
}
g.Log().Infof(ctx, "租户 %d 在 %d年 的年统计数据生成成功", tenantID, year)
return nil
}
// GetStatistics 获取统计数据
func (s *orderStatistics) GetStatistics(ctx context.Context, req *dto.GetOrderStatisticsReq) (*dto.GetOrderStatisticsRes, error) {
reportDate, err := time.Parse("2006-01-02", req.StartDate)
if err != nil {
return nil, fmt.Errorf("日期格式错误: %v", err)
}
var result *dto.OrderStatisticsDetail
// 根据统计类型调用不同的DAO
switch req.ReportType {
case "daily":
statistics, err := dao.OrderDailyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取日统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "daily",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "monthly":
statistics, err := dao.OrderMonthlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取月统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "monthly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "quarterly":
statistics, err := dao.OrderQuarterlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取季度统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "quarterly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
case "yearly":
statistics, err := dao.OrderYearlyStatisticsDAOInstance.GetByTenantAndDate(ctx, req.TenantID, reportDate)
if err != nil {
return nil, fmt.Errorf("获取年度统计数据失败: %v", err)
}
if statistics != nil {
result = &dto.OrderStatisticsDetail{
ReportType: "yearly",
ReportDate: statistics.ReportDate,
Period: statistics.Period,
TotalOrders: statistics.TotalOrders,
CompletedOrders: statistics.CompletedOrders,
CancelledOrders: statistics.CancelledOrders,
PaidOrders: statistics.PaidOrders,
TotalAmount: statistics.TotalAmount,
PaidAmount: statistics.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: statistics.NetAmount,
AverageOrderValue: statistics.AverageOrderValue,
PaymentRate: statistics.PaymentRate,
CompletionRate: statistics.CompletionRate,
UniqueUsers: statistics.UniqueUsers,
NewUsers: statistics.NewUsers,
ReturningUsers: statistics.ReturningUsers,
TotalItems: statistics.TotalItems,
UniqueAssets: statistics.UniqueAssets,
TopAssetID: statistics.TopAssetID,
TopAssetName: statistics.TopAssetName,
TopAssetCount: statistics.TopAssetCount,
CreatedAt: statistics.CreatedAt,
UpdatedAt: statistics.UpdatedAt,
}
}
default:
return nil, fmt.Errorf("不支持的统计类型: %s", req.ReportType)
}
return &dto.GetOrderStatisticsRes{
Statistics: result,
}, nil
}
// GetStatisticsList 获取统计列表
func (s *orderStatistics) GetStatisticsList(ctx context.Context, req *dto.GetOrderStatisticsListReq) (*dto.GetOrderStatisticsListRes, error) {
// 设置默认分页参数
pageNum := req.PageNum
if pageNum <= 0 {
pageNum = 1
}
pageSize := req.PageSize
if pageSize <= 0 {
pageSize = 20
}
var startDate, endDate time.Time
var err error
if req.StartDate != "" {
startDate, err = time.Parse("2006-01-02", req.StartDate)
if err != nil {
return nil, fmt.Errorf("开始日期格式错误: %v", err)
}
}
if req.EndDate != "" {
endDate, err = time.Parse("2006-01-02", req.EndDate)
if err != nil {
return nil, fmt.Errorf("结束日期格式错误: %v", err)
}
// 设置为当天的结束时间
endDate = endDate.Add(24 * time.Hour).Add(-time.Second)
}
var result []*dto.OrderStatisticsDetail
var totalCount int64
// 根据统计类型调用不同的DAO
switch req.ReportType {
case "daily":
list, count, err := dao.OrderDailyStatisticsDAOInstance.GetListByTenant(ctx, req.TenantID, startDate, endDate, pageNum, pageSize)
if err != nil {
return nil, fmt.Errorf("获取日统计列表失败: %v", err)
}
totalCount = count
for _, item := range list {
result = append(result, &dto.OrderStatisticsDetail{
ReportType: "daily",
ReportDate: item.ReportDate,
Period: item.Period,
TotalOrders: item.TotalOrders,
CompletedOrders: item.CompletedOrders,
CancelledOrders: item.CancelledOrders,
PaidOrders: item.PaidOrders,
TotalAmount: item.TotalAmount,
PaidAmount: item.PaidAmount,
RefundAmount: 0, // 需要根据实际业务添加
NetAmount: item.NetAmount,
AverageOrderValue: item.AverageOrderValue,
PaymentRate: item.PaymentRate,
CompletionRate: item.CompletionRate,
UniqueUsers: item.UniqueUsers,
NewUsers: item.NewUsers,
ReturningUsers: item.ReturningUsers,
TotalItems: item.TotalItems,
UniqueAssets: item.UniqueAssets,
TopAssetID: item.TopAssetID,
TopAssetName: item.TopAssetName,
TopAssetCount: item.TopAssetCount,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
})
}
case "monthly":
// 月度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
case "quarterly":
// 季度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
case "yearly":
// 年度统计需要添加分页查询方法到DAO中
// 暂时返回空结果
result = []*dto.OrderStatisticsDetail{}
totalCount = 0
default:
return nil, fmt.Errorf("不支持的统计类型: %s", req.ReportType)
}
return &dto.GetOrderStatisticsListRes{
List: result,
TotalCount: totalCount,
PageNum: pageNum,
PageSize: pageSize,
}, nil
}
// GenerateStatistics 生成统计数据
func (s *orderStatistics) GenerateStatistics(ctx context.Context, req *dto.GenerateOrderStatisticsReq) (*dto.GenerateOrderStatisticsRes, error) {
reportDate := time.Now()
if req.ReportDate != "" {
var err error
reportDate, err = time.Parse("2006-01-02", req.ReportDate)
if err != nil {
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: "日期格式错误请使用YYYY-MM-DD格式",
}, nil
}
}
var err error
switch req.ReportType {
case "daily":
err = s.GenerateDailyStatistics(ctx, req.TenantID, reportDate, req.Force)
case "monthly":
err = s.GenerateMonthlyStatistics(ctx, req.TenantID, reportDate.Year(), int(reportDate.Month()), req.Force)
case "quarterly":
quarter := (int(reportDate.Month())-1)/3 + 1
err = s.GenerateQuarterlyStatistics(ctx, req.TenantID, reportDate.Year(), quarter, req.Force)
case "yearly":
err = s.GenerateYearlyStatistics(ctx, req.TenantID, reportDate.Year(), req.Force)
default:
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: "不支持的统计类型",
}, nil
}
if err != nil {
return &dto.GenerateOrderStatisticsRes{
Success: false,
Message: fmt.Sprintf("生成统计数据失败: %v", err),
}, nil
}
return &dto.GenerateOrderStatisticsRes{
Success: true,
Message: "统计数据生成成功",
}, nil
}

View File

@@ -64,8 +64,8 @@ func (s *payment) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*dto.PayO
// 6. 创建支付记录
paymentRecord := &entity.PaymentRecord{
TenantID: req.TenantID,
OrderID: pendingOrder.ID,
TenantId: req.TenantID,
OrderID: pendingOrder.Id,
OrderNo: req.OrderNo,
PayMethod: req.PayMethod,
PayType: req.PayType,
@@ -184,7 +184,7 @@ func (s *payment) HandlePaymentNotify(ctx context.Context, req *dto.PaymentNotif
}
// 3. 更新支付记录状态
if err := dao.PaymentRecord.UpdateStatus(ctx, paymentRecord.ID.Hex(), req.Status, req.TransactionID, req.TradeNo); err != nil {
if err := dao.PaymentRecord.UpdateStatus(ctx, paymentRecord.Id.Hex(), req.Status, req.TransactionID, req.TradeNo); err != nil {
return fmt.Errorf("更新支付记录失败: %w", err)
}
@@ -252,8 +252,8 @@ func (s *payment) RefundOrder(ctx context.Context, req *dto.RefundOrderReq) (*dt
// 6. 创建退款记录
refundRecord := &entity.RefundRecord{
TenantID: req.TenantID,
OrderID: paidOrder.ID,
TenantId: req.TenantID,
OrderID: paidOrder.Id,
OrderNo: req.OrderNo,
RefundNo: refundResp.RefundNo,
RefundAmount: req.RefundAmount,
@@ -332,7 +332,7 @@ func (s *payment) HandleRefundNotify(ctx context.Context, req *dto.RefundNotifyR
}
// 3. 更新退款记录状态
if err := dao.RefundRecord.UpdateRefundStatus(ctx, refundRecord.ID.Hex(), req.Status, req.RefundID); err != nil {
if err := dao.RefundRecord.UpdateRefundStatus(ctx, refundRecord.Id.Hex(), req.Status, req.RefundID); err != nil {
return fmt.Errorf("更新退款记录失败: %w", err)
}

View File

@@ -5,10 +5,12 @@ import (
"errors"
"time"
"go.mongodb.org/mongo-driver/v2/bson"
"order/dao"
"order/model/dto"
"order/model/entity"
"github.com/gogf/gf/v2/util/gconv"
"go.mongodb.org/mongo-driver/v2/bson"
)
type paymentConfig struct{}
@@ -34,7 +36,7 @@ func (s *paymentConfig) CreatePaymentConfig(ctx context.Context, req *dto.Create
// 3. 创建配置实体
config := parseConfigMap(req.PayMethod, req.Config)
config.TenantID = req.TenantID
config.TenantId = req.TenantID
config.Description = req.Remark
config.Enabled = req.IsEnabled
@@ -45,8 +47,8 @@ func (s *paymentConfig) CreatePaymentConfig(ctx context.Context, req *dto.Create
// 5. 返回结果
resp := &dto.PaymentConfigResp{
ID: config.ID.Hex(),
TenantID: config.TenantID,
ID: config.Id.Hex(),
TenantID: gconv.String(config.TenantId),
PayMethod: config.PayMethod,
Config: buildConfigMap(config),
IsEnabled: config.Enabled,
@@ -80,7 +82,7 @@ func (s *paymentConfig) UpdatePaymentConfig(ctx context.Context, req *dto.Update
}
// 3. 检查是否是租户自己的配置
if config.TenantID != req.TenantID {
if config.TenantId != req.TenantID {
return nil, errors.New("无权限操作该配置")
}
@@ -99,8 +101,8 @@ func (s *paymentConfig) UpdatePaymentConfig(ctx context.Context, req *dto.Update
// 6. 返回结果
resp := &dto.PaymentConfigResp{
ID: config.ID.Hex(),
TenantID: config.TenantID,
ID: config.Id.Hex(),
TenantID: gconv.String(config.TenantId),
PayMethod: config.PayMethod,
ConfigName: config.ConfigName,
Remark: config.Description,
@@ -147,8 +149,8 @@ func (s *paymentConfig) GetPaymentConfig(ctx context.Context, req *dto.QueryPaym
// 3. 返回结果
resp := &dto.PaymentConfigResp{
ID: config.ID.Hex(),
TenantID: config.TenantID,
ID: config.Id.Hex(),
TenantID: gconv.String(config.TenantId),
PayMethod: config.PayMethod,
ConfigName: config.ConfigName,
Remark: config.Description,
@@ -178,8 +180,8 @@ func (s *paymentConfig) GetPaymentConfigList(ctx context.Context, tenantID strin
var resp []dto.PaymentConfigResp
for _, config := range configs {
resp = append(resp, dto.PaymentConfigResp{
ID: config.ID.Hex(),
TenantID: config.TenantID,
ID: config.Id.Hex(),
TenantID: gconv.String(config.TenantId),
PayMethod: config.PayMethod,
ConfigName: config.ConfigName,
Remark: config.Description,
@@ -215,7 +217,7 @@ func (s *paymentConfig) DeletePaymentConfig(ctx context.Context, tenantID, confi
}
// 3. 检查是否是租户自己的配置
if config.TenantID != tenantID {
if config.TenantId != tenantID {
return errors.New("无权限操作该配置")
}
@@ -255,7 +257,7 @@ func (s *paymentConfig) updateConfigStatus(ctx context.Context, tenantID, config
}
// 3. 检查是否是租户自己的配置
if config.TenantID != tenantID {
if config.TenantId != tenantID {
return errors.New("无权限操作该配置")
}