dukcapil/internal/processor/letter_approval_processor.go
2025-09-20 16:31:22 +07:00

113 lines
3.4 KiB
Go

package processor
import (
"context"
"time"
"eslogad-be/internal/entities"
"eslogad-be/internal/repository"
"github.com/google/uuid"
)
type LetterApprovalProcessor interface {
CreateApprovalSteps(ctx context.Context, letter *entities.LetterOutgoing) error
ProcessApprovalAction(ctx context.Context, letterID uuid.UUID, approval *entities.LetterOutgoingApproval, userID uuid.UUID, isApproval bool) error
UpdateApprovalStatus(ctx context.Context, approval *entities.LetterOutgoingApproval, status entities.ApprovalStatus, userID uuid.UUID) error
CheckAllApprovalsComplete(ctx context.Context, letterID uuid.UUID) (bool, error)
}
type LetterApprovalProcessorImpl struct {
approvalRepo *repository.LetterOutgoingApprovalRepository
approvalFlowRepo *repository.ApprovalFlowRepository
letterRepo *repository.LetterOutgoingRepository
}
func NewLetterApprovalProcessor(
approvalRepo *repository.LetterOutgoingApprovalRepository,
approvalFlowRepo *repository.ApprovalFlowRepository,
letterRepo *repository.LetterOutgoingRepository,
) *LetterApprovalProcessorImpl {
return &LetterApprovalProcessorImpl{
approvalRepo: approvalRepo,
approvalFlowRepo: approvalFlowRepo,
letterRepo: letterRepo,
}
}
func (p *LetterApprovalProcessorImpl) CreateApprovalSteps(ctx context.Context, letter *entities.LetterOutgoing) error {
if letter.ApprovalFlowID == nil {
return nil
}
flow, err := p.approvalFlowRepo.Get(ctx, *letter.ApprovalFlowID)
if err != nil || flow == nil || len(flow.Steps) == 0 {
return err
}
// Find the minimum step order (first step)
minStepOrder := flow.Steps[0].StepOrder
for _, step := range flow.Steps {
if step.StepOrder < minStepOrder {
minStepOrder = step.StepOrder
}
}
// Create approval records for each step
for _, step := range flow.Steps {
approval := entities.LetterOutgoingApproval{
LetterID: letter.ID,
StepID: step.ID,
StepOrder: step.StepOrder,
ParallelGroup: step.ParallelGroup,
IsRequired: step.Required,
ApproverID: step.ApproverUserID,
}
// Set initial status
if step.StepOrder == minStepOrder {
approval.Status = entities.ApprovalStatusPending
} else {
approval.Status = entities.ApprovalStatusNotStarted
}
if err := p.approvalRepo.Create(ctx, &approval); err != nil {
return err
}
}
return nil
}
func (p *LetterApprovalProcessorImpl) ProcessApprovalAction(ctx context.Context, letterID uuid.UUID, approval *entities.LetterOutgoingApproval, userID uuid.UUID, isApproval bool) error {
status := entities.ApprovalStatusApproved
if !isApproval {
status = entities.ApprovalStatusRejected
}
return p.UpdateApprovalStatus(ctx, approval, status, userID)
}
func (p *LetterApprovalProcessorImpl) UpdateApprovalStatus(ctx context.Context, approval *entities.LetterOutgoingApproval, status entities.ApprovalStatus, userID uuid.UUID) error {
approval.Status = status
approval.ApproverID = &userID
now := time.Now()
approval.ActedAt = &now
return p.approvalRepo.Update(ctx, approval)
}
func (p *LetterApprovalProcessorImpl) CheckAllApprovalsComplete(ctx context.Context, letterID uuid.UUID) (bool, error) {
approvals, err := p.approvalRepo.ListByLetter(ctx, letterID)
if err != nil {
return false, err
}
for _, approval := range approvals {
if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
return false, nil
}
}
return true, nil
}