This commit is contained in:
Aditya Siregar 2025-10-20 00:32:53 +07:00
parent 7463a86299
commit 92aba06d67
2 changed files with 86 additions and 24 deletions

View File

@ -573,12 +573,47 @@ func (p *LetterOutgoingProcessorImpl) getApprovalsByStepForRevision(ctx context.
}
// isStepCompleted checks if all required approvals in a step are approved
// For parallel groups, at least one approval per group must be completed
func (p *LetterOutgoingProcessorImpl) isStepCompleted(stepApprovals []entities.LetterOutgoingApproval) bool {
// Group approvals by parallel group
approvalsByParallelGroup := make(map[int][]entities.LetterOutgoingApproval)
for _, approval := range stepApprovals {
if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
approvalsByParallelGroup[approval.ParallelGroup] = append(
approvalsByParallelGroup[approval.ParallelGroup],
approval,
)
}
// Check each parallel group
for _, groupApprovals := range approvalsByParallelGroup {
// For each parallel group, check if it has at least one approved
groupHasApproval := false
hasRequiredPending := false
for _, approval := range groupApprovals {
if approval.Status == entities.ApprovalStatusApproved {
groupHasApproval = true
}
if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
hasRequiredPending = true
}
}
// If this group has required approvals that are still pending, step is not complete
if hasRequiredPending {
return false
}
// If this group has no approvals at all and contains required approvals, step is not complete
if !groupHasApproval {
for _, approval := range groupApprovals {
if approval.IsRequired {
return false
}
}
}
}
return true
}

View File

@ -997,43 +997,70 @@ func (s *LetterOutgoingServiceImpl) GetLetterApprovalInfo(ctx context.Context, l
return nil, err
}
// Group approvals by step order to understand the workflow
approvalsByStep := make(map[int][]entities.LetterOutgoingApproval)
// Group approvals by step order and parallel group to understand the workflow
approvalsByStepAndGroup := make(map[int]map[int][]entities.LetterOutgoingApproval)
for _, approval := range approvals {
approvalsByStep[approval.StepOrder] = append(approvalsByStep[approval.StepOrder], approval)
if approvalsByStepAndGroup[approval.StepOrder] == nil {
approvalsByStepAndGroup[approval.StepOrder] = make(map[int][]entities.LetterOutgoingApproval)
}
approvalsByStepAndGroup[approval.StepOrder][approval.ParallelGroup] = append(
approvalsByStepAndGroup[approval.StepOrder][approval.ParallelGroup],
approval,
)
}
// Find the current active step (lowest step order with pending approvals)
var currentStepOrder int = -1
var userApproval *entities.LetterOutgoingApproval
var isApproverOnActiveStep bool
var canApprove bool
// Find the minimum step order that has pending approvals
for stepOrder, stepApprovals := range approvalsByStep {
hasPending := false
for _, approval := range stepApprovals {
if approval.Status == entities.ApprovalStatusPending {
hasPending = true
// Check if this user is an approver for this pending approval
if approval.ApproverID != nil && *approval.ApproverID == userID {
if currentStepOrder == -1 || stepOrder < currentStepOrder {
currentStepOrder = stepOrder
userApproval = &approval
isApproverOnActiveStep = true
for stepOrder, groupApprovals := range approvalsByStepAndGroup {
stepHasPending := false
// Check each parallel group in this step
for _, groupMembers := range groupApprovals {
groupHasPending := false
var userApprovalInGroup *entities.LetterOutgoingApproval
// Check if this group has pending approvals and if user is in this group
for i := range groupMembers {
approval := groupMembers[i]
if approval.Status == entities.ApprovalStatusPending {
groupHasPending = true
stepHasPending = true
// Check if this user is an approver in this group
if approval.ApproverID != nil && *approval.ApproverID == userID {
userApprovalInGroup = &approval
}
}
}
}
// Track the lowest pending step
if hasPending && (currentStepOrder == -1 || stepOrder < currentStepOrder) {
currentStepOrder = stepOrder
}
}
// User can approve if they have a pending approval on the current active step
if isApproverOnActiveStep && userApproval != nil && userApproval.Status == entities.ApprovalStatusPending {
canApprove = true
// If this is the earliest step with pending approvals and user is in a pending group
if groupHasPending && userApprovalInGroup != nil {
if currentStepOrder == -1 || stepOrder < currentStepOrder {
currentStepOrder = stepOrder
userApproval = userApprovalInGroup
// User can approve if they're in a parallel group with pending approvals at the current active step
canApprove = true
} else if stepOrder == currentStepOrder {
// Same step order - user can still approve if in parallel group
userApproval = userApprovalInGroup
canApprove = true
}
}
}
// Track the lowest step with pending approvals
if stepHasPending && (currentStepOrder == -1 || stepOrder < currentStepOrder) {
currentStepOrder = stepOrder
// Reset canApprove if we found a lower step and user is not in it
if userApproval == nil || userApproval.StepOrder != stepOrder {
canApprove = false
userApproval = nil
}
}
}
// Build actions based on eligibility
@ -1095,7 +1122,7 @@ func (s *LetterOutgoingServiceImpl) GetLetterApprovalInfo(ctx context.Context, l
}
info := &contract.LetterApprovalInfoResponse{
IsApproverOnActiveStep: isApproverOnActiveStep,
IsApproverOnActiveStep: canApprove, // User can approve means they're on the active step
DecisionStatus: decisionStatus,
CanApprove: canApprove,
Actions: actions,