dukcapil/internal/processor/letter_disposition_department_processor.go
2025-09-08 12:24:37 +07:00

181 lines
6.7 KiB
Go

package processor
import (
"context"
"time"
"eslogad-be/internal/contract"
"eslogad-be/internal/entities"
"eslogad-be/internal/repository"
"eslogad-be/internal/transformer"
"github.com/google/uuid"
)
type LetterDispositionDepartmentProcessor interface {
GetByLetterIncomingID(ctx context.Context, letterIncomingID uuid.UUID) ([]entities.LetterIncomingDispositionDepartment, error)
GetDepartmentDispositionStatus(ctx context.Context, letterIncomingID uuid.UUID) (*contract.ListDepartmentDispositionStatusResponse, error)
UpdateDispositionStatus(ctx context.Context, letterIncomingID uuid.UUID, departmentID uuid.UUID, userID uuid.UUID, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error)
CheckAndUpdateLetterCompletionStatus(ctx context.Context, letterIncomingID uuid.UUID) error
}
type LetterDispositionDepartmentProcessorImpl struct {
dispositionDeptRepo *repository.LetterIncomingDispositionDepartmentRepository
dispositionNoteRepo *repository.DispositionNoteRepository
letterRepo *repository.LetterIncomingRepository
}
func NewLetterDispositionDepartmentProcessor(
dispositionDeptRepo *repository.LetterIncomingDispositionDepartmentRepository,
dispositionNoteRepo *repository.DispositionNoteRepository,
letterRepo *repository.LetterIncomingRepository,
) *LetterDispositionDepartmentProcessorImpl {
return &LetterDispositionDepartmentProcessorImpl{
dispositionDeptRepo: dispositionDeptRepo,
dispositionNoteRepo: dispositionNoteRepo,
letterRepo: letterRepo,
}
}
// GetByLetterIncomingID retrieves all disposition departments for a letter
func (p *LetterDispositionDepartmentProcessorImpl) GetByLetterIncomingID(ctx context.Context, letterIncomingID uuid.UUID) ([]entities.LetterIncomingDispositionDepartment, error) {
return p.dispositionDeptRepo.GetByLetterIncomingID(ctx, letterIncomingID)
}
// GetDepartmentDispositionStatus retrieves disposition status for a specific letter
func (p *LetterDispositionDepartmentProcessorImpl) GetDepartmentDispositionStatus(ctx context.Context, letterIncomingID uuid.UUID) (*contract.ListDepartmentDispositionStatusResponse, error) {
dispositions, err := p.dispositionDeptRepo.GetByLetterIncomingID(ctx, letterIncomingID)
if err != nil {
return nil, err
}
response := p.buildDispositionStatusResponse(dispositions)
return response, nil
}
func (p *LetterDispositionDepartmentProcessorImpl) UpdateDispositionStatus(ctx context.Context, letterIncomingID uuid.UUID, departmentID uuid.UUID, userID uuid.UUID, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error) {
dispDept, err := p.dispositionDeptRepo.GetByDispositionAndDepartment(ctx, letterIncomingID, departmentID)
if err != nil {
return nil, err
}
now := time.Now()
var dispositionStatus entities.LetterIncomingDispositionDepartmentStatus
var readAt, completedAt *time.Time
switch req.Status {
case "completed":
dispositionStatus = entities.DispositionDepartmentStatusCompleted
completedAt = &now
readAt = &now // Mark as read when completing
case "read":
dispositionStatus = entities.DispositionDepartmentStatusRead
readAt = &now
case "dispositioned":
dispositionStatus = entities.DispositionDepartmentStatusDispositioned
default:
dispositionStatus = entities.DispositionDepartmentStatusPending
}
// Extract notes for the update
notes := ""
if req.Notes != nil && *req.Notes != "" {
notes = *req.Notes
}
if err := p.dispositionDeptRepo.UpdateStatus(ctx, dispDept.ID, dispositionStatus, notes, readAt, completedAt); err != nil {
return nil, err
}
// Check and update letter completion status
if err := p.CheckAndUpdateLetterCompletionStatus(ctx, letterIncomingID); err != nil {
// Log error but don't fail the status update
}
// Get updated record for response
updatedDispDept, err := p.dispositionDeptRepo.GetByID(ctx, dispDept.ID)
if err != nil {
return nil, err
}
return p.buildSingleDispositionStatusResponse(updatedDispDept), nil
}
// CheckAndUpdateLetterCompletionStatus checks if all dispositions are completed and updates letter status
func (p *LetterDispositionDepartmentProcessorImpl) CheckAndUpdateLetterCompletionStatus(ctx context.Context, letterIncomingID uuid.UUID) error {
// Get all disposition departments for this letter
dispositions, err := p.dispositionDeptRepo.GetByLetterIncomingID(ctx, letterIncomingID)
if err != nil {
return err
}
// Check if all dispositions are completed
allCompleted := true
for _, disp := range dispositions {
if disp.Status == entities.DispositionDepartmentStatusPending {
allCompleted = false
break
}
}
// If all dispositions are completed, update the letter status to completed
if allCompleted && len(dispositions) > 0 {
letter, err := p.letterRepo.GetByID(ctx, letterIncomingID)
if err != nil {
return err
}
letter.Status = "completed"
if err := p.letterRepo.Update(ctx, letter); err != nil {
return err
}
}
return nil
}
// Helper methods
func (p *LetterDispositionDepartmentProcessorImpl) buildDispositionStatusResponse(dispositions []entities.LetterIncomingDispositionDepartment) *contract.ListDepartmentDispositionStatusResponse {
var response []contract.DepartmentDispositionStatusResponse
for _, disp := range dispositions {
response = append(response, *p.buildSingleDispositionStatusResponse(&disp))
}
return &contract.ListDepartmentDispositionStatusResponse{
Dispositions: response,
Pagination: contract.PaginationResponse{
TotalCount: len(response),
Page: 1,
Limit: len(response),
TotalPages: 1,
},
}
}
func (p *LetterDispositionDepartmentProcessorImpl) buildSingleDispositionStatusResponse(dispDept *entities.LetterIncomingDispositionDepartment) *contract.DepartmentDispositionStatusResponse {
letterResp := transformer.LetterIncomingEntityToContract(dispDept.LetterIncoming)
var fromDept *contract.DepartmentResponse
if dispDept.LetterIncomingDisposition != nil && dispDept.LetterIncomingDisposition.DepartmentID != nil {
fromDept = transformer.DepartmentEntityToContract(&dispDept.LetterIncomingDisposition.Department)
}
return &contract.DepartmentDispositionStatusResponse{
ID: dispDept.ID,
LetterID: dispDept.LetterIncomingID,
Letter: letterResp,
FromDepartmentID: dispDept.LetterIncomingDisposition.DepartmentID,
FromDepartment: fromDept,
ToDepartmentID: dispDept.DepartmentID,
ToDepartment: transformer.DepartmentEntityToContract(dispDept.Department),
Status: string(dispDept.Status),
Notes: dispDept.LetterIncomingDisposition.Notes,
ReadAt: dispDept.ReadAt,
CompletedAt: dispDept.CompletedAt,
CreatedAt: dispDept.CreatedAt,
UpdatedAt: dispDept.UpdatedAt,
}
}