f
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
domain_finance_repo "hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
AlipayOrdersTable = "typay_orders"
|
||||
)
|
||||
|
||||
type GormAlipayOrderRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ domain_finance_repo.AlipayOrderRepository = (*GormAlipayOrderRepository)(nil)
|
||||
|
||||
func NewGormAlipayOrderRepository(db *gorm.DB, logger *zap.Logger) domain_finance_repo.AlipayOrderRepository {
|
||||
return &GormAlipayOrderRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, AlipayOrdersTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) Create(ctx context.Context, order entities.AlipayOrder) (entities.AlipayOrder, error) {
|
||||
err := r.CreateEntity(ctx, &order)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) GetByID(ctx context.Context, id string) (entities.AlipayOrder, error) {
|
||||
var order entities.AlipayOrder
|
||||
err := r.SmartGetByID(ctx, id, &order)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.AlipayOrder{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.AlipayOrder{}, err
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) GetByOutTradeNo(ctx context.Context, outTradeNo string) (*entities.AlipayOrder, error) {
|
||||
var order entities.AlipayOrder
|
||||
err := r.GetDB(ctx).Where("out_trade_no = ?", outTradeNo).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) GetByRechargeID(ctx context.Context, rechargeID string) (*entities.AlipayOrder, error) {
|
||||
var order entities.AlipayOrder
|
||||
err := r.GetDB(ctx).Where("recharge_id = ?", rechargeID).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) GetByUserID(ctx context.Context, userID string) ([]entities.AlipayOrder, error) {
|
||||
var orders []entities.AlipayOrder
|
||||
err := r.GetDB(ctx).
|
||||
Joins("JOIN recharge_records ON typay_orders.recharge_id = recharge_records.id").
|
||||
Where("recharge_records.user_id = ?", userID).
|
||||
Order("typay_orders.created_at DESC").
|
||||
Find(&orders).Error
|
||||
return orders, err
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) Update(ctx context.Context, order entities.AlipayOrder) error {
|
||||
return r.UpdateEntity(ctx, &order)
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) UpdateStatus(ctx context.Context, id string, status entities.AlipayOrderStatus) error {
|
||||
return r.GetDB(ctx).Model(&entities.AlipayOrder{}).Where("id = ?", id).Update("status", status).Error
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.GetDB(ctx).Delete(&entities.AlipayOrder{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
func (r *GormAlipayOrderRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.AlipayOrder{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
"hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
"hyapi-server/internal/shared/interfaces"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
PurchaseOrdersTable = "ty_purchase_orders"
|
||||
)
|
||||
|
||||
type GormPurchaseOrderRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ repositories.PurchaseOrderRepository = (*GormPurchaseOrderRepository)(nil)
|
||||
|
||||
func NewGormPurchaseOrderRepository(db *gorm.DB, logger *zap.Logger) repositories.PurchaseOrderRepository {
|
||||
return &GormPurchaseOrderRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, PurchaseOrdersTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) Create(ctx context.Context, order *entities.PurchaseOrder) (*entities.PurchaseOrder, error) {
|
||||
err := r.CreateEntity(ctx, order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) Update(ctx context.Context, order *entities.PurchaseOrder) error {
|
||||
return r.UpdateEntity(ctx, order)
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByID(ctx context.Context, id string) (*entities.PurchaseOrder, error) {
|
||||
var order entities.PurchaseOrder
|
||||
err := r.SmartGetByID(ctx, id, &order)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByOrderNo(ctx context.Context, orderNo string) (*entities.PurchaseOrder, error) {
|
||||
var order entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).Where("order_no = ?", orderNo).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByUserID(ctx context.Context, userID string, limit, offset int) ([]*entities.PurchaseOrder, int64, error) {
|
||||
var orders []entities.PurchaseOrder
|
||||
var count int64
|
||||
|
||||
db := r.GetDB(ctx).Where("user_id = ?", userID)
|
||||
|
||||
// 获取总数
|
||||
err := db.Model(&entities.PurchaseOrder{}).Count(&count).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
err = db.Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&orders).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*entities.PurchaseOrder, len(orders))
|
||||
for i := range orders {
|
||||
result[i] = &orders[i]
|
||||
}
|
||||
|
||||
return result, count, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByUserIDAndProductID(ctx context.Context, userID, productID string) (*entities.PurchaseOrder, error) {
|
||||
var order entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).
|
||||
Where("user_id = ? AND product_id = ? AND status = ?", userID, productID, entities.PurchaseOrderStatusPaid).
|
||||
First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByPaymentTypeAndTransactionID(ctx context.Context, paymentType, transactionID string) (*entities.PurchaseOrder, error) {
|
||||
var order entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).
|
||||
Where("payment_type = ? AND trade_no = ?", paymentType, transactionID).
|
||||
First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByTradeNo(ctx context.Context, tradeNo string) (*entities.PurchaseOrder, error) {
|
||||
var order entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).Where("trade_no = ?", tradeNo).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) UpdatePaymentStatus(ctx context.Context, orderID string, status entities.PurchaseOrderStatus, tradeNo *string, payAmount, receiptAmount *string, paymentTime *time.Time) error {
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
}
|
||||
|
||||
if tradeNo != nil {
|
||||
updates["trade_no"] = *tradeNo
|
||||
}
|
||||
|
||||
if payAmount != nil {
|
||||
updates["pay_amount"] = *payAmount
|
||||
}
|
||||
|
||||
if receiptAmount != nil {
|
||||
updates["receipt_amount"] = *receiptAmount
|
||||
}
|
||||
|
||||
if paymentTime != nil {
|
||||
updates["pay_time"] = *paymentTime
|
||||
updates["notify_time"] = *paymentTime
|
||||
}
|
||||
|
||||
err := r.GetDB(ctx).
|
||||
Model(&entities.PurchaseOrder{}).
|
||||
Where("id = ?", orderID).
|
||||
Updates(updates).Error
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetUserPurchasedProductCodes(ctx context.Context, userID string) ([]string, error) {
|
||||
var orders []entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).
|
||||
Select("product_code").
|
||||
Where("user_id = ? AND status = ?", userID, entities.PurchaseOrderStatusPaid).
|
||||
Find(&orders).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
codesMap := make(map[string]bool)
|
||||
for _, order := range orders {
|
||||
// 添加主产品编号
|
||||
if order.ProductCode != "" {
|
||||
codesMap[order.ProductCode] = true
|
||||
}
|
||||
}
|
||||
|
||||
codes := make([]string, 0, len(codesMap))
|
||||
for code := range codesMap {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
return codes, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetUserPaidProductIDs(ctx context.Context, userID string) ([]string, error) {
|
||||
var orders []entities.PurchaseOrder
|
||||
err := r.GetDB(ctx).
|
||||
Select("product_id").
|
||||
Where("user_id = ? AND status = ?", userID, entities.PurchaseOrderStatusPaid).
|
||||
Find(&orders).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idsMap := make(map[string]bool)
|
||||
for _, order := range orders {
|
||||
// 添加主产品ID
|
||||
if order.ProductID != "" {
|
||||
idsMap[order.ProductID] = true
|
||||
}
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(idsMap))
|
||||
for id := range idsMap {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) HasUserPurchased(ctx context.Context, userID string, productCode string) (bool, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.PurchaseOrder{}).
|
||||
Where("user_id = ? AND product_code = ? AND status = ?", userID, productCode, entities.PurchaseOrderStatusPaid).
|
||||
Count(&count).Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetExpiringOrders(ctx context.Context, before time.Time, limit int) ([]*entities.PurchaseOrder, error) {
|
||||
// 购买订单实体没有过期时间字段,此方法返回空结果
|
||||
return []*entities.PurchaseOrder{}, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetExpiredOrders(ctx context.Context, limit int) ([]*entities.PurchaseOrder, error) {
|
||||
// 购买订单实体没有过期时间字段,此方法返回空结果
|
||||
return []*entities.PurchaseOrder{}, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByStatus(ctx context.Context, status entities.PurchaseOrderStatus, limit, offset int) ([]*entities.PurchaseOrder, int64, error) {
|
||||
var orders []entities.PurchaseOrder
|
||||
var count int64
|
||||
|
||||
db := r.GetDB(ctx).Where("status = ?", status)
|
||||
|
||||
// 获取总数
|
||||
err := db.Model(&entities.PurchaseOrder{}).Count(&count).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
err = db.Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&orders).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*entities.PurchaseOrder, len(orders))
|
||||
for i := range orders {
|
||||
result[i] = &orders[i]
|
||||
}
|
||||
|
||||
return result, count, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) GetByFilters(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) ([]*entities.PurchaseOrder, error) {
|
||||
var orders []entities.PurchaseOrder
|
||||
|
||||
db := r.GetDB(ctx)
|
||||
|
||||
// 应用筛选条件
|
||||
if filters != nil {
|
||||
if userID, ok := filters["user_id"]; ok {
|
||||
db = db.Where("user_id = ?", userID)
|
||||
}
|
||||
if status, ok := filters["status"]; ok && status != "" {
|
||||
db = db.Where("status = ?", status)
|
||||
}
|
||||
if paymentType, ok := filters["payment_type"]; ok && paymentType != "" {
|
||||
db = db.Where("payment_type = ?", paymentType)
|
||||
}
|
||||
if payChannel, ok := filters["pay_channel"]; ok && payChannel != "" {
|
||||
db = db.Where("pay_channel = ?", payChannel)
|
||||
}
|
||||
if startTime, ok := filters["start_time"]; ok && startTime != "" {
|
||||
db = db.Where("created_at >= ?", startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"]; ok && endTime != "" {
|
||||
db = db.Where("created_at <= ?", endTime)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用排序和分页
|
||||
// 默认按创建时间倒序
|
||||
db = db.Order("created_at DESC")
|
||||
|
||||
// 应用分页
|
||||
if options.PageSize > 0 {
|
||||
db = db.Limit(options.PageSize)
|
||||
}
|
||||
|
||||
if options.Page > 0 {
|
||||
db = db.Offset((options.Page - 1) * options.PageSize)
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
err := db.Find(&orders).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.PurchaseOrder, len(orders))
|
||||
for i := range orders {
|
||||
result[i] = &orders[i]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *GormPurchaseOrderRepository) CountByFilters(ctx context.Context, filters map[string]interface{}) (int64, error) {
|
||||
var count int64
|
||||
|
||||
db := r.GetDB(ctx).Model(&entities.PurchaseOrder{})
|
||||
|
||||
// 应用筛选条件
|
||||
if filters != nil {
|
||||
if userID, ok := filters["user_id"]; ok {
|
||||
db = db.Where("user_id = ?", userID)
|
||||
}
|
||||
if status, ok := filters["status"]; ok && status != "" {
|
||||
db = db.Where("status = ?", status)
|
||||
}
|
||||
if paymentType, ok := filters["payment_type"]; ok && paymentType != "" {
|
||||
db = db.Where("payment_type = ?", paymentType)
|
||||
}
|
||||
if payChannel, ok := filters["pay_channel"]; ok && payChannel != "" {
|
||||
db = db.Where("pay_channel = ?", payChannel)
|
||||
}
|
||||
if startTime, ok := filters["start_time"]; ok && startTime != "" {
|
||||
db = db.Where("created_at >= ?", startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"]; ok && endTime != "" {
|
||||
db = db.Where("created_at <= ?", endTime)
|
||||
}
|
||||
}
|
||||
|
||||
// 执行计数
|
||||
err := db.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
domain_finance_repo "hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
"hyapi-server/internal/shared/interfaces"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
RechargeRecordsTable = "recharge_records"
|
||||
)
|
||||
|
||||
type GormRechargeRecordRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ domain_finance_repo.RechargeRecordRepository = (*GormRechargeRecordRepository)(nil)
|
||||
|
||||
func NewGormRechargeRecordRepository(db *gorm.DB, logger *zap.Logger) domain_finance_repo.RechargeRecordRepository {
|
||||
return &GormRechargeRecordRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, RechargeRecordsTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Create(ctx context.Context, record entities.RechargeRecord) (entities.RechargeRecord, error) {
|
||||
err := r.CreateEntity(ctx, &record)
|
||||
return record, err
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) GetByID(ctx context.Context, id string) (entities.RechargeRecord, error) {
|
||||
var record entities.RechargeRecord
|
||||
err := r.SmartGetByID(ctx, id, &record)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.RechargeRecord{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.RechargeRecord{}, err
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) GetByUserID(ctx context.Context, userID string) ([]entities.RechargeRecord, error) {
|
||||
var records []entities.RechargeRecord
|
||||
err := r.GetDB(ctx).Where("user_id = ?", userID).Order("created_at DESC").Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) GetByAlipayOrderID(ctx context.Context, alipayOrderID string) (*entities.RechargeRecord, error) {
|
||||
var record entities.RechargeRecord
|
||||
err := r.GetDB(ctx).Where("alipay_order_id = ?", alipayOrderID).First(&record).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) GetByTransferOrderID(ctx context.Context, transferOrderID string) (*entities.RechargeRecord, error) {
|
||||
var record entities.RechargeRecord
|
||||
err := r.GetDB(ctx).Where("transfer_order_id = ?", transferOrderID).First(&record).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Update(ctx context.Context, record entities.RechargeRecord) error {
|
||||
return r.UpdateEntity(ctx, &record)
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) UpdateStatus(ctx context.Context, id string, status entities.RechargeStatus) error {
|
||||
return r.GetDB(ctx).Model(&entities.RechargeRecord{}).Where("id = ?", id).Update("status", status).Error
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
|
||||
// 检查是否有 company_name 筛选,如果有则需要 JOIN 表
|
||||
hasCompanyNameFilter := false
|
||||
if options.Filters != nil {
|
||||
if companyName, ok := options.Filters["company_name"].(string); ok && companyName != "" {
|
||||
hasCompanyNameFilter = true
|
||||
}
|
||||
}
|
||||
|
||||
var query *gorm.DB
|
||||
if hasCompanyNameFilter {
|
||||
// 使用 JOIN 查询以支持企业名称筛选
|
||||
query = r.GetDB(ctx).Table("recharge_records rr").
|
||||
Joins("LEFT JOIN users u ON rr.user_id = u.id").
|
||||
Joins("LEFT JOIN enterprise_infos ei ON u.id = ei.user_id")
|
||||
} else {
|
||||
// 普通查询
|
||||
query = r.GetDB(ctx).Model(&entities.RechargeRecord{})
|
||||
}
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
// 特殊处理时间范围过滤器
|
||||
if key == "start_time" {
|
||||
if startTime, ok := value.(time.Time); ok {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.created_at >= ?", startTime)
|
||||
} else {
|
||||
query = query.Where("created_at >= ?", startTime)
|
||||
}
|
||||
}
|
||||
} else if key == "end_time" {
|
||||
if endTime, ok := value.(time.Time); ok {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.created_at <= ?", endTime)
|
||||
} else {
|
||||
query = query.Where("created_at <= ?", endTime)
|
||||
}
|
||||
}
|
||||
} else if key == "company_name" {
|
||||
// 处理企业名称筛选
|
||||
if companyName, ok := value.(string); ok && companyName != "" {
|
||||
query = query.Where("ei.company_name LIKE ?", "%"+companyName+"%")
|
||||
}
|
||||
} else if key == "min_amount" {
|
||||
// 处理最小金额,支持string、int、int64类型
|
||||
if amount, err := r.parseAmount(value); err == nil {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.amount >= ?", amount)
|
||||
} else {
|
||||
query = query.Where("amount >= ?", amount)
|
||||
}
|
||||
}
|
||||
} else if key == "max_amount" {
|
||||
// 处理最大金额,支持string、int、int64类型
|
||||
if amount, err := r.parseAmount(value); err == nil {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.amount <= ?", amount)
|
||||
} else {
|
||||
query = query.Where("amount <= ?", amount)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他过滤器使用等值查询
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr."+key+" = ?", value)
|
||||
} else {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if options.Search != "" {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.user_id LIKE ? OR rr.transfer_order_id LIKE ? OR rr.alipay_order_id LIKE ? OR rr.wechat_order_id LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
} else {
|
||||
query = query.Where("user_id LIKE ? OR transfer_order_id LIKE ? OR alipay_order_id LIKE ? OR wechat_order_id LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
}
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.RechargeRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.RechargeRecord, error) {
|
||||
var records []entities.RechargeRecord
|
||||
|
||||
// 检查是否有 company_name 筛选,如果有则需要 JOIN 表
|
||||
hasCompanyNameFilter := false
|
||||
if options.Filters != nil {
|
||||
if companyName, ok := options.Filters["company_name"].(string); ok && companyName != "" {
|
||||
hasCompanyNameFilter = true
|
||||
}
|
||||
}
|
||||
|
||||
var query *gorm.DB
|
||||
if hasCompanyNameFilter {
|
||||
// 使用 JOIN 查询以支持企业名称筛选
|
||||
query = r.GetDB(ctx).Table("recharge_records rr").
|
||||
Select("rr.*").
|
||||
Joins("LEFT JOIN users u ON rr.user_id = u.id").
|
||||
Joins("LEFT JOIN enterprise_infos ei ON u.id = ei.user_id")
|
||||
} else {
|
||||
// 普通查询
|
||||
query = r.GetDB(ctx).Model(&entities.RechargeRecord{})
|
||||
}
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
// 特殊处理 user_ids 过滤器
|
||||
if key == "user_ids" {
|
||||
if userIds, ok := value.(string); ok && userIds != "" {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.user_id IN ?", strings.Split(userIds, ","))
|
||||
} else {
|
||||
query = query.Where("user_id IN ?", strings.Split(userIds, ","))
|
||||
}
|
||||
}
|
||||
} else if key == "company_name" {
|
||||
// 处理企业名称筛选
|
||||
if companyName, ok := value.(string); ok && companyName != "" {
|
||||
query = query.Where("ei.company_name LIKE ?", "%"+companyName+"%")
|
||||
}
|
||||
} else if key == "start_time" {
|
||||
// 处理开始时间范围
|
||||
if startTime, ok := value.(time.Time); ok {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.created_at >= ?", startTime)
|
||||
} else {
|
||||
query = query.Where("created_at >= ?", startTime)
|
||||
}
|
||||
}
|
||||
} else if key == "end_time" {
|
||||
// 处理结束时间范围
|
||||
if endTime, ok := value.(time.Time); ok {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.created_at <= ?", endTime)
|
||||
} else {
|
||||
query = query.Where("created_at <= ?", endTime)
|
||||
}
|
||||
}
|
||||
} else if key == "min_amount" {
|
||||
// 处理最小金额,支持string、int、int64类型
|
||||
if amount, err := r.parseAmount(value); err == nil {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.amount >= ?", amount)
|
||||
} else {
|
||||
query = query.Where("amount >= ?", amount)
|
||||
}
|
||||
}
|
||||
} else if key == "max_amount" {
|
||||
// 处理最大金额,支持string、int、int64类型
|
||||
if amount, err := r.parseAmount(value); err == nil {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.amount <= ?", amount)
|
||||
} else {
|
||||
query = query.Where("amount <= ?", amount)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他过滤器使用等值查询
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr."+key+" = ?", value)
|
||||
} else {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Where("rr.user_id LIKE ? OR rr.transfer_order_id LIKE ? OR rr.alipay_order_id LIKE ? OR rr.wechat_order_id LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
} else {
|
||||
query = query.Where("user_id LIKE ? OR transfer_order_id LIKE ? OR alipay_order_id LIKE ? OR wechat_order_id LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
}
|
||||
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order == "desc" || options.Order == "DESC" {
|
||||
order = "DESC"
|
||||
}
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Order("rr." + options.Sort + " " + order)
|
||||
} else {
|
||||
query = query.Order(options.Sort + " " + order)
|
||||
}
|
||||
} else {
|
||||
if hasCompanyNameFilter {
|
||||
query = query.Order("rr.created_at DESC")
|
||||
} else {
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
err := query.Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) CreateBatch(ctx context.Context, records []entities.RechargeRecord) error {
|
||||
return r.GetDB(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.RechargeRecord, error) {
|
||||
var records []entities.RechargeRecord
|
||||
err := r.GetDB(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) UpdateBatch(ctx context.Context, records []entities.RechargeRecord) error {
|
||||
return r.GetDB(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
return r.GetDB(ctx).Delete(&entities.RechargeRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.RechargeRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormRechargeRecordRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(gormTx, r.GetLogger(), RechargeRecordsTable),
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.RechargeRecord{})
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.SoftDeleteEntity(ctx, id, &entities.RechargeRecord{})
|
||||
}
|
||||
|
||||
func (r *GormRechargeRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.RestoreEntity(ctx, id, &entities.RechargeRecord{})
|
||||
}
|
||||
|
||||
// GetTotalAmountByUserId 获取用户总充值金额(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetTotalAmountByUserId(ctx context.Context, userId string) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.RechargeRecord{}).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Where("user_id = ? AND status = ? AND recharge_type != ?", userId, entities.RechargeStatusSuccess, entities.RechargeTypeGift).
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetTotalAmountByUserIdAndDateRange 按用户ID和日期范围获取总充值金额(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetTotalAmountByUserIdAndDateRange(ctx context.Context, userId string, startDate, endDate time.Time) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.RechargeRecord{}).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Where("user_id = ? AND status = ? AND recharge_type != ? AND created_at >= ? AND created_at < ?", userId, entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate, endDate).
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetDailyStatsByUserId 获取用户每日充值统计(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetDailyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
// 构建SQL查询 - 使用PostgreSQL语法,使用具体的日期范围
|
||||
sql := `
|
||||
SELECT
|
||||
DATE(created_at) as date,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM recharge_records
|
||||
WHERE user_id = $1
|
||||
AND status = $2
|
||||
AND recharge_type != $3
|
||||
AND DATE(created_at) >= $4
|
||||
AND DATE(created_at) <= $5
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, userId, entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetMonthlyStatsByUserId 获取用户每月充值统计(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetMonthlyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
// 构建SQL查询 - 使用PostgreSQL语法,使用具体的日期范围
|
||||
sql := `
|
||||
SELECT
|
||||
TO_CHAR(created_at, 'YYYY-MM') as month,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM recharge_records
|
||||
WHERE user_id = $1
|
||||
AND status = $2
|
||||
AND recharge_type != $3
|
||||
AND created_at >= $4
|
||||
AND created_at <= $5
|
||||
GROUP BY TO_CHAR(created_at, 'YYYY-MM')
|
||||
ORDER BY month ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, userId, entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate, endDate).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetSystemTotalAmount 获取系统总充值金额(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetSystemTotalAmount(ctx context.Context) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.RechargeRecord{}).
|
||||
Where("status = ? AND recharge_type != ?", entities.RechargeStatusSuccess, entities.RechargeTypeGift).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetSystemAmountByDateRange 获取系统指定时间范围内的充值金额(排除赠送)
|
||||
// endDate 应该是结束日期当天的次日00:00:00(日统计)或下个月1号00:00:00(月统计),使用 < 而不是 <=
|
||||
func (r *GormRechargeRecordRepository) GetSystemAmountByDateRange(ctx context.Context, startDate, endDate time.Time) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.RechargeRecord{}).
|
||||
Where("status = ? AND recharge_type != ? AND created_at >= ? AND created_at < ?", entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate, endDate).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetSystemDailyStats 获取系统每日充值统计(排除赠送)
|
||||
// startDate 和 endDate 应该是时间对象,endDate 应该是结束日期当天的次日00:00:00,使用 < 而不是 <=
|
||||
func (r *GormRechargeRecordRepository) GetSystemDailyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
sql := `
|
||||
SELECT
|
||||
DATE(created_at) as date,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM recharge_records
|
||||
WHERE status = ?
|
||||
AND recharge_type != ?
|
||||
AND created_at >= ?
|
||||
AND created_at < ?
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate, endDate).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetSystemMonthlyStats 获取系统每月充值统计(排除赠送)
|
||||
func (r *GormRechargeRecordRepository) GetSystemMonthlyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
sql := `
|
||||
SELECT
|
||||
TO_CHAR(created_at, 'YYYY-MM') as month,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM recharge_records
|
||||
WHERE status = ?
|
||||
AND recharge_type != ?
|
||||
AND created_at >= ?
|
||||
AND created_at < ?
|
||||
GROUP BY TO_CHAR(created_at, 'YYYY-MM')
|
||||
ORDER BY month ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, entities.RechargeStatusSuccess, entities.RechargeTypeGift, startDate, endDate).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// parseAmount 解析金额值,支持string、int、int64类型,转换为decimal.Decimal
|
||||
func (r *GormRechargeRecordRepository) parseAmount(value interface{}) (decimal.Decimal, error) {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
if v == "" {
|
||||
return decimal.Zero, fmt.Errorf("empty string")
|
||||
}
|
||||
return decimal.NewFromString(v)
|
||||
case int:
|
||||
return decimal.NewFromInt(int64(v)), nil
|
||||
case int64:
|
||||
return decimal.NewFromInt(v), nil
|
||||
case float64:
|
||||
return decimal.NewFromFloat(v), nil
|
||||
case decimal.Decimal:
|
||||
return v, nil
|
||||
default:
|
||||
return decimal.Zero, fmt.Errorf("unsupported type: %T", value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
domain_finance_repo "hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
"hyapi-server/internal/shared/interfaces"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
WalletsTable = "wallets"
|
||||
)
|
||||
|
||||
type GormWalletRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ domain_finance_repo.WalletRepository = (*GormWalletRepository)(nil)
|
||||
|
||||
func NewGormWalletRepository(db *gorm.DB, logger *zap.Logger) domain_finance_repo.WalletRepository {
|
||||
return &GormWalletRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, WalletsTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Create(ctx context.Context, wallet entities.Wallet) (entities.Wallet, error) {
|
||||
err := r.CreateEntity(ctx, &wallet)
|
||||
return wallet, err
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetByID(ctx context.Context, id string) (entities.Wallet, error) {
|
||||
var wallet entities.Wallet
|
||||
err := r.SmartGetByID(ctx, id, &wallet)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Wallet{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Wallet{}, err
|
||||
}
|
||||
return wallet, nil
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Update(ctx context.Context, wallet entities.Wallet) error {
|
||||
return r.UpdateEntity(ctx, &wallet)
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.Wallet{})
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.SoftDeleteEntity(ctx, id, &entities.Wallet{})
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.RestoreEntity(ctx, id, &entities.Wallet{})
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.GetDB(ctx).Model(&entities.Wallet{})
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
if options.Search != "" {
|
||||
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
return count, query.Count(&count).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) CreateBatch(ctx context.Context, wallets []entities.Wallet) error {
|
||||
return r.GetDB(ctx).Create(&wallets).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.Wallet, error) {
|
||||
var wallets []entities.Wallet
|
||||
err := r.GetDB(ctx).Where("id IN ?", ids).Order("created_at DESC").Find(&wallets).Error
|
||||
return wallets, err
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) UpdateBatch(ctx context.Context, wallets []entities.Wallet) error {
|
||||
return r.GetDB(ctx).Save(&wallets).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
return r.GetDB(ctx).Delete(&entities.Wallet{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Wallet, error) {
|
||||
var wallets []entities.Wallet
|
||||
query := r.GetDB(ctx).Model(&entities.Wallet{})
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
if options.Search != "" {
|
||||
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
if options.Sort != "" {
|
||||
order := options.Sort
|
||||
if options.Order == "desc" {
|
||||
order += " DESC"
|
||||
} else {
|
||||
order += " ASC"
|
||||
}
|
||||
query = query.Order(order)
|
||||
} else {
|
||||
// 默认按创建时间倒序
|
||||
query = query.Order("created_at DESC")
|
||||
}
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
return wallets, query.Find(&wallets).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) WithTx(tx interface{}) interfaces.Repository[entities.Wallet] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormWalletRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(gormTx, r.GetLogger(), WalletsTable),
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) FindByUserID(ctx context.Context, userID string) (*entities.Wallet, error) {
|
||||
var wallet entities.Wallet
|
||||
err := r.GetDB(ctx).Where("user_id = ?", userID).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &wallet, nil
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) ExistsByUserID(ctx context.Context, userID string) (bool, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetTotalBalance(ctx context.Context) (interface{}, error) {
|
||||
var total decimal.Decimal
|
||||
err := r.GetDB(ctx).Model(&entities.Wallet{}).Select("COALESCE(SUM(balance), 0)").Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetActiveWalletCount(ctx context.Context) (int64, error) {
|
||||
var count int64
|
||||
err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("is_active = ?", true).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// ================ 接口要求的方法 ================
|
||||
|
||||
func (r *GormWalletRepository) GetByUserID(ctx context.Context, userID string) (*entities.Wallet, error) {
|
||||
var wallet entities.Wallet
|
||||
err := r.GetDB(ctx).Where("user_id = ?", userID).First(&wallet).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &wallet, nil
|
||||
}
|
||||
|
||||
// UpdateBalanceWithVersion 乐观锁自动重试,最大重试maxRetry次
|
||||
func (r *GormWalletRepository) UpdateBalanceWithVersion(ctx context.Context, walletID string, amount decimal.Decimal, operation string) (bool, error) {
|
||||
maxRetry := 10
|
||||
for i := 0; i < maxRetry; i++ {
|
||||
// 每次重试都重新获取最新的钱包信息
|
||||
var wallet entities.Wallet
|
||||
err := r.GetDB(ctx).Where("id = ?", walletID).First(&wallet).Error
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("获取钱包信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 重新计算新余额
|
||||
var newBalance decimal.Decimal
|
||||
switch operation {
|
||||
case "add":
|
||||
newBalance = wallet.Balance.Add(amount)
|
||||
case "subtract":
|
||||
newBalance = wallet.Balance.Sub(amount)
|
||||
default:
|
||||
return false, fmt.Errorf("不支持的操作类型: %s", operation)
|
||||
}
|
||||
|
||||
// 乐观锁更新
|
||||
result := r.GetDB(ctx).Model(&entities.Wallet{}).
|
||||
Where("id = ? AND version = ?", walletID, wallet.Version).
|
||||
Updates(map[string]interface{}{
|
||||
"balance": newBalance.String(),
|
||||
"version": wallet.Version + 1,
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return false, fmt.Errorf("更新钱包余额失败: %w", result.Error)
|
||||
}
|
||||
|
||||
if result.RowsAffected == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 乐观锁冲突,继续重试
|
||||
// 注意:这里可以添加日志记录,但需要确保logger可用
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("高并发下余额变动失败,已达到最大重试次数 %d", maxRetry)
|
||||
}
|
||||
|
||||
// UpdateBalanceByUserID 乐观锁更新(通过用户ID直接更新,使用原生SQL)
|
||||
func (r *GormWalletRepository) UpdateBalanceByUserID(ctx context.Context, userID string, amount decimal.Decimal, operation string) (bool, error) {
|
||||
maxRetry := 20 // 增加重试次数
|
||||
baseDelay := 1 // 基础延迟毫秒
|
||||
|
||||
for i := 0; i < maxRetry; i++ {
|
||||
// 每次重试都重新获取最新的钱包信息
|
||||
var wallet entities.Wallet
|
||||
err := r.GetDB(ctx).Where("user_id = ?", userID).First(&wallet).Error
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("获取钱包信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 重新计算新余额
|
||||
var newBalance decimal.Decimal
|
||||
switch operation {
|
||||
case "add":
|
||||
newBalance = wallet.Balance.Add(amount)
|
||||
case "subtract":
|
||||
newBalance = wallet.Balance.Sub(amount)
|
||||
default:
|
||||
return false, fmt.Errorf("不支持的操作类型: %s", operation)
|
||||
}
|
||||
|
||||
// 使用原生SQL进行乐观锁更新
|
||||
newVersion := wallet.Version + 1
|
||||
result := r.GetDB(ctx).Exec(`
|
||||
UPDATE wallets
|
||||
SET balance = ?, version = ?, updated_at = NOW()
|
||||
WHERE user_id = ? AND version = ?
|
||||
`, newBalance.String(), newVersion, userID, wallet.Version)
|
||||
|
||||
if result.Error != nil {
|
||||
return false, fmt.Errorf("更新钱包余额失败: %w", result.Error)
|
||||
}
|
||||
|
||||
if result.RowsAffected == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 乐观锁冲突,添加指数退避延迟
|
||||
if i < maxRetry-1 {
|
||||
delay := baseDelay * (1 << i) // 指数退避: 1ms, 2ms, 4ms, 8ms...
|
||||
if delay > 50 {
|
||||
delay = 50 // 最大延迟50ms
|
||||
}
|
||||
time.Sleep(time.Duration(delay) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("高并发下余额变动失败,已达到最大重试次数 %d", maxRetry)
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) UpdateBalance(ctx context.Context, walletID string, balance string) error {
|
||||
return r.GetDB(ctx).Model(&entities.Wallet{}).Where("id = ?", walletID).Update("balance", balance).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) ActivateWallet(ctx context.Context, walletID string) error {
|
||||
return r.GetDB(ctx).Model(&entities.Wallet{}).Where("id = ?", walletID).Update("is_active", true).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) DeactivateWallet(ctx context.Context, walletID string) error {
|
||||
return r.GetDB(ctx).Model(&entities.Wallet{}).Where("id = ?", walletID).Update("is_active", false).Error
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetStats(ctx context.Context) (*domain_finance_repo.FinanceStats, error) {
|
||||
var stats domain_finance_repo.FinanceStats
|
||||
|
||||
// 总钱包数
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Count(&stats.TotalWallets).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 激活钱包数
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("is_active = ?", true).Count(&stats.ActiveWallets).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 总余额
|
||||
var totalBalance decimal.Decimal
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Select("COALESCE(SUM(balance), 0)").Scan(&totalBalance).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats.TotalBalance = totalBalance.String()
|
||||
|
||||
// 今日交易数(这里需要根据实际业务逻辑实现)
|
||||
stats.TodayTransactions = 0
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
func (r *GormWalletRepository) GetUserWalletStats(ctx context.Context, userID string) (*domain_finance_repo.FinanceStats, error) {
|
||||
var stats domain_finance_repo.FinanceStats
|
||||
|
||||
// 用户钱包数
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Count(&stats.TotalWallets).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 用户激活钱包数
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("user_id = ? AND is_active = ?", userID, true).Count(&stats.ActiveWallets).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 用户总余额
|
||||
var totalBalance decimal.Decimal
|
||||
if err := r.GetDB(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Select("COALESCE(SUM(balance), 0)").Scan(&totalBalance).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats.TotalBalance = totalBalance.String()
|
||||
|
||||
// 用户今日交易数(这里需要根据实际业务逻辑实现)
|
||||
stats.TodayTransactions = 0
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
@@ -0,0 +1,643 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
domain_finance_repo "hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
"hyapi-server/internal/shared/interfaces"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// WalletTransactionWithProduct 包含产品名称的钱包交易记录
|
||||
type WalletTransactionWithProduct struct {
|
||||
entities.WalletTransaction
|
||||
ProductName string `json:"product_name" gorm:"column:product_name"`
|
||||
}
|
||||
|
||||
const (
|
||||
WalletTransactionsTable = "wallet_transactions"
|
||||
)
|
||||
|
||||
type GormWalletTransactionRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ domain_finance_repo.WalletTransactionRepository = (*GormWalletTransactionRepository)(nil)
|
||||
|
||||
func NewGormWalletTransactionRepository(db *gorm.DB, logger *zap.Logger) domain_finance_repo.WalletTransactionRepository {
|
||||
return &GormWalletTransactionRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, WalletTransactionsTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) Create(ctx context.Context, transaction entities.WalletTransaction) (entities.WalletTransaction, error) {
|
||||
err := r.CreateEntity(ctx, &transaction)
|
||||
return transaction, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) Update(ctx context.Context, transaction entities.WalletTransaction) error {
|
||||
return r.UpdateEntity(ctx, &transaction)
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) GetByID(ctx context.Context, id string) (entities.WalletTransaction, error) {
|
||||
var transaction entities.WalletTransaction
|
||||
err := r.SmartGetByID(ctx, id, &transaction)
|
||||
return transaction, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) GetByUserID(ctx context.Context, userID string, limit, offset int) ([]*entities.WalletTransaction, error) {
|
||||
var transactions []*entities.WalletTransaction
|
||||
options := database.CacheListOptions{
|
||||
Where: "user_id = ?",
|
||||
Args: []interface{}{userID},
|
||||
Order: "created_at DESC",
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}
|
||||
err := r.ListWithCache(ctx, &transactions, 10*time.Minute, options)
|
||||
return transactions, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) GetByApiCallID(ctx context.Context, apiCallID string) (*entities.WalletTransaction, error) {
|
||||
var transaction entities.WalletTransaction
|
||||
err := r.FindOne(ctx, &transaction, "api_call_id = ?", apiCallID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &transaction, nil
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) ListByUserId(ctx context.Context, userId string, options interfaces.ListOptions) ([]*entities.WalletTransaction, int64, error) {
|
||||
var transactions []*entities.WalletTransaction
|
||||
var total int64
|
||||
|
||||
// 构建查询条件
|
||||
whereCondition := "user_id = ?"
|
||||
whereArgs := []interface{}{userId}
|
||||
|
||||
// 获取总数
|
||||
count, err := r.CountWhere(ctx, &entities.WalletTransaction{}, whereCondition, whereArgs...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
total = count
|
||||
|
||||
// 使用基础仓储的分页查询方法
|
||||
err = r.ListWithOptions(ctx, &entities.WalletTransaction{}, &transactions, options)
|
||||
return transactions, total, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) ListByUserIdWithFilters(ctx context.Context, userId string, filters map[string]interface{}, options interfaces.ListOptions) ([]*entities.WalletTransaction, int64, error) {
|
||||
var transactions []*entities.WalletTransaction
|
||||
var total int64
|
||||
|
||||
// 构建基础查询条件
|
||||
whereCondition := "user_id = ?"
|
||||
whereArgs := []interface{}{userId}
|
||||
|
||||
// 应用筛选条件
|
||||
if filters != nil {
|
||||
// 时间范围筛选
|
||||
if startTime, ok := filters["start_time"].(time.Time); ok {
|
||||
whereCondition += " AND created_at >= ?"
|
||||
whereArgs = append(whereArgs, startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"].(time.Time); ok {
|
||||
whereCondition += " AND created_at <= ?"
|
||||
whereArgs = append(whereArgs, endTime)
|
||||
}
|
||||
|
||||
// 关键词筛选(支持transaction_id和product_name)
|
||||
if keyword, ok := filters["keyword"].(string); ok && keyword != "" {
|
||||
whereCondition += " AND (transaction_id LIKE ? OR product_id IN (SELECT id FROM product WHERE name LIKE ?))"
|
||||
whereArgs = append(whereArgs, "%"+keyword+"%", "%"+keyword+"%")
|
||||
}
|
||||
|
||||
// API调用ID筛选
|
||||
if apiCallId, ok := filters["api_call_id"].(string); ok && apiCallId != "" {
|
||||
whereCondition += " AND api_call_id LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+apiCallId+"%")
|
||||
}
|
||||
|
||||
// 金额范围筛选
|
||||
if minAmount, ok := filters["min_amount"].(string); ok && minAmount != "" {
|
||||
whereCondition += " AND amount >= ?"
|
||||
whereArgs = append(whereArgs, minAmount)
|
||||
}
|
||||
if maxAmount, ok := filters["max_amount"].(string); ok && maxAmount != "" {
|
||||
whereCondition += " AND amount <= ?"
|
||||
whereArgs = append(whereArgs, maxAmount)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
count, err := r.CountWhere(ctx, &entities.WalletTransaction{}, whereCondition, whereArgs...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
total = count
|
||||
|
||||
// 使用基础仓储的分页查询方法
|
||||
err = r.ListWithOptions(ctx, &entities.WalletTransaction{}, &transactions, options)
|
||||
return transactions, total, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) CountByUserId(ctx context.Context, userId string) (int64, error) {
|
||||
return r.CountWhere(ctx, &entities.WalletTransaction{}, "user_id = ?", userId)
|
||||
}
|
||||
|
||||
// CountByUserIdAndDateRange 按用户ID和日期范围统计钱包交易次数
|
||||
func (r *GormWalletTransactionRepository) CountByUserIdAndDateRange(ctx context.Context, userId string, startDate, endDate time.Time) (int64, error) {
|
||||
return r.CountWhere(ctx, &entities.WalletTransaction{}, "user_id = ? AND created_at >= ? AND created_at < ?", userId, startDate, endDate)
|
||||
}
|
||||
|
||||
// GetTotalAmountByUserId 获取用户总消费金额
|
||||
func (r *GormWalletTransactionRepository) GetTotalAmountByUserId(ctx context.Context, userId string) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.WalletTransaction{}).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Where("user_id = ?", userId).
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetTotalAmountByUserIdAndDateRange 按用户ID和日期范围获取总消费金额
|
||||
func (r *GormWalletTransactionRepository) GetTotalAmountByUserIdAndDateRange(ctx context.Context, userId string, startDate, endDate time.Time) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.WalletTransaction{}).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Where("user_id = ? AND created_at >= ? AND created_at < ?", userId, startDate, endDate).
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetDailyStatsByUserId 获取用户每日消费统计
|
||||
func (r *GormWalletTransactionRepository) GetDailyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
// 构建SQL查询 - 使用PostgreSQL语法,使用具体的日期范围
|
||||
sql := `
|
||||
SELECT
|
||||
DATE(created_at) as date,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM wallet_transactions
|
||||
WHERE user_id = $1
|
||||
AND DATE(created_at) >= $2
|
||||
AND DATE(created_at) <= $3
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, userId, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetMonthlyStatsByUserId 获取用户每月消费统计
|
||||
func (r *GormWalletTransactionRepository) GetMonthlyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
// 构建SQL查询 - 使用PostgreSQL语法,使用具体的日期范围
|
||||
sql := `
|
||||
SELECT
|
||||
TO_CHAR(created_at, 'YYYY-MM') as month,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM wallet_transactions
|
||||
WHERE user_id = $1
|
||||
AND created_at >= $2
|
||||
AND created_at <= $3
|
||||
GROUP BY TO_CHAR(created_at, 'YYYY-MM')
|
||||
ORDER BY month ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, userId, startDate, endDate).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// 实现interfaces.Repository接口的其他方法
|
||||
func (r *GormWalletTransactionRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.WalletTransaction{})
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
return r.ExistsEntity(ctx, id, &entities.WalletTransaction{})
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.WalletTransaction, error) {
|
||||
var transactions []entities.WalletTransaction
|
||||
err := r.ListWithOptions(ctx, &entities.WalletTransaction{}, &transactions, options)
|
||||
return transactions, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
return r.CountWithOptions(ctx, &entities.WalletTransaction{}, options)
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) CreateBatch(ctx context.Context, transactions []entities.WalletTransaction) error {
|
||||
return r.CreateBatchEntity(ctx, &transactions)
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.WalletTransaction, error) {
|
||||
var transactions []entities.WalletTransaction
|
||||
err := r.GetEntitiesByIDs(ctx, ids, &transactions)
|
||||
return transactions, err
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) UpdateBatch(ctx context.Context, transactions []entities.WalletTransaction) error {
|
||||
return r.UpdateBatchEntity(ctx, &transactions)
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
return r.DeleteBatchEntity(ctx, ids, &entities.WalletTransaction{})
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) WithTx(tx interface{}) interfaces.Repository[entities.WalletTransaction] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormWalletTransactionRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(gormTx, r.GetLogger(), WalletTransactionsTable),
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.SoftDeleteEntity(ctx, id, &entities.WalletTransaction{})
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.RestoreEntity(ctx, id, &entities.WalletTransaction{})
|
||||
}
|
||||
|
||||
func (r *GormWalletTransactionRepository) ListByUserIdWithFiltersAndProductName(ctx context.Context, userId string, filters map[string]interface{}, options interfaces.ListOptions) (map[string]string, []*entities.WalletTransaction, int64, error) {
|
||||
var transactionsWithProduct []*WalletTransactionWithProduct
|
||||
var total int64
|
||||
|
||||
// 构建基础查询条件
|
||||
whereCondition := "wt.user_id = ?"
|
||||
whereArgs := []interface{}{userId}
|
||||
|
||||
// 应用筛选条件
|
||||
if filters != nil {
|
||||
// 时间范围筛选
|
||||
if startTime, ok := filters["start_time"].(time.Time); ok {
|
||||
whereCondition += " AND wt.created_at >= ?"
|
||||
whereArgs = append(whereArgs, startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"].(time.Time); ok {
|
||||
whereCondition += " AND wt.created_at <= ?"
|
||||
whereArgs = append(whereArgs, endTime)
|
||||
}
|
||||
|
||||
// 交易ID筛选
|
||||
if transactionId, ok := filters["transaction_id"].(string); ok && transactionId != "" {
|
||||
whereCondition += " AND wt.transaction_id LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+transactionId+"%")
|
||||
}
|
||||
|
||||
// 产品名称筛选
|
||||
if productName, ok := filters["product_name"].(string); ok && productName != "" {
|
||||
whereCondition += " AND p.name LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+productName+"%")
|
||||
}
|
||||
|
||||
// 金额范围筛选
|
||||
if minAmount, ok := filters["min_amount"].(string); ok && minAmount != "" {
|
||||
whereCondition += " AND wt.amount >= ?"
|
||||
whereArgs = append(whereArgs, minAmount)
|
||||
}
|
||||
if maxAmount, ok := filters["max_amount"].(string); ok && maxAmount != "" {
|
||||
whereCondition += " AND wt.amount <= ?"
|
||||
whereArgs = append(whereArgs, maxAmount)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建JOIN查询
|
||||
query := r.GetDB(ctx).Table("wallet_transactions wt").
|
||||
Select("wt.*, p.name as product_name").
|
||||
Joins("LEFT JOIN product p ON wt.product_id = p.id").
|
||||
Where(whereCondition, whereArgs...)
|
||||
|
||||
// 获取总数
|
||||
var count int64
|
||||
err := query.Count(&count).Error
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
total = count
|
||||
|
||||
// 应用排序和分页
|
||||
if options.Sort != "" {
|
||||
query = query.Order("wt." + options.Sort + " " + options.Order)
|
||||
} else {
|
||||
query = query.Order("wt.created_at DESC")
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
err = query.Find(&transactionsWithProduct).Error
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为entities.WalletTransaction并构建产品名称映射
|
||||
var transactions []*entities.WalletTransaction
|
||||
productNameMap := make(map[string]string)
|
||||
|
||||
for _, t := range transactionsWithProduct {
|
||||
transaction := t.WalletTransaction
|
||||
transactions = append(transactions, &transaction)
|
||||
// 构建产品ID到产品名称的映射
|
||||
if t.ProductName != "" {
|
||||
productNameMap[transaction.ProductID] = t.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
return productNameMap, transactions, total, nil
|
||||
}
|
||||
|
||||
// ListWithFiltersAndProductName 管理端:根据条件筛选所有钱包交易记录(包含产品名称)
|
||||
func (r *GormWalletTransactionRepository) ListWithFiltersAndProductName(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) (map[string]string, []*entities.WalletTransaction, int64, error) {
|
||||
var transactionsWithProduct []*WalletTransactionWithProduct
|
||||
var total int64
|
||||
|
||||
// 构建基础查询条件
|
||||
whereCondition := "1=1"
|
||||
whereArgs := []interface{}{}
|
||||
|
||||
// 应用筛选条件
|
||||
if filters != nil {
|
||||
// 用户ID筛选(支持单个和多个)
|
||||
if userIds, ok := filters["user_ids"].(string); ok && userIds != "" {
|
||||
// 多个用户ID,逗号分隔
|
||||
userIdsList := strings.Split(userIds, ",")
|
||||
whereCondition += " AND wt.user_id IN ?"
|
||||
whereArgs = append(whereArgs, userIdsList)
|
||||
} else if userId, ok := filters["user_id"].(string); ok && userId != "" {
|
||||
// 单个用户ID
|
||||
whereCondition += " AND wt.user_id = ?"
|
||||
whereArgs = append(whereArgs, userId)
|
||||
}
|
||||
|
||||
// 产品ID筛选(支持多个)
|
||||
if productIds, ok := filters["product_ids"].(string); ok && productIds != "" {
|
||||
// 多个产品ID,逗号分隔
|
||||
productIdsList := strings.Split(productIds, ",")
|
||||
whereCondition += " AND wt.product_id IN ?"
|
||||
whereArgs = append(whereArgs, productIdsList)
|
||||
}
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime, ok := filters["start_time"].(time.Time); ok {
|
||||
whereCondition += " AND wt.created_at >= ?"
|
||||
whereArgs = append(whereArgs, startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"].(time.Time); ok {
|
||||
whereCondition += " AND wt.created_at <= ?"
|
||||
whereArgs = append(whereArgs, endTime)
|
||||
}
|
||||
|
||||
// 交易ID筛选
|
||||
if transactionId, ok := filters["transaction_id"].(string); ok && transactionId != "" {
|
||||
whereCondition += " AND wt.transaction_id LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+transactionId+"%")
|
||||
}
|
||||
|
||||
// 产品名称筛选
|
||||
if productName, ok := filters["product_name"].(string); ok && productName != "" {
|
||||
whereCondition += " AND p.name LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+productName+"%")
|
||||
}
|
||||
|
||||
// 企业名称筛选
|
||||
if companyName, ok := filters["company_name"].(string); ok && companyName != "" {
|
||||
whereCondition += " AND ei.company_name LIKE ?"
|
||||
whereArgs = append(whereArgs, "%"+companyName+"%")
|
||||
}
|
||||
|
||||
// 金额范围筛选
|
||||
if minAmount, ok := filters["min_amount"].(string); ok && minAmount != "" {
|
||||
whereCondition += " AND wt.amount >= ?"
|
||||
whereArgs = append(whereArgs, minAmount)
|
||||
}
|
||||
if maxAmount, ok := filters["max_amount"].(string); ok && maxAmount != "" {
|
||||
whereCondition += " AND wt.amount <= ?"
|
||||
whereArgs = append(whereArgs, maxAmount)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建JOIN查询
|
||||
// 需要JOIN product表获取产品名称,JOIN users和enterprise_infos表获取企业名称
|
||||
query := r.GetDB(ctx).Table("wallet_transactions wt").
|
||||
Select("wt.*, p.name as product_name").
|
||||
Joins("LEFT JOIN product p ON wt.product_id = p.id").
|
||||
Joins("LEFT JOIN users u ON wt.user_id = u.id").
|
||||
Joins("LEFT JOIN enterprise_infos ei ON u.id = ei.user_id").
|
||||
Where(whereCondition, whereArgs...)
|
||||
|
||||
// 获取总数
|
||||
var count int64
|
||||
err := query.Count(&count).Error
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
total = count
|
||||
|
||||
// 应用排序和分页
|
||||
if options.Sort != "" {
|
||||
query = query.Order("wt." + options.Sort + " " + options.Order)
|
||||
} else {
|
||||
query = query.Order("wt.created_at DESC")
|
||||
}
|
||||
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
query = query.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
err = query.Find(&transactionsWithProduct).Error
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为entities.WalletTransaction并构建产品名称映射
|
||||
var transactions []*entities.WalletTransaction
|
||||
productNameMap := make(map[string]string)
|
||||
|
||||
for _, t := range transactionsWithProduct {
|
||||
transaction := t.WalletTransaction
|
||||
transactions = append(transactions, &transaction)
|
||||
// 构建产品ID到产品名称的映射
|
||||
if t.ProductName != "" {
|
||||
productNameMap[transaction.ProductID] = t.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
return productNameMap, transactions, total, nil
|
||||
}
|
||||
|
||||
// ExportWithFiltersAndProductName 导出钱包交易记录(包含产品名称和企业信息)
|
||||
func (r *GormWalletTransactionRepository) ExportWithFiltersAndProductName(ctx context.Context, filters map[string]interface{}) ([]*entities.WalletTransaction, error) {
|
||||
var transactionsWithProduct []WalletTransactionWithProduct
|
||||
|
||||
// 构建查询
|
||||
query := r.GetDB(ctx).Table("wallet_transactions wt").
|
||||
Select("wt.*, p.name as product_name").
|
||||
Joins("LEFT JOIN product p ON wt.product_id = p.id")
|
||||
|
||||
// 构建WHERE条件
|
||||
var whereConditions []string
|
||||
var whereArgs []interface{}
|
||||
|
||||
// 用户ID筛选
|
||||
if userIds, ok := filters["user_ids"].(string); ok && userIds != "" {
|
||||
whereConditions = append(whereConditions, "wt.user_id IN (?)")
|
||||
whereArgs = append(whereArgs, strings.Split(userIds, ","))
|
||||
} else if userId, ok := filters["user_id"].(string); ok && userId != "" {
|
||||
whereConditions = append(whereConditions, "wt.user_id = ?")
|
||||
whereArgs = append(whereArgs, userId)
|
||||
}
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime, ok := filters["start_time"].(time.Time); ok {
|
||||
whereConditions = append(whereConditions, "wt.created_at >= ?")
|
||||
whereArgs = append(whereArgs, startTime)
|
||||
}
|
||||
if endTime, ok := filters["end_time"].(time.Time); ok {
|
||||
whereConditions = append(whereConditions, "wt.created_at <= ?")
|
||||
whereArgs = append(whereArgs, endTime)
|
||||
}
|
||||
|
||||
// 交易ID筛选
|
||||
if transactionId, ok := filters["transaction_id"].(string); ok && transactionId != "" {
|
||||
whereConditions = append(whereConditions, "wt.transaction_id LIKE ?")
|
||||
whereArgs = append(whereArgs, "%"+transactionId+"%")
|
||||
}
|
||||
|
||||
// 产品名称筛选
|
||||
if productName, ok := filters["product_name"].(string); ok && productName != "" {
|
||||
whereConditions = append(whereConditions, "p.name LIKE ?")
|
||||
whereArgs = append(whereArgs, "%"+productName+"%")
|
||||
}
|
||||
|
||||
// 产品ID列表筛选
|
||||
if productIds, ok := filters["product_ids"].(string); ok && productIds != "" {
|
||||
whereConditions = append(whereConditions, "wt.product_id IN (?)")
|
||||
whereArgs = append(whereArgs, strings.Split(productIds, ","))
|
||||
}
|
||||
|
||||
// 金额范围筛选
|
||||
if minAmount, ok := filters["min_amount"].(string); ok && minAmount != "" {
|
||||
whereConditions = append(whereConditions, "wt.amount >= ?")
|
||||
whereArgs = append(whereArgs, minAmount)
|
||||
}
|
||||
if maxAmount, ok := filters["max_amount"].(string); ok && maxAmount != "" {
|
||||
whereConditions = append(whereConditions, "wt.amount <= ?")
|
||||
whereArgs = append(whereArgs, maxAmount)
|
||||
}
|
||||
|
||||
// 应用WHERE条件
|
||||
if len(whereConditions) > 0 {
|
||||
query = query.Where(strings.Join(whereConditions, " AND "), whereArgs...)
|
||||
}
|
||||
|
||||
// 排序
|
||||
query = query.Order("wt.created_at DESC")
|
||||
|
||||
// 执行查询
|
||||
err := query.Find(&transactionsWithProduct).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为entities.WalletTransaction
|
||||
var transactions []*entities.WalletTransaction
|
||||
for _, t := range transactionsWithProduct {
|
||||
transaction := t.WalletTransaction
|
||||
transactions = append(transactions, &transaction)
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
// GetSystemTotalAmount 获取系统总消费金额
|
||||
func (r *GormWalletTransactionRepository) GetSystemTotalAmount(ctx context.Context) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.WalletTransaction{}).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetSystemAmountByDateRange 获取系统指定时间范围内的消费金额
|
||||
// endDate 应该是结束日期当天的次日00:00:00(日统计)或下个月1号00:00:00(月统计),使用 < 而不是 <=
|
||||
func (r *GormWalletTransactionRepository) GetSystemAmountByDateRange(ctx context.Context, startDate, endDate time.Time) (float64, error) {
|
||||
var total float64
|
||||
err := r.GetDB(ctx).Model(&entities.WalletTransaction{}).
|
||||
Where("created_at >= ? AND created_at < ?", startDate, endDate).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Scan(&total).Error
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetSystemDailyStats 获取系统每日消费统计
|
||||
func (r *GormWalletTransactionRepository) GetSystemDailyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
sql := `
|
||||
SELECT
|
||||
DATE(created_at) as date,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM wallet_transactions
|
||||
WHERE DATE(created_at) >= ?
|
||||
AND DATE(created_at) <= ?
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetSystemMonthlyStats 获取系统每月消费统计
|
||||
func (r *GormWalletTransactionRepository) GetSystemMonthlyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error) {
|
||||
var results []map[string]interface{}
|
||||
|
||||
sql := `
|
||||
SELECT
|
||||
TO_CHAR(created_at, 'YYYY-MM') as month,
|
||||
COALESCE(SUM(amount), 0) as amount
|
||||
FROM wallet_transactions
|
||||
WHERE created_at >= ?
|
||||
AND created_at < ?
|
||||
GROUP BY TO_CHAR(created_at, 'YYYY-MM')
|
||||
ORDER BY month ASC
|
||||
`
|
||||
|
||||
err := r.GetDB(ctx).Raw(sql, startDate, endDate).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
domain_finance_repo "hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/shared/database"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
WechatOrdersTable = "typay_orders"
|
||||
)
|
||||
|
||||
type GormWechatOrderRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
var _ domain_finance_repo.WechatOrderRepository = (*GormWechatOrderRepository)(nil)
|
||||
|
||||
func NewGormWechatOrderRepository(db *gorm.DB, logger *zap.Logger) domain_finance_repo.WechatOrderRepository {
|
||||
return &GormWechatOrderRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, WechatOrdersTable),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) Create(ctx context.Context, order entities.WechatOrder) (entities.WechatOrder, error) {
|
||||
err := r.CreateEntity(ctx, &order)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) GetByID(ctx context.Context, id string) (entities.WechatOrder, error) {
|
||||
var order entities.WechatOrder
|
||||
err := r.SmartGetByID(ctx, id, &order)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.WechatOrder{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.WechatOrder{}, err
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) GetByOutTradeNo(ctx context.Context, outTradeNo string) (*entities.WechatOrder, error) {
|
||||
var order entities.WechatOrder
|
||||
err := r.GetDB(ctx).Where("out_trade_no = ?", outTradeNo).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) GetByRechargeID(ctx context.Context, rechargeID string) (*entities.WechatOrder, error) {
|
||||
var order entities.WechatOrder
|
||||
err := r.GetDB(ctx).Where("recharge_id = ?", rechargeID).First(&order).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &order, nil
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) GetByUserID(ctx context.Context, userID string) ([]entities.WechatOrder, error) {
|
||||
var orders []entities.WechatOrder
|
||||
// 需要通过充值记录关联查询,这里简化处理
|
||||
err := r.GetDB(ctx).Find(&orders).Error
|
||||
return orders, err
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) Update(ctx context.Context, order entities.WechatOrder) error {
|
||||
return r.UpdateEntity(ctx, &order)
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) UpdateStatus(ctx context.Context, id string, status entities.WechatOrderStatus) error {
|
||||
return r.GetDB(ctx).Model(&entities.WechatOrder{}).Where("id = ?", id).Update("status", status).Error
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.WechatOrder{})
|
||||
}
|
||||
|
||||
func (r *GormWechatOrderRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
return r.ExistsEntity(ctx, id, &entities.WechatOrder{})
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
"hyapi-server/internal/domains/finance/repositories"
|
||||
"hyapi-server/internal/domains/finance/value_objects"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormInvoiceApplicationRepository 发票申请仓储的GORM实现
|
||||
type GormInvoiceApplicationRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewGormInvoiceApplicationRepository 创建发票申请仓储
|
||||
func NewGormInvoiceApplicationRepository(db *gorm.DB) repositories.InvoiceApplicationRepository {
|
||||
return &GormInvoiceApplicationRepository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建发票申请
|
||||
func (r *GormInvoiceApplicationRepository) Create(ctx context.Context, application *entities.InvoiceApplication) error {
|
||||
return r.db.WithContext(ctx).Create(application).Error
|
||||
}
|
||||
|
||||
// Update 更新发票申请
|
||||
func (r *GormInvoiceApplicationRepository) Update(ctx context.Context, application *entities.InvoiceApplication) error {
|
||||
return r.db.WithContext(ctx).Save(application).Error
|
||||
}
|
||||
|
||||
// Save 保存发票申请
|
||||
func (r *GormInvoiceApplicationRepository) Save(ctx context.Context, application *entities.InvoiceApplication) error {
|
||||
return r.db.WithContext(ctx).Save(application).Error
|
||||
}
|
||||
|
||||
// FindByID 根据ID查找发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByID(ctx context.Context, id string) (*entities.InvoiceApplication, error) {
|
||||
var application entities.InvoiceApplication
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&application).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &application, nil
|
||||
}
|
||||
|
||||
// FindByUserID 根据用户ID查找发票申请列表
|
||||
func (r *GormInvoiceApplicationRepository) FindByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
err := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).Where("user_id = ?", userID).Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = r.db.WithContext(ctx).Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindPendingApplications 查找待处理的发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindPendingApplications(ctx context.Context, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
err := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).
|
||||
Where("status = ?", entities.ApplicationStatusPending).
|
||||
Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = r.db.WithContext(ctx).
|
||||
Where("status = ?", entities.ApplicationStatusPending).
|
||||
Order("created_at ASC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindByUserIDAndStatus 根据用户ID和状态查找发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByUserIDAndStatus(ctx context.Context, userID string, status entities.ApplicationStatus, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).Where("user_id = ?", userID)
|
||||
if status != "" {
|
||||
query = query.Where("status = ?", status)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindByUserIDAndStatusWithTimeRange 根据用户ID、状态和时间范围查找发票申请列表
|
||||
func (r *GormInvoiceApplicationRepository) FindByUserIDAndStatusWithTimeRange(ctx context.Context, userID string, status entities.ApplicationStatus, startTime, endTime *time.Time, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).Where("user_id = ?", userID)
|
||||
|
||||
// 添加状态筛选
|
||||
if status != "" {
|
||||
query = query.Where("status = ?", status)
|
||||
}
|
||||
|
||||
// 添加时间范围筛选
|
||||
if startTime != nil {
|
||||
query = query.Where("created_at >= ?", startTime)
|
||||
}
|
||||
if endTime != nil {
|
||||
query = query.Where("created_at <= ?", endTime)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindByStatus 根据状态查找发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByStatus(ctx context.Context, status entities.ApplicationStatus) ([]*entities.InvoiceApplication, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
err := r.db.WithContext(ctx).
|
||||
Where("status = ?", status).
|
||||
Order("created_at DESC").
|
||||
Find(&applications).Error
|
||||
return applications, err
|
||||
}
|
||||
|
||||
// GetUserInvoiceInfo 获取用户发票信息
|
||||
|
||||
|
||||
|
||||
|
||||
// GetUserTotalInvoicedAmount 获取用户已开票总金额
|
||||
func (r *GormInvoiceApplicationRepository) GetUserTotalInvoicedAmount(ctx context.Context, userID string) (string, error) {
|
||||
var total string
|
||||
err := r.db.WithContext(ctx).
|
||||
Model(&entities.InvoiceApplication{}).
|
||||
Select("COALESCE(SUM(CAST(amount AS DECIMAL(10,2))), '0')").
|
||||
Where("user_id = ? AND status = ?", userID, entities.ApplicationStatusCompleted).
|
||||
Scan(&total).Error
|
||||
|
||||
return total, err
|
||||
}
|
||||
|
||||
// GetUserTotalAppliedAmount 获取用户申请开票总金额
|
||||
func (r *GormInvoiceApplicationRepository) GetUserTotalAppliedAmount(ctx context.Context, userID string) (string, error) {
|
||||
var total string
|
||||
err := r.db.WithContext(ctx).
|
||||
Model(&entities.InvoiceApplication{}).
|
||||
Select("COALESCE(SUM(CAST(amount AS DECIMAL(10,2))), '0')").
|
||||
Where("user_id = ?", userID).
|
||||
Scan(&total).Error
|
||||
|
||||
return total, err
|
||||
}
|
||||
|
||||
// FindByUserIDAndInvoiceType 根据用户ID和发票类型查找申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByUserIDAndInvoiceType(ctx context.Context, userID string, invoiceType value_objects.InvoiceType, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).Where("user_id = ? AND invoice_type = ?", userID, invoiceType)
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindByDateRange 根据日期范围查找申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByDateRange(ctx context.Context, startDate, endDate string, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{})
|
||||
if startDate != "" {
|
||||
query = query.Where("DATE(created_at) >= ?", startDate)
|
||||
}
|
||||
if endDate != "" {
|
||||
query = query.Where("DATE(created_at) <= ?", endDate)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// SearchApplications 搜索发票申请
|
||||
func (r *GormInvoiceApplicationRepository) SearchApplications(ctx context.Context, keyword string, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).
|
||||
Where("company_name LIKE ? OR email LIKE ? OR tax_number LIKE ?",
|
||||
fmt.Sprintf("%%%s%%", keyword),
|
||||
fmt.Sprintf("%%%s%%", keyword),
|
||||
fmt.Sprintf("%%%s%%", keyword))
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindByStatusWithTimeRange 根据状态和时间范围查找发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindByStatusWithTimeRange(ctx context.Context, status entities.ApplicationStatus, startTime, endTime *time.Time, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{}).Where("status = ?", status)
|
||||
|
||||
// 添加时间范围筛选
|
||||
if startTime != nil {
|
||||
query = query.Where("created_at >= ?", startTime)
|
||||
}
|
||||
if endTime != nil {
|
||||
query = query.Where("created_at <= ?", endTime)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
|
||||
// FindAllWithTimeRange 根据时间范围查找所有发票申请
|
||||
func (r *GormInvoiceApplicationRepository) FindAllWithTimeRange(ctx context.Context, startTime, endTime *time.Time, page, pageSize int) ([]*entities.InvoiceApplication, int64, error) {
|
||||
var applications []*entities.InvoiceApplication
|
||||
var total int64
|
||||
|
||||
query := r.db.WithContext(ctx).Model(&entities.InvoiceApplication{})
|
||||
|
||||
// 添加时间范围筛选
|
||||
if startTime != nil {
|
||||
query = query.Where("created_at >= ?", startTime)
|
||||
}
|
||||
if endTime != nil {
|
||||
query = query.Where("created_at <= ?", endTime)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
offset := (page - 1) * pageSize
|
||||
err = query.Order("created_at DESC").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&applications).Error
|
||||
|
||||
return applications, total, err
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hyapi-server/internal/domains/finance/entities"
|
||||
"hyapi-server/internal/domains/finance/repositories"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GormUserInvoiceInfoRepository 用户开票信息仓储的GORM实现
|
||||
type GormUserInvoiceInfoRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewGormUserInvoiceInfoRepository 创建用户开票信息仓储
|
||||
func NewGormUserInvoiceInfoRepository(db *gorm.DB) repositories.UserInvoiceInfoRepository {
|
||||
return &GormUserInvoiceInfoRepository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建用户开票信息
|
||||
func (r *GormUserInvoiceInfoRepository) Create(ctx context.Context, info *entities.UserInvoiceInfo) error {
|
||||
return r.db.WithContext(ctx).Create(info).Error
|
||||
}
|
||||
|
||||
// Update 更新用户开票信息
|
||||
func (r *GormUserInvoiceInfoRepository) Update(ctx context.Context, info *entities.UserInvoiceInfo) error {
|
||||
return r.db.WithContext(ctx).Save(info).Error
|
||||
}
|
||||
|
||||
// Save 保存用户开票信息(创建或更新)
|
||||
func (r *GormUserInvoiceInfoRepository) Save(ctx context.Context, info *entities.UserInvoiceInfo) error {
|
||||
return r.db.WithContext(ctx).Save(info).Error
|
||||
}
|
||||
|
||||
// FindByUserID 根据用户ID查找开票信息
|
||||
func (r *GormUserInvoiceInfoRepository) FindByUserID(ctx context.Context, userID string) (*entities.UserInvoiceInfo, error) {
|
||||
var info entities.UserInvoiceInfo
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&info).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// FindByID 根据ID查找开票信息
|
||||
func (r *GormUserInvoiceInfoRepository) FindByID(ctx context.Context, id string) (*entities.UserInvoiceInfo, error) {
|
||||
var info entities.UserInvoiceInfo
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&info).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// Delete 删除用户开票信息
|
||||
func (r *GormUserInvoiceInfoRepository) Delete(ctx context.Context, userID string) error {
|
||||
return r.db.WithContext(ctx).Where("user_id = ?", userID).Delete(&entities.UserInvoiceInfo{}).Error
|
||||
}
|
||||
|
||||
// Exists 检查用户开票信息是否存在
|
||||
func (r *GormUserInvoiceInfoRepository) Exists(ctx context.Context, userID string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.UserInvoiceInfo{}).Where("user_id = ?", userID).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
Reference in New Issue
Block a user