package repository import ( "context" "eslogad-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type DispositionRouteRepository struct{ db *gorm.DB } func NewDispositionRouteRepository(db *gorm.DB) *DispositionRouteRepository { return &DispositionRouteRepository{db: db} } func (r *DispositionRouteRepository) Create(ctx context.Context, e *entities.DispositionRoute) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } // Upsert creates or updates a disposition route based on from_department_id and to_department_id func (r *DispositionRouteRepository) Upsert(ctx context.Context, e *entities.DispositionRoute) error { db := DBFromContext(ctx, r.db) // Check if route exists var existing entities.DispositionRoute err := db.WithContext(ctx). Where("from_department_id = ? AND to_department_id = ?", e.FromDepartmentID, e.ToDepartmentID). First(&existing).Error if err == gorm.ErrRecordNotFound { // Create new route return db.WithContext(ctx).Create(e).Error } else if err != nil { return err } // Update existing route e.ID = existing.ID return db.WithContext(ctx).Model(&entities.DispositionRoute{}). Where("id = ?", existing.ID). Updates(e).Error } // BulkUpsert performs bulk create or update for multiple routes func (r *DispositionRouteRepository) BulkUpsert(ctx context.Context, fromDeptID uuid.UUID, toDeptIDs []uuid.UUID, isActive bool, allowedActions entities.JSONB) (created int, updated int, err error) { db := DBFromContext(ctx, r.db) // Start transaction tx := db.WithContext(ctx).Begin() defer func() { if err != nil { tx.Rollback() } }() // Get existing routes for this from_department_id var existingRoutes []entities.DispositionRoute if err = tx.Where("from_department_id = ?", fromDeptID).Find(&existingRoutes).Error; err != nil { return 0, 0, err } // Create map of existing routes existingMap := make(map[uuid.UUID]entities.DispositionRoute) for _, route := range existingRoutes { existingMap[route.ToDepartmentID] = route } // Process each to_department_id for _, toDeptID := range toDeptIDs { route := entities.DispositionRoute{ FromDepartmentID: fromDeptID, ToDepartmentID: toDeptID, IsActive: isActive, AllowedActions: allowedActions, } if existing, exists := existingMap[toDeptID]; exists { // Update existing route route.ID = existing.ID if err = tx.Model(&entities.DispositionRoute{}). Where("id = ?", existing.ID). Updates(&route).Error; err != nil { return created, updated, err } updated++ // Remove from map to track which routes to delete delete(existingMap, toDeptID) } else { // Create new route if err = tx.Create(&route).Error; err != nil { return created, updated, err } created++ } } // Optionally deactivate routes that are no longer in the list // (routes that exist in DB but not in the new list) for _, oldRoute := range existingMap { if err = tx.Model(&entities.DispositionRoute{}). Where("id = ?", oldRoute.ID). Update("is_active", false).Error; err != nil { return created, updated, err } } // Commit transaction if err = tx.Commit().Error; err != nil { return 0, 0, err } return created, updated, nil } func (r *DispositionRouteRepository) Update(ctx context.Context, e *entities.DispositionRoute) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.DispositionRoute{}).Where("id = ?", e.ID).Updates(e).Error } func (r *DispositionRouteRepository) Get(ctx context.Context, id uuid.UUID) (*entities.DispositionRoute, error) { db := DBFromContext(ctx, r.db) var e entities.DispositionRoute if err := db.WithContext(ctx). Preload("FromDepartment"). Preload("ToDepartment"). First(&e, "id = ?", id).Error; err != nil { return nil, err } return &e, nil } func (r *DispositionRouteRepository) ListByFromDept(ctx context.Context, fromDept uuid.UUID) ([]entities.DispositionRoute, error) { db := DBFromContext(ctx, r.db) var list []entities.DispositionRoute if err := db.WithContext(ctx).Where("from_department_id = ?", fromDept). Preload("FromDepartment"). Preload("ToDepartment"). Order("to_department_id").Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *DispositionRouteRepository) IsEligibleForDisposition(ctx context.Context, fromDept uuid.UUID) (bool, error) { db := DBFromContext(ctx, r.db) var list []entities.DispositionRoute if err := db.WithContext(ctx).Where("from_department_id = ?", fromDept).Find(&list).Error; err != nil { return false, err } return len(list) > 0, nil } func (r *DispositionRouteRepository) SetActive(ctx context.Context, id uuid.UUID, isActive bool) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.DispositionRoute{}).Where("id = ?", id).Update("is_active", isActive).Error } // ListAllGrouped returns all disposition routes grouped by from_department_id func (r *DispositionRouteRepository) ListAllGrouped(ctx context.Context) (map[uuid.UUID][]uuid.UUID, error) { db := DBFromContext(ctx, r.db) var routes []entities.DispositionRoute if err := db.WithContext(ctx). Where("is_active = ?", true). Order("from_department_id, to_department_id"). Find(&routes).Error; err != nil { return nil, err } // Group by from_department_id grouped := make(map[uuid.UUID][]uuid.UUID) for _, route := range routes { grouped[route.FromDepartmentID] = append(grouped[route.FromDepartmentID], route.ToDepartmentID) } return grouped, nil } // ListAllGroupedWithDepartments returns all disposition routes grouped by from_department_id with department details func (r *DispositionRouteRepository) ListAllGroupedWithDepartments(ctx context.Context) ([]entities.DispositionRoute, error) { db := DBFromContext(ctx, r.db) var routes []entities.DispositionRoute if err := db.WithContext(ctx). Preload("FromDepartment"). Preload("ToDepartment"). Where("is_active = ?", true). Order("from_department_id, to_department_id"). Find(&routes).Error; err != nil { return nil, err } return routes, nil } // ListAll returns all disposition routes with department details func (r *DispositionRouteRepository) ListAll(ctx context.Context) ([]entities.DispositionRoute, error) { db := DBFromContext(ctx, r.db) var routes []entities.DispositionRoute if err := db.WithContext(ctx). Preload("FromDepartment"). Preload("ToDepartment"). Where("is_active = ?", true). Order("from_department_id, to_department_id"). Find(&routes).Error; err != nil { return nil, err } return routes, nil }