Update
This commit is contained in:
@@ -39,7 +39,7 @@ type LetterOutgoingProcessor interface {
|
||||
|
||||
GetApprovalsByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingApproval, error)
|
||||
GetApprovalFlow(ctx context.Context, flowID uuid.UUID) (*entities.ApprovalFlow, error)
|
||||
|
||||
|
||||
// GetOutgoingLetterWithDetails fetches letter with all related data
|
||||
GetOutgoingLetterWithDetails(ctx context.Context, letterID uuid.UUID) (*entities.LetterOutgoing, error)
|
||||
GetUsersByIDs(ctx context.Context, userIDs []uuid.UUID) ([]entities.User, error)
|
||||
@@ -178,7 +178,38 @@ func (p *LetterOutgoingProcessorImpl) createRecipientsFromApprovalFlow(ctx conte
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all recipients from the first step (can be multiple if parallel)
|
||||
// Create all approval steps in letter_outgoing_approvals
|
||||
var approvals []entities.LetterOutgoingApproval
|
||||
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 status based on step order
|
||||
if step.StepOrder == minStepOrder {
|
||||
// First step(s) are set to pending
|
||||
approval.Status = entities.ApprovalStatusPending
|
||||
} else {
|
||||
// All other steps are set to not_started
|
||||
approval.Status = entities.ApprovalStatusNotStarted
|
||||
}
|
||||
|
||||
approvals = append(approvals, approval)
|
||||
}
|
||||
|
||||
// Bulk create all approvals
|
||||
if len(approvals) > 0 {
|
||||
if err := p.approvalRepo.CreateBulk(ctx, approvals); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Also create recipients from the first step (for backward compatibility)
|
||||
var recipients []entities.LetterOutgoingRecipient
|
||||
for i, step := range flow.Steps {
|
||||
// Only process steps with the minimum step order (first step)
|
||||
@@ -198,13 +229,12 @@ func (p *LetterOutgoingProcessorImpl) createRecipientsFromApprovalFlow(ctx conte
|
||||
}
|
||||
}
|
||||
|
||||
// If no recipients were created, return without error
|
||||
if len(recipients) == 0 {
|
||||
return nil
|
||||
// Bulk create all recipients if any
|
||||
if len(recipients) > 0 {
|
||||
return p.recipientRepo.CreateBulk(ctx, recipients)
|
||||
}
|
||||
|
||||
// Bulk create all recipients
|
||||
return p.recipientRepo.CreateBulk(ctx, recipients)
|
||||
return nil
|
||||
}
|
||||
|
||||
// createRecipientFromApprovalStep creates a recipient from an approval flow step
|
||||
@@ -331,12 +361,31 @@ func (p *LetterOutgoingProcessorImpl) ProcessApprovalSubmission(ctx context.Cont
|
||||
}
|
||||
|
||||
return p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
||||
// Find the minimum step order (first step)
|
||||
minStepOrder := flow.Steps[0].StepOrder
|
||||
for _, step := range flow.Steps {
|
||||
if step.StepOrder < minStepOrder {
|
||||
minStepOrder = step.StepOrder
|
||||
}
|
||||
}
|
||||
|
||||
approvals := make([]entities.LetterOutgoingApproval, len(flow.Steps))
|
||||
for i, step := range flow.Steps {
|
||||
approvals[i] = entities.LetterOutgoingApproval{
|
||||
LetterID: letterID,
|
||||
StepID: step.ID,
|
||||
Status: entities.ApprovalStatusPending,
|
||||
LetterID: letterID,
|
||||
StepID: step.ID,
|
||||
StepOrder: step.StepOrder,
|
||||
ParallelGroup: step.ParallelGroup,
|
||||
IsRequired: step.Required,
|
||||
ApproverID: step.ApproverUserID,
|
||||
Status: entities.ApprovalStatusPending,
|
||||
}
|
||||
|
||||
// Set status based on step order
|
||||
if step.StepOrder == minStepOrder {
|
||||
approvals[i].Status = entities.ApprovalStatusPending
|
||||
} else {
|
||||
approvals[i].Status = entities.ApprovalStatusNotStarted
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +393,39 @@ func (p *LetterOutgoingProcessorImpl) ProcessApprovalSubmission(ctx context.Cont
|
||||
return err
|
||||
}
|
||||
|
||||
// Add first step approvers as recipients
|
||||
existingRecipients, err := p.recipientRepo.ListByLetter(txCtx, letterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a map of existing user IDs for quick lookup
|
||||
existingUserIDs := make(map[uuid.UUID]bool)
|
||||
for _, recipient := range existingRecipients {
|
||||
if recipient.UserID != nil {
|
||||
existingUserIDs[*recipient.UserID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Add approvers from the first step as recipients
|
||||
for _, approval := range approvals {
|
||||
if approval.StepOrder == minStepOrder && approval.ApproverID != nil {
|
||||
if !existingUserIDs[*approval.ApproverID] {
|
||||
newRecipient := entities.LetterOutgoingRecipient{
|
||||
LetterID: letterID,
|
||||
UserID: approval.ApproverID,
|
||||
IsPrimary: false,
|
||||
Status: "unread",
|
||||
IsArchived: false,
|
||||
}
|
||||
if err := p.recipientRepo.Create(txCtx, &newRecipient); err != nil {
|
||||
return err
|
||||
}
|
||||
existingUserIDs[*approval.ApproverID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.letterRepo.UpdateStatus(txCtx, letterID, entities.LetterOutgoingStatusPendingApproval); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -376,7 +458,78 @@ func (p *LetterOutgoingProcessorImpl) ProcessApproval(ctx context.Context, lette
|
||||
return err
|
||||
}
|
||||
|
||||
if allApproved {
|
||||
allApprovals, err := p.approvalRepo.ListByLetter(txCtx, letterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
approvalsByStep := make(map[int][]entities.LetterOutgoingApproval)
|
||||
for _, a := range allApprovals {
|
||||
approvalsByStep[a.StepOrder] = append(approvalsByStep[a.StepOrder], a)
|
||||
}
|
||||
|
||||
currentStepCompleted := true
|
||||
for _, a := range approvalsByStep[approval.StepOrder] {
|
||||
if a.IsRequired && a.Status != entities.ApprovalStatusApproved {
|
||||
currentStepCompleted = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If current step is completed, activate the next step and add approvers as recipients
|
||||
if currentStepCompleted {
|
||||
nextStepOrder := approval.StepOrder + 1
|
||||
if nextStepApprovals, exists := approvalsByStep[nextStepOrder]; exists {
|
||||
currentRecipients, err := p.recipientRepo.ListByLetter(txCtx, letterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existingUserIDs := make(map[uuid.UUID]bool)
|
||||
for _, recipient := range currentRecipients {
|
||||
if recipient.UserID != nil {
|
||||
existingUserIDs[*recipient.UserID] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, nextApproval := range nextStepApprovals {
|
||||
|
||||
if nextApproval.Status == entities.ApprovalStatusNotStarted {
|
||||
nextApproval.Status = entities.ApprovalStatusPending
|
||||
if err := p.approvalRepo.Update(txCtx, &nextApproval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if nextApproval.ApproverID != nil && !existingUserIDs[*nextApproval.ApproverID] {
|
||||
newRecipient := entities.LetterOutgoingRecipient{
|
||||
LetterID: letterID,
|
||||
UserID: nextApproval.ApproverID,
|
||||
IsPrimary: false,
|
||||
Status: "unread",
|
||||
IsArchived: false,
|
||||
}
|
||||
if err := p.recipientRepo.Create(txCtx, &newRecipient); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existingUserIDs[*nextApproval.ApproverID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all required approvals are completed
|
||||
allRequiredApproved := true
|
||||
for _, a := range allApprovals {
|
||||
if a.IsRequired && a.Status != entities.ApprovalStatusApproved {
|
||||
allRequiredApproved = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Update letter status if all required approvals are done
|
||||
if allRequiredApproved {
|
||||
if err := p.letterRepo.UpdateStatus(txCtx, letterID, entities.LetterOutgoingStatusApproved); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -587,11 +740,11 @@ func (p *LetterOutgoingProcessorImpl) GetOutgoingLetterWithDetails(ctx context.C
|
||||
"Discussions.Attachments",
|
||||
"ActivityLogs",
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
return letter, nil
|
||||
}
|
||||
|
||||
@@ -600,16 +753,16 @@ func (p *LetterOutgoingProcessorImpl) GetUsersByIDs(ctx context.Context, userIDs
|
||||
if len(userIDs) == 0 {
|
||||
return []entities.User{}, nil
|
||||
}
|
||||
|
||||
|
||||
var users []entities.User
|
||||
err := p.db.WithContext(ctx).
|
||||
Preload("Profile").
|
||||
Where("id IN ?", userIDs).
|
||||
Find(&users).Error
|
||||
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user