package processor import ( "context" "eslogad-be/internal/contract" "eslogad-be/internal/entities" "eslogad-be/internal/repository" "eslogad-be/internal/transformer" "github.com/google/uuid" ) type LetterDispositionProcessor interface { CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error) GetByLetterID(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingDisposition, error) GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error) } type LetterDispositionProcessorImpl struct { dispositionRepo *repository.LetterIncomingDispositionRepository dispositionDeptRepo *repository.LetterIncomingDispositionDepartmentRepository dispositionActionSelRepo *repository.LetterDispositionActionSelectionRepository dispositionNoteRepo *repository.DispositionNoteRepository discussionRepo *repository.LetterDiscussionRepository dispActionRepo *repository.DispositionActionRepository activity *ActivityLogProcessorImpl } func NewLetterDispositionProcessor( dispositionRepo *repository.LetterIncomingDispositionRepository, dispositionDeptRepo *repository.LetterIncomingDispositionDepartmentRepository, dispositionActionSelRepo *repository.LetterDispositionActionSelectionRepository, dispositionNoteRepo *repository.DispositionNoteRepository, discussionRepo *repository.LetterDiscussionRepository, dispActionRepo *repository.DispositionActionRepository, activity *ActivityLogProcessorImpl, ) *LetterDispositionProcessorImpl { return &LetterDispositionProcessorImpl{ dispositionRepo: dispositionRepo, dispositionDeptRepo: dispositionDeptRepo, dispositionActionSelRepo: dispositionActionSelRepo, dispositionNoteRepo: dispositionNoteRepo, discussionRepo: discussionRepo, dispActionRepo: dispActionRepo, activity: activity, } } func (p *LetterDispositionProcessorImpl) CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error) { disposition := &entities.LetterIncomingDisposition{ LetterID: req.LetterID, DepartmentID: &req.FromDepartment, Notes: req.Notes, CreatedBy: req.CreatedBy, } if err := p.dispositionRepo.Create(ctx, disposition); err != nil { return nil, err } if err := p.createDispositionDepartments(ctx, disposition.ID, req.LetterID, req.ToDepartmentIDs); err != nil { return nil, err } if len(req.SelectedActions) > 0 { if err := p.createActionSelectionsFromRequest(ctx, disposition.ID, req.SelectedActions); err != nil { return nil, err } } if p.activity != nil { p.activity.LogDispositionCreated(ctx, req.LetterID, req.CreatedBy, len(req.ToDepartmentIDs)) } // Build response dispositions := []entities.LetterIncomingDisposition{*disposition} response := p.buildDispositionsResponse(dispositions) return response, nil } func (p *LetterDispositionProcessorImpl) GetByLetterID(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingDisposition, error) { return p.dispositionRepo.ListByLetter(ctx, letterID) } func (p *LetterDispositionProcessorImpl) GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error) { // Get dispositions dispositions, err := p.dispositionRepo.ListByLetter(ctx, letterID) if err != nil { return nil, err } // Get discussions discussions, err := p.discussionRepo.ListByLetter(ctx, letterID) if err != nil { return nil, err } // Build enhanced response enhancedDispositions := make([]contract.EnhancedDispositionResponse, 0, len(dispositions)) for _, disp := range dispositions { // Build disposition response using existing structure var dept contract.DepartmentResponse if disp.Department.ID != uuid.Nil { dept = *transformer.DepartmentEntityToContract(&disp.Department) } // Build departments departments := make([]contract.DispositionDepartmentResponse, 0, len(disp.Departments)) for _, d := range disp.Departments { departments = append(departments, contract.DispositionDepartmentResponse{ ID: d.ID, DepartmentID: d.DepartmentID, Department: transformer.DepartmentEntityToContract(d.Department), }) } // Build actions actions := make([]contract.DispositionActionSelectionResponse, 0, len(disp.ActionSelections)) for _, a := range disp.ActionSelections { if a.Action != nil { actions = append(actions, contract.DispositionActionSelectionResponse{ ID: a.ID, ActionID: a.ActionID, Action: &contract.DispositionActionResponse{ ID: a.Action.ID.String(), Code: a.Action.Code, Label: a.Action.Label, Description: a.Action.Description, RequiresNote: a.Action.RequiresNote, }, }) } } // Build notes notes := make([]contract.DispositionNoteResponse, 0, len(disp.DispositionNotes)) for _, n := range disp.DispositionNotes { var userResp *contract.UserResponse if n.User != nil { userResp = transformer.EntityToContract(n.User) } notes = append(notes, contract.DispositionNoteResponse{ ID: n.ID, Note: n.Note, CreatedAt: n.CreatedAt, User: userResp, }) } enhancedDispositions = append(enhancedDispositions, contract.EnhancedDispositionResponse{ ID: disp.ID, LetterID: disp.LetterID, DepartmentID: disp.DepartmentID, Notes: disp.Notes, ReadAt: disp.ReadAt, CreatedBy: disp.CreatedBy, CreatedAt: disp.CreatedAt, UpdatedAt: disp.UpdatedAt, Department: dept, Departments: departments, Actions: actions, DispositionNotes: notes, }) } // Get general discussions var generalDiscussions []contract.LetterDiscussionResponse for _, disc := range discussions { generalDiscussions = append(generalDiscussions, *transformer.DiscussionEntityToContract(&disc)) } return &contract.ListEnhancedDispositionsResponse{ Dispositions: enhancedDispositions, Discussions: generalDiscussions, }, nil } // Helper methods func (p *LetterDispositionProcessorImpl) createDispositionDepartments(ctx context.Context, dispositionID, letterID uuid.UUID, departmentIDs []uuid.UUID) error { departments := make([]entities.LetterIncomingDispositionDepartment, 0, len(departmentIDs)) for _, deptID := range departmentIDs { departments = append(departments, entities.LetterIncomingDispositionDepartment{ LetterIncomingDispositionID: dispositionID, LetterIncomingID: letterID, DepartmentID: deptID, Status: entities.DispositionDepartmentStatusPending, }) } if len(departments) > 0 { return p.dispositionDeptRepo.CreateBulk(ctx, departments) } return nil } func (p *LetterDispositionProcessorImpl) createActionSelectionsFromRequest(ctx context.Context, dispositionID uuid.UUID, selectedActions []contract.CreateDispositionActionSelection) error { selections := make([]entities.LetterDispositionActionSelection, 0, len(selectedActions)) for _, action := range selectedActions { selections = append(selections, entities.LetterDispositionActionSelection{ DispositionID: dispositionID, ActionID: action.ActionID, }) } if len(selections) > 0 { return p.dispositionActionSelRepo.CreateBulk(ctx, selections) } return nil } func (p *LetterDispositionProcessorImpl) buildDispositionsResponse(dispositions []entities.LetterIncomingDisposition) *contract.ListDispositionsResponse { dispositionResponses := make([]contract.DispositionResponse, 0, len(dispositions)) for _, disp := range dispositions { dispositionResponses = append(dispositionResponses, *p.buildDispositionResponse(&disp)) } return &contract.ListDispositionsResponse{ Dispositions: dispositionResponses, } } func (p *LetterDispositionProcessorImpl) buildDispositionResponse(disp *entities.LetterIncomingDisposition) *contract.DispositionResponse { return &contract.DispositionResponse{ ID: disp.ID, LetterID: disp.LetterID, DepartmentID: disp.DepartmentID, Notes: disp.Notes, ReadAt: disp.ReadAt, CreatedBy: disp.CreatedBy, CreatedAt: disp.CreatedAt, UpdatedAt: disp.UpdatedAt, } }