package repository import ( "context" "errors" "time" "gorm.io/gorm" "gorm.io/gorm/clause" "pay-bridge/internal/model" ) // NotifyLogRepository 通知记录数据访问 type NotifyLogRepository struct { db *gorm.DB } func NewNotifyLogRepository(db *gorm.DB) *NotifyLogRepository { return &NotifyLogRepository{db: db} } // Upsert 创建或更新通知记录 func (r *NotifyLogRepository) Upsert(ctx context.Context, log *model.NotifyLog) error { return r.db.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "trade_no"}, {Name: "notify_type"}}, DoUpdates: clause.AssignmentColumns([]string{"notify_url", "status", "retry_count", "next_retry_time", "last_response"}), }).Create(log).Error } // GetByTradeNo 按 trade_no + notify_type 查询 func (r *NotifyLogRepository) GetByTradeNo(ctx context.Context, tradeNo string, notifyType model.NotifyType) (*model.NotifyLog, error) { var log model.NotifyLog err := r.db.WithContext(ctx).Where("trade_no = ? AND notify_type = ?", tradeNo, notifyType).First(&log).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &log, err } // ListPendingRetry 查询到期需要重试的通知 func (r *NotifyLogRepository) ListPendingRetry(ctx context.Context, before time.Time, limit int) ([]*model.NotifyLog, error) { var logs []*model.NotifyLog err := r.db.WithContext(ctx). Where("status IN ? AND next_retry_time <= ?", []model.NotifyStatus{model.NotifyStatusPending, model.NotifyStatusRetry}, before). Order("next_retry_time ASC"). Limit(limit). Find(&logs).Error return logs, err } // IncrRetryCount 重试次数+1,更新下次重试时间和最后响应 func (r *NotifyLogRepository) IncrRetryCount(ctx context.Context, id uint64, status model.NotifyStatus, nextRetryTime *time.Time, lastResponse string) error { return r.db.WithContext(ctx).Model(&model.NotifyLog{}).Where("id = ?", id).Updates(map[string]any{ "retry_count": gorm.Expr("retry_count + 1"), "status": status, "next_retry_time": nextRetryTime, "last_response": lastResponse, }).Error } // MarkSuccess 标记通知成功 func (r *NotifyLogRepository) MarkSuccess(ctx context.Context, id uint64, lastResponse string) error { return r.db.WithContext(ctx).Model(&model.NotifyLog{}).Where("id = ?", id).Updates(map[string]any{ "status": model.NotifyStatusSuccess, "last_response": lastResponse, }).Error } // MarkGiveup 标记放弃通知 func (r *NotifyLogRepository) MarkGiveup(ctx context.Context, id uint64) error { return r.db.WithContext(ctx).Model(&model.NotifyLog{}).Where("id = ?", id). Update("status", model.NotifyStatusGiveup).Error }