package service import ( "context" "github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/maintenance_group/repository" staticDto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" "github.com/google/uuid" "gorm.io/gorm" ) type MaintenanceGroupService interface { Create(ctx context.Context, maintGroup dto.MaintGroupCreateRequest) (dto.MaintGroupResponse, error) GetById(ctx context.Context, maintGroupId string) (dto.MaintGroupResponse, error) GetByName(ctx context.Context, name string) (dto.MaintGroupResponse, error) GetByCode(ctx context.Context, code string) (dto.MaintGroupResponse, error) // GetAll(ctx context.Context) ([]dto.MaintGroupResponse, error) Update(ctx context.Context, maintGroup dto.MaintGroupUpdateRequest, maintGroupId string) (dto.MaintGroupResponse, error) Delete(ctx context.Context, maintGroupId string) error } type maintenanceGroupService struct { maintGroupRepo repository.MaintGroupRepository maintGroupRoleRepo repository.MaintGroupRoleRepository maintGroupRoleUserRepo repository.MaintGroupRoleUserRepository db *gorm.DB } // Create implements MaintenanceGroupService. func (m *maintenanceGroupService) Create(ctx context.Context, req dto.MaintGroupCreateRequest) (dto.MaintGroupResponse, error) { tx := m.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() clientUUID, err := uuid.Parse(req.ClientID) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } maintGroup := entities.M_MaintenanceGroup{ Code: req.Code, Name: req.Name, Description: req.Description, ClientID: clientUUID, } createdGroup, err := m.maintGroupRepo.Create(ctx, tx, maintGroup) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } for _, roleReq := range req.MaintenanceGroupRoles { roleUUID, err := uuid.Parse(roleReq.RoleID) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } role := entities.M_MaintenanceGroupRole{ MaintenanceGroupID: createdGroup.ID, RoleID: roleUUID, Level: roleReq.Level, } createdRole, err := m.maintGroupRoleRepo.Create(ctx, tx, role) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } for _, userReq := range roleReq.MaintenanceGroupRoleUsers { userUUID, err := uuid.Parse(userReq.UserID) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } user := entities.M_MaintenanceGroupRoleUser{ MaintenanceGroupRoleID: createdRole.ID, UserID: userUUID, } _, err = m.maintGroupRoleUserRepo.Create(ctx, tx, user) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } } err = tx.Commit().Error if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } result, err := m.GetById(ctx, createdGroup.ID.String()) if err != nil { return dto.MaintGroupResponse{}, err } return result, nil } // Delete implements MaintenanceGroupService. func (m *maintenanceGroupService) Delete(ctx context.Context, maintGroupId string) error { tx := m.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 1. Ambil semua role dari group roles, err := m.maintGroupRoleRepo.FindByMaintGroupId(ctx, tx, maintGroupId) if err != nil { tx.Rollback() return err } // 2. Hapus semua user dari setiap role for _, role := range roles { err := m.maintGroupRoleUserRepo.DeleteByMaintGroupRoleID(ctx, tx, role.ID.String()) if err != nil { tx.Rollback() return err } } // 3. Hapus semua role dari group err = m.maintGroupRoleRepo.DeleteByMaintGroupId(ctx, tx, maintGroupId) if err != nil { tx.Rollback() return err } // 4. Hapus group err = m.maintGroupRepo.Delete(ctx, tx, maintGroupId) if err != nil { tx.Rollback() return err } // 5. Commit err = tx.Commit().Error if err != nil { tx.Rollback() return err } return nil } // GetAll implements MaintenanceGroupService. // func (m *maintenanceGroupService) GetAll(ctx context.Context) ([]dto.MaintGroupResponse, error) { // groups, err := m.maintGroupRepo.GetAll(ctx, m.db) // if err != nil { // return nil, err // } // var responses []dto.MaintGroupResponse // for _, group := range groups { // responses = append(responses, dto.MaintGroupResponse{ // ID: group.ID.String(), // Code: group.Code, // Name: group.Name, // Description: group.Description, // ClientID: group.ClientID.String(), // // MaintenanceGroupRoles: ... // }) // } // return responses, nil // } // GetByCode implements MaintenanceGroupService. func (m *maintenanceGroupService) GetByCode(ctx context.Context, code string) (dto.MaintGroupResponse, error) { panic("unimplemented") } // GetById implements MaintenanceGroupService. func (m *maintenanceGroupService) GetById(ctx context.Context, maintGroupId string) (dto.MaintGroupResponse, error) { group, err := m.maintGroupRepo.GetById(ctx, m.db, maintGroupId) if err != nil { return dto.MaintGroupResponse{}, err } // Mapping client client := staticDto.IdNameResponse{ ID: group.Client.ID.String(), Name: group.Client.Name, } var roles []dto.MaintenanceGroupRoleResponse for _, role := range group.MaintenanceGroupRoles { // Mapping role roleResp := staticDto.RoleResponse{ ID: role.RoleID.String(), Name: role.Role.Name, // pastikan entity Role ada field Name } var users []dto.MaintenanceGroupRoleUserResponse for _, user := range role.MaintenanceGroupRoleUsers { userResp := staticDto.UserResponse{ ID: user.User.ID.String(), Name: user.User.Name, // pastikan entity User ada field Name } users = append(users, dto.MaintenanceGroupRoleUserResponse{ ID: user.ID.String(), User: userResp, }) } roles = append(roles, dto.MaintenanceGroupRoleResponse{ ID: role.ID.String(), Role: roleResp, Level: role.Level, MaintenanceGroupRoleUsers: users, }) } return dto.MaintGroupResponse{ ID: group.ID.String(), Code: group.Code, Name: group.Name, Description: group.Description, Client: client, MaintenanceGroupRoles: &roles, }, nil } // GetByName implements MaintenanceGroupService. func (m *maintenanceGroupService) GetByName(ctx context.Context, name string) (dto.MaintGroupResponse, error) { panic("unimplemented") } // Update implements MaintenanceGroupService. func (m *maintenanceGroupService) Update(ctx context.Context, req dto.MaintGroupUpdateRequest, maintGroupId string) (dto.MaintGroupResponse, error) { tx := m.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() group, err := m.maintGroupRepo.GetById(ctx, tx, maintGroupId) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } if req.Code != nil { group.Code = *req.Code } if req.Name != nil { group.Name = *req.Name } if req.Description != nil { group.Description = *req.Description } if req.ClientID != nil { clientUUID, err := uuid.Parse(*req.ClientID) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } group.ClientID = clientUUID } updatedGroup, err := m.maintGroupRepo.Update(ctx, tx, group) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } if req.MaintenanceGroupRoles != nil { // 1. Ambil semua role lama via repo oldRoles, err := m.maintGroupRoleRepo.FindByMaintGroupId(ctx, tx, group.ID.String()) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } oldRoleIDs := map[string]bool{} for _, r := range oldRoles { oldRoleIDs[r.ID.String()] = true } // 2. Upsert roles via repo newRoleIDs := map[string]bool{} for _, roleReq := range *req.MaintenanceGroupRoles { if roleReq.ID != nil { newRoleIDs[*roleReq.ID] = true role := entities.M_MaintenanceGroupRole{ ID: uuid.MustParse(*roleReq.ID), MaintenanceGroupID: group.ID, RoleID: uuid.MustParse(*roleReq.RoleID), Level: roleReq.Level, } if _, err := m.maintGroupRoleRepo.Update(ctx, tx, role); err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } else { role := entities.M_MaintenanceGroupRole{ MaintenanceGroupID: group.ID, RoleID: uuid.MustParse(*roleReq.RoleID), Level: roleReq.Level, } if _, err := m.maintGroupRoleRepo.Create(ctx, tx, role); err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } } // 3. Hapus role lama yang tidak ada di request via repo var toDelete []string for oldID := range oldRoleIDs { if !newRoleIDs[oldID] { toDelete = append(toDelete, oldID) } } if len(toDelete) > 0 { if err := m.maintGroupRoleRepo.DeleteByIds(ctx, tx, toDelete); err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } // 4. Untuk setiap role, lakukan upsert pada users via repo for _, roleReq := range *req.MaintenanceGroupRoles { var roleID uuid.UUID if roleReq.ID != nil { roleID = uuid.MustParse(*roleReq.ID) } else { // Handle ambil ID role baru jika perlu continue } oldUsers, err := m.maintGroupRoleUserRepo.FindByRoleId(ctx, tx, roleID.String()) if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } oldUserIDs := map[string]bool{} for _, u := range oldUsers { oldUserIDs[u.UserID.String()] = true } newUserIDs := map[string]bool{} if roleReq.MaintenanceGroupRoleUsers != nil { for _, userReq := range *roleReq.MaintenanceGroupRoleUsers { if userReq.UserID != "" { newUserIDs[userReq.UserID] = true userUUID := uuid.MustParse(userReq.UserID) if !oldUserIDs[userReq.UserID] { user := entities.M_MaintenanceGroupRoleUser{ MaintenanceGroupRoleID: roleID, UserID: userUUID, } if _, err := m.maintGroupRoleUserRepo.Create(ctx, tx, user); err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } } } } var toDeleteUser []string for oldID := range oldUserIDs { if !newUserIDs[oldID] { toDeleteUser = append(toDeleteUser, oldID) } } if len(toDeleteUser) > 0 { if err := m.maintGroupRoleUserRepo.DeleteByRoleIdAndUserIds(ctx, tx, roleID.String(), toDeleteUser); err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } } } } err = tx.Commit().Error if err != nil { tx.Rollback() return dto.MaintGroupResponse{}, err } result, err := m.GetById(ctx, updatedGroup.ID.String()) if err != nil { return dto.MaintGroupResponse{}, err } return result, nil } func NewMaintenanceGroupService(maintGroupRepo repository.MaintGroupRepository, maintGroupRoleRepo repository.MaintGroupRoleRepository, maintGroupRoleUserRepo repository.MaintGroupRoleUserRepository, db *gorm.DB) MaintenanceGroupService { return &maintenanceGroupService{ maintGroupRepo: maintGroupRepo, maintGroupRoleRepo: maintGroupRoleRepo, maintGroupRoleUserRepo: maintGroupRoleUserRepo, db: db, } }