Update department etc

This commit is contained in:
Aditya Siregar
2025-09-09 14:41:00 +07:00
parent d869d83d4b
commit 0399c87736
22 changed files with 1193 additions and 502 deletions
@@ -23,20 +23,20 @@ func (r *DispositionRouteRepository) Create(ctx context.Context, e *entities.Dis
// 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{}).
@@ -47,7 +47,7 @@ func (r *DispositionRouteRepository) Upsert(ctx context.Context, e *entities.Dis
// 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() {
@@ -55,19 +55,19 @@ func (r *DispositionRouteRepository) BulkUpsert(ctx context.Context, fromDeptID
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{
@@ -76,7 +76,7 @@ func (r *DispositionRouteRepository) BulkUpsert(ctx context.Context, fromDeptID
IsActive: isActive,
AllowedActions: allowedActions,
}
if existing, exists := existingMap[toDeptID]; exists {
// Update existing route
route.ID = existing.ID
@@ -96,7 +96,7 @@ func (r *DispositionRouteRepository) BulkUpsert(ctx context.Context, fromDeptID
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 {
@@ -106,12 +106,12 @@ func (r *DispositionRouteRepository) BulkUpsert(ctx context.Context, fromDeptID
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 {
@@ -133,7 +133,7 @@ func (r *DispositionRouteRepository) Get(ctx context.Context, id uuid.UUID) (*en
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).
if err := db.WithContext(ctx).Where("from_department_id = ? and is_active=true", fromDept).
Preload("FromDepartment").
Preload("ToDepartment").
Order("to_department_id").Find(&list).Error; err != nil {
@@ -160,20 +160,20 @@ func (r *DispositionRouteRepository) SetActive(ctx context.Context, id uuid.UUID
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
}
@@ -181,7 +181,7 @@ func (r *DispositionRouteRepository) ListAllGrouped(ctx context.Context) (map[uu
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").
@@ -190,7 +190,7 @@ func (r *DispositionRouteRepository) ListAllGroupedWithDepartments(ctx context.C
Find(&routes).Error; err != nil {
return nil, err
}
return routes, nil
}
@@ -198,7 +198,7 @@ func (r *DispositionRouteRepository) ListAllGroupedWithDepartments(ctx context.C
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").
@@ -207,6 +207,6 @@ func (r *DispositionRouteRepository) ListAll(ctx context.Context) ([]entities.Di
Find(&routes).Error; err != nil {
return nil, err
}
return routes, nil
}
+134
View File
@@ -225,6 +225,45 @@ func (r *DepartmentRepository) List(ctx context.Context, search string, limit, o
return list, total, nil
}
func (r *DepartmentRepository) ListWithParentFilter(ctx context.Context, search string, limit, offset int, parentPath string, excludedPaths []string) ([]entities.Department, int64, error) {
db := DBFromContext(ctx, r.db)
query := db.WithContext(ctx).Model(&entities.Department{})
// Filter by parent path if provided - include the parent itself and all descendants
if parentPath != "" {
query = query.Where("path = ? OR path <@ ?", parentPath, parentPath)
}
// Exclude specific paths
for _, excludedPath := range excludedPaths {
query = query.Where("NOT (path ~ ?)", excludedPath)
}
// Add search filter if provided
if search != "" {
query = query.Where("name ILIKE ? OR code ILIKE ?", "%"+search+"%", "%"+search+"%")
}
// Get total count
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// Get paginated results
var list []entities.Department
if err := query.
Order("name ASC").
Limit(limit).
Offset(offset).
Find(&list).Error; err != nil {
return nil, 0, err
}
return list, total, nil
}
func (r *DepartmentRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.Department, error) {
db := DBFromContext(ctx, r.db)
var e entities.Department
@@ -233,3 +272,98 @@ func (r *DepartmentRepository) GetByID(ctx context.Context, id uuid.UUID) (*enti
}
return &e, nil
}
func (r *DepartmentRepository) Create(ctx context.Context, department *entities.Department) error {
db := DBFromContext(ctx, r.db)
return db.WithContext(ctx).Create(department).Error
}
func (r *DepartmentRepository) Update(ctx context.Context, department *entities.Department) error {
db := DBFromContext(ctx, r.db)
return db.WithContext(ctx).Save(department).Error
}
func (r *DepartmentRepository) Delete(ctx context.Context, id uuid.UUID) error {
db := DBFromContext(ctx, r.db)
return db.WithContext(ctx).Delete(&entities.Department{}, "id = ?", id).Error
}
func (r *DepartmentRepository) GetByPath(ctx context.Context, path string) (*entities.Department, error) {
db := DBFromContext(ctx, r.db)
var department entities.Department
if err := db.WithContext(ctx).Where("path = ?", path).First(&department).Error; err != nil {
return nil, err
}
return &department, nil
}
func (r *DepartmentRepository) GetAll(ctx context.Context) ([]entities.Department, error) {
db := DBFromContext(ctx, r.db)
var departments []entities.Department
if err := db.WithContext(ctx).Order("path ASC").Find(&departments).Error; err != nil {
return nil, err
}
return departments, nil
}
func (r *DepartmentRepository) GetAllWithParentFilter(ctx context.Context, parentPath string, excludedPaths []string) ([]entities.Department, error) {
db := DBFromContext(ctx, r.db)
var departments []entities.Department
query := db.WithContext(ctx)
// Filter by parent path if provided - include the parent itself and all descendants
if parentPath != "" {
query = query.Where("path = ? OR path <@ ?", parentPath, parentPath)
}
// Exclude specific paths
for _, excludedPath := range excludedPaths {
query = query.Where("NOT (path ~ ?)", excludedPath)
}
if err := query.Order("path ASC").Find(&departments).Error; err != nil {
return nil, err
}
return departments, nil
}
func (r *DepartmentRepository) GetByPathPrefix(ctx context.Context, pathPrefix string) ([]entities.Department, error) {
db := DBFromContext(ctx, r.db)
var departments []entities.Department
// Using ltree operators for hierarchical queries
query := db.WithContext(ctx).Order("path ASC")
if pathPrefix != "" {
// Get all descendants of a path
query = query.Where("path <@ ?", pathPrefix)
}
if err := query.Find(&departments).Error; err != nil {
return nil, err
}
return departments, nil
}
func (r *DepartmentRepository) GetChildren(ctx context.Context, parentPath string) ([]entities.Department, error) {
db := DBFromContext(ctx, r.db)
var departments []entities.Department
// Get direct children and all descendants
if err := db.WithContext(ctx).
Where("path <@ ? AND path != ?", parentPath, parentPath).
Order("path ASC").
Find(&departments).Error; err != nil {
return nil, err
}
return departments, nil
}
func (r *DepartmentRepository) UpdateChildrenPaths(ctx context.Context, oldPath, newPath string) error {
db := DBFromContext(ctx, r.db)
// Use raw SQL for ltree path update
// This will update all children paths by replacing the old prefix with the new one
query := `
UPDATE departments
SET path = ? || subpath(path, nlevel(?))
WHERE path <@ ? AND path != ?
`
return db.WithContext(ctx).Exec(query, newPath, oldPath, oldPath, oldPath).Error
}
+66 -6
View File
@@ -194,26 +194,86 @@ func (r *UserRepositoryImpl) ListWithFilters(ctx context.Context, search *string
var users []*entities.User
var total int64
q := r.b.WithContext(ctx).Table("users").Model(&entities.User{})
// Build base query - use Model directly without Table for proper field mapping
baseQuery := r.b.WithContext(ctx).Model(&entities.User{})
if search != nil && *search != "" {
like := "%" + *search + "%"
q = q.Where("users.name ILIKE ?", like)
baseQuery = baseQuery.Where("name ILIKE ? OR email ILIKE ?", like, like)
}
if isActive != nil {
q = q.Where("users.is_active = ?", *isActive)
baseQuery = baseQuery.Where("is_active = ?", *isActive)
}
// For counting with role filter, we need to use a subquery or join
countQuery := baseQuery
if roleCode != nil && *roleCode != "" {
q = q.Joins("JOIN user_role ur ON ur.user_id = users.id AND ur.removed_at IS NULL").
countQuery = countQuery.
Joins("JOIN user_role ur ON ur.user_id = users.id AND ur.removed_at IS NULL").
Joins("JOIN roles r ON r.id = ur.role_id").
Where("r.code = ?", *roleCode)
}
if err := q.Distinct("users.id").Count(&total).Error; err != nil {
// Get total count
if err := countQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
if err := q.Select("users.*").Distinct("users.id").Limit(limit).Offset(offset).Preload("Profile").Preload("Departments").Find(&users).Error; err != nil {
// Build query for fetching data
dataQuery := r.b.WithContext(ctx).Model(&entities.User{})
if search != nil && *search != "" {
like := "%" + *search + "%"
dataQuery = dataQuery.Where("name ILIKE ? OR email ILIKE ?", like, like)
}
if isActive != nil {
dataQuery = dataQuery.Where("is_active = ?", *isActive)
}
if roleCode != nil && *roleCode != "" {
dataQuery = dataQuery.
Joins("JOIN user_role ur ON ur.user_id = users.id AND ur.removed_at IS NULL").
Joins("JOIN roles r ON r.id = ur.role_id").
Where("r.code = ?", *roleCode)
}
// Fetch users with preloads
if err := dataQuery.
Limit(limit).
Offset(offset).
Preload("Profile").
Preload("Departments").
Find(&users).Error; err != nil {
return nil, 0, err
}
return users, total, nil
}
func (r *UserRepositoryImpl) GetByIDWithDepartments(ctx context.Context, id uuid.UUID) (*entities.User, error) {
var user entities.User
err := r.b.WithContext(ctx).
Preload("Profile").
Preload("Departments").
First(&user, "id = ?", id).Error
if err != nil {
return nil, err
}
return &user, nil
}
func (r *UserRepositoryImpl) UpdateDepartments(ctx context.Context, userID uuid.UUID, departments []entities.Department) error {
// First, clear existing associations
if err := r.b.WithContext(ctx).Model(&entities.User{ID: userID}).Association("Departments").Clear(); err != nil {
return err
}
// Then add new associations
if len(departments) > 0 {
return r.b.WithContext(ctx).Model(&entities.User{ID: userID}).Association("Departments").Append(&departments)
}
return nil
}