224 lines
6.9 KiB
Go
224 lines
6.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/entities"
|
|
"eslogad-be/internal/repository"
|
|
"eslogad-be/internal/transformer"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type DispositionRouteServiceImpl struct {
|
|
repo *repository.DispositionRouteRepository
|
|
}
|
|
|
|
func NewDispositionRouteService(repo *repository.DispositionRouteRepository) *DispositionRouteServiceImpl {
|
|
return &DispositionRouteServiceImpl{repo: repo}
|
|
}
|
|
|
|
// CreateOrUpdate handles bulk create or update of disposition routes
|
|
func (s *DispositionRouteServiceImpl) CreateOrUpdate(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.BulkCreateDispositionRouteResponse, error) {
|
|
// Set default values
|
|
isActive := true
|
|
if req.IsActive != nil {
|
|
isActive = *req.IsActive
|
|
}
|
|
|
|
var allowedActions entities.JSONB
|
|
if req.AllowedActions != nil {
|
|
allowedActions = entities.JSONB(*req.AllowedActions)
|
|
}
|
|
|
|
// Perform bulk upsert
|
|
created, updated, err := s.repo.BulkUpsert(ctx, req.FromDepartmentID, req.ToDepartmentIDs, isActive, allowedActions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Fetch all routes for the from_department_id to return
|
|
routes, err := s.repo.ListByFromDept(ctx, req.FromDepartmentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Transform to response
|
|
routeResponses := transformer.DispositionRoutesToContract(routes)
|
|
|
|
return &contract.BulkCreateDispositionRouteResponse{
|
|
Created: created,
|
|
Updated: updated,
|
|
Routes: routeResponses,
|
|
}, nil
|
|
}
|
|
|
|
// Create maintains backward compatibility for single route creation
|
|
func (s *DispositionRouteServiceImpl) Create(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.DispositionRouteResponse, error) {
|
|
// If only one to_department_id is provided, create a single route
|
|
if len(req.ToDepartmentIDs) == 1 {
|
|
entity := &entities.DispositionRoute{
|
|
FromDepartmentID: req.FromDepartmentID,
|
|
ToDepartmentID: req.ToDepartmentIDs[0],
|
|
}
|
|
if req.IsActive != nil {
|
|
entity.IsActive = *req.IsActive
|
|
} else {
|
|
entity.IsActive = true
|
|
}
|
|
if req.AllowedActions != nil {
|
|
entity.AllowedActions = entities.JSONB(*req.AllowedActions)
|
|
}
|
|
|
|
// Use upsert to handle create or update
|
|
if err := s.repo.Upsert(ctx, entity); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Fetch the created/updated route
|
|
route, err := s.repo.Get(ctx, entity.ID)
|
|
if err != nil {
|
|
// If we can't get by ID (new creation), try to get by from/to combination
|
|
routes, err := s.repo.ListByFromDept(ctx, req.FromDepartmentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, r := range routes {
|
|
if r.ToDepartmentID == req.ToDepartmentIDs[0] {
|
|
resp := transformer.DispositionRoutesToContract([]entities.DispositionRoute{r})[0]
|
|
return &resp, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
resp := transformer.DispositionRoutesToContract([]entities.DispositionRoute{*route})[0]
|
|
return &resp, nil
|
|
}
|
|
|
|
// For multiple to_department_ids, use bulk create/update
|
|
bulkResp, err := s.CreateOrUpdate(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Return the first route as response for backward compatibility
|
|
if len(bulkResp.Routes) > 0 {
|
|
return &bulkResp.Routes[0], nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
func (s *DispositionRouteServiceImpl) Update(ctx context.Context, id uuid.UUID, req *contract.UpdateDispositionRouteRequest) (*contract.DispositionRouteResponse, error) {
|
|
entity, err := s.repo.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if req.IsActive != nil {
|
|
entity.IsActive = *req.IsActive
|
|
}
|
|
if req.AllowedActions != nil {
|
|
entity.AllowedActions = entities.JSONB(*req.AllowedActions)
|
|
}
|
|
if err := s.repo.Update(ctx, entity); err != nil {
|
|
return nil, err
|
|
}
|
|
resp := transformer.DispositionRoutesToContract([]entities.DispositionRoute{*entity})[0]
|
|
return &resp, nil
|
|
}
|
|
func (s *DispositionRouteServiceImpl) Get(ctx context.Context, id uuid.UUID) (*contract.DispositionRouteResponse, error) {
|
|
entity, err := s.repo.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp := transformer.DispositionRoutesToContract([]entities.DispositionRoute{*entity})[0]
|
|
return &resp, nil
|
|
}
|
|
func (s *DispositionRouteServiceImpl) ListByFromDept(ctx context.Context, from uuid.UUID) (*contract.ListDispositionRoutesResponse, error) {
|
|
list, err := s.repo.ListByFromDept(ctx, from)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &contract.ListDispositionRoutesResponse{Routes: transformer.DispositionRoutesToContract(list)}, nil
|
|
}
|
|
func (s *DispositionRouteServiceImpl) SetActive(ctx context.Context, id uuid.UUID, active bool) error {
|
|
return s.repo.SetActive(ctx, id, active)
|
|
}
|
|
|
|
// ListGrouped returns all disposition routes grouped by from_department_id with clean department structure
|
|
func (s *DispositionRouteServiceImpl) ListGrouped(ctx context.Context) (*contract.ListDispositionRoutesGroupedResponse, error) {
|
|
// Get routes with department details
|
|
routes, err := s.repo.ListAllGroupedWithDepartments(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Group routes by from_department_id and collect department info
|
|
type groupedData struct {
|
|
fromDept contract.DepartmentMapping
|
|
toDepts []contract.DepartmentMapping
|
|
toDeptMap map[uuid.UUID]bool // To avoid duplicates
|
|
}
|
|
|
|
grouped := make(map[uuid.UUID]*groupedData)
|
|
|
|
for _, route := range routes {
|
|
if _, exists := grouped[route.FromDepartmentID]; !exists {
|
|
grouped[route.FromDepartmentID] = &groupedData{
|
|
fromDept: contract.DepartmentMapping{
|
|
ID: route.FromDepartmentID,
|
|
Name: route.FromDepartment.Name,
|
|
},
|
|
toDepts: []contract.DepartmentMapping{},
|
|
toDeptMap: make(map[uuid.UUID]bool),
|
|
}
|
|
}
|
|
|
|
// Add to_department if not already added (avoid duplicates)
|
|
if !grouped[route.FromDepartmentID].toDeptMap[route.ToDepartmentID] {
|
|
grouped[route.FromDepartmentID].toDepts = append(
|
|
grouped[route.FromDepartmentID].toDepts,
|
|
contract.DepartmentMapping{
|
|
ID: route.ToDepartmentID,
|
|
Name: route.ToDepartment.Name,
|
|
},
|
|
)
|
|
grouped[route.FromDepartmentID].toDeptMap[route.ToDepartmentID] = true
|
|
}
|
|
}
|
|
|
|
// Convert to response format
|
|
var dispositions []contract.DispositionRouteGroupedItem
|
|
for _, data := range grouped {
|
|
dispositions = append(dispositions, contract.DispositionRouteGroupedItem{
|
|
FromDepartment: data.fromDept,
|
|
ToDepartments: data.toDepts,
|
|
})
|
|
}
|
|
|
|
// Sort by from department name for consistent ordering
|
|
sort.Slice(dispositions, func(i, j int) bool {
|
|
return dispositions[i].FromDepartment.Name < dispositions[j].FromDepartment.Name
|
|
})
|
|
|
|
return &contract.ListDispositionRoutesGroupedResponse{
|
|
Dispositions: dispositions,
|
|
}, nil
|
|
}
|
|
|
|
// ListAll returns all disposition routes with department details
|
|
func (s *DispositionRouteServiceImpl) ListAll(ctx context.Context) (*contract.ListDispositionRoutesDetailedResponse, error) {
|
|
routes, err := s.repo.ListAll(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
routeResponses := transformer.DispositionRoutesToContract(routes)
|
|
|
|
return &contract.ListDispositionRoutesDetailedResponse{
|
|
Routes: routeResponses,
|
|
Total: len(routeResponses),
|
|
}, nil
|
|
}
|