package payment import ( "context" "gorm.io/gorm" "hfb_sys/backend/internal/model" ) func (r *Repository) QueryWalletRecharge(ctx context.Context, userID uint64, paymentID uint64) (*PaymentDTO, error) { var payment model.PaymentOrder if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ? AND order_id = 0", paymentID, userID).First(&payment).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, ErrPaymentNotFound } return nil, err } runtimeConfig, err := r.runtimeConfigForPayment(ctx, &payment) if err != nil { return nil, ErrPaymentUnavailable } if payment.Status == "paid" || runtimeConfig.isMockMode() { dto := toDTO(payment) return &dto, nil } if runtimeConfig.Channel == nil { return nil, ErrPaymentUnavailable } resp, err := runtimeConfig.Channel.QueryPayment(ctx, payment.ThirdOrderID, payment.ProviderOrderID) if err != nil { return nil, err } if err := r.applyChannelStatus(ctx, &payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil { return nil, err } latest, err := r.findPaymentByID(ctx, payment.ID) if err != nil { return nil, err } dto := toDTO(*latest) return &dto, nil } func (r *Repository) Query(ctx context.Context, userID uint64, orderID uint64) (*PaymentDTO, error) { var payment model.PaymentOrder if err := r.db.WithContext(ctx).Where("order_id = ? AND user_id = ? AND biz_type = ?", orderID, userID, "order_pay").Order("id DESC").First(&payment).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, ErrPaymentNotFound } return nil, err } runtimeConfig, err := r.runtimeConfigForPayment(ctx, &payment) if err != nil { return nil, ErrPaymentUnavailable } if payment.Status == "paid" || runtimeConfig.isMockMode() { dto := toDTO(payment) return &dto, nil } if runtimeConfig.Channel == nil { return nil, ErrPaymentUnavailable } resp, err := runtimeConfig.Channel.QueryPayment(ctx, payment.ThirdOrderID, payment.ProviderOrderID) if err != nil { return nil, err } if err := r.applyChannelStatus(ctx, &payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil { return nil, err } latest, err := r.findPaymentByID(ctx, payment.ID) if err != nil { return nil, err } dto := toDTO(*latest) return &dto, nil } func (r *Repository) AdminList(ctx context.Context, query AdminPaymentQuery) (*PaginatedResult, error) { db := r.db.WithContext(ctx).Table("payment_orders AS p"). Select("p.*, COALESCE(u.phone, '') AS user_phone"). Joins("LEFT JOIN users AS u ON u.id = p.user_id") countDB := r.db.WithContext(ctx).Model(&model.PaymentOrder{}) if query.UserID > 0 { db = db.Where("p.user_id = ?", query.UserID) countDB = countDB.Where("user_id = ?", query.UserID) } if query.OrderID > 0 { db = db.Where("p.order_id = ?", query.OrderID) countDB = countDB.Where("order_id = ?", query.OrderID) } if query.OrderNo != "" { db = db.Where("p.order_no = ?", query.OrderNo) countDB = countDB.Where("order_no = ?", query.OrderNo) } if query.BizType != "" { db = db.Where("p.biz_type = ?", query.BizType) countDB = countDB.Where("biz_type = ?", query.BizType) } if query.Status != "" { db = db.Where("p.status = ?", query.Status) countDB = countDB.Where("status = ?", query.Status) } if query.Provider != "" { db = db.Where("p.provider = ?", query.Provider) countDB = countDB.Where("provider = ?", query.Provider) } var total int64 if err := countDB.Count(&total).Error; err != nil { return nil, err } offset := (query.Page - 1) * query.PageSize var rows []adminPaymentRow if err := db.Order("p.id DESC").Offset(offset).Limit(query.PageSize).Scan(&rows).Error; err != nil { return nil, err } items := make([]AdminPaymentDTO, 0, len(rows)) for _, row := range rows { items = append(items, row.toDTO()) } return &PaginatedResult{Items: items, Total: total, Page: query.Page, PageSize: query.PageSize}, nil } func (r *Repository) findPaymentByID(ctx context.Context, paymentID uint64) (*model.PaymentOrder, error) { var payment model.PaymentOrder if err := r.db.WithContext(ctx).First(&payment, paymentID).Error; err != nil { return nil, err } return &payment, nil } type adminPaymentRow struct { model.PaymentOrder UserPhone string } func (row adminPaymentRow) toDTO() AdminPaymentDTO { errorCode, errorMessage := paymentErrorSummary(row.Status, row.RawResponse) return AdminPaymentDTO{ ID: row.ID, PaymentNo: row.PaymentNo, OrderID: row.OrderID, OrderNo: row.OrderNo, UserID: row.UserID, UserPhone: row.UserPhone, Provider: row.Provider, MerchantID: row.MerchantID, ThirdOrderID: row.ThirdOrderID, ProviderOrderID: row.ProviderOrderID, PayWay: row.PayWay, AmountCent: row.AmountCent, BizType: row.BizType, Status: row.Status, ErrorCode: errorCode, ErrorMessage: errorMessage, RawRequest: row.RawRequest, RawResponse: row.RawResponse, PaidAt: row.PaidAt, NotifiedAt: row.NotifiedAt, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt, } }