221 lines
6.7 KiB
Go
221 lines
6.7 KiB
Go
package processor
|
|
|
|
import (
|
|
"context"
|
|
|
|
"eslogad-be/internal/entities"
|
|
"eslogad-be/internal/repository"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// LetterOutgoingRecipientProcessor handles all recipient-related operations for outgoing letters
|
|
type LetterOutgoingRecipientProcessor interface {
|
|
// CreateRecipients creates multiple recipients for a letter
|
|
CreateRecipients(ctx context.Context, letterID uuid.UUID, recipients []entities.LetterOutgoingRecipient) error
|
|
|
|
// CreateInitialRecipients creates recipients from both approval workflow and department members
|
|
CreateInitialRecipients(ctx context.Context, letter *entities.LetterOutgoing, creatorDepartmentID uuid.UUID) error
|
|
|
|
// UpdateRecipient updates a single recipient's information
|
|
UpdateRecipient(ctx context.Context, recipient *entities.LetterOutgoingRecipient) error
|
|
|
|
// RemoveRecipient removes a recipient from a letter
|
|
RemoveRecipient(ctx context.Context, letterID uuid.UUID, recipientID uuid.UUID) error
|
|
|
|
// GetRecipientsByLetterID retrieves all recipients for a specific letter
|
|
GetRecipientsByLetterID(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingRecipient, error)
|
|
}
|
|
|
|
type LetterOutgoingRecipientProcessorImpl struct {
|
|
recipientRepo *repository.LetterOutgoingRecipientRepository
|
|
approvalFlowRepo *repository.ApprovalFlowRepository
|
|
userDeptRepo *repository.UserDepartmentRepository
|
|
}
|
|
|
|
func NewLetterOutgoingRecipientProcessor(
|
|
recipientRepo *repository.LetterOutgoingRecipientRepository,
|
|
approvalFlowRepo *repository.ApprovalFlowRepository,
|
|
userDeptRepo *repository.UserDepartmentRepository,
|
|
) *LetterOutgoingRecipientProcessorImpl {
|
|
return &LetterOutgoingRecipientProcessorImpl{
|
|
recipientRepo: recipientRepo,
|
|
approvalFlowRepo: approvalFlowRepo,
|
|
userDeptRepo: userDeptRepo,
|
|
}
|
|
}
|
|
|
|
// CreateRecipients creates multiple recipients for a letter
|
|
func (p *LetterOutgoingRecipientProcessorImpl) CreateRecipients(
|
|
ctx context.Context,
|
|
letterID uuid.UUID,
|
|
recipients []entities.LetterOutgoingRecipient,
|
|
) error {
|
|
if len(recipients) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Ensure all recipients have the correct letter ID and default status
|
|
for i := range recipients {
|
|
recipients[i].LetterID = letterID
|
|
if recipients[i].Status == "" {
|
|
recipients[i].Status = "pending"
|
|
}
|
|
}
|
|
|
|
return p.recipientRepo.CreateBulk(ctx, recipients)
|
|
}
|
|
|
|
// CreateInitialRecipients creates the initial set of recipients for an outgoing letter
|
|
// It combines:
|
|
// 1. Approvers from the approval workflow (if exists)
|
|
// 2. All active users from the letter creator's department
|
|
func (p *LetterOutgoingRecipientProcessorImpl) CreateInitialRecipients(
|
|
ctx context.Context,
|
|
letter *entities.LetterOutgoing,
|
|
creatorDepartmentID uuid.UUID,
|
|
) error {
|
|
// Track unique users to avoid duplicates
|
|
uniqueUsers := make(map[uuid.UUID]bool)
|
|
var allRecipients []entities.LetterOutgoingRecipient
|
|
|
|
// Step 1: Add recipients from approval workflow
|
|
approvalRecipients := p.collectApprovalWorkflowRecipients(ctx, letter, uniqueUsers)
|
|
allRecipients = append(allRecipients, approvalRecipients...)
|
|
|
|
// Step 2: Add all users from the creator's department
|
|
departmentRecipients := p.collectDepartmentRecipients(ctx, letter.ID, creatorDepartmentID, uniqueUsers)
|
|
allRecipients = append(allRecipients, departmentRecipients...)
|
|
|
|
// Step 3: Mark the first recipient as primary and save all
|
|
if len(allRecipients) > 0 {
|
|
allRecipients[0].IsPrimary = true
|
|
return p.recipientRepo.CreateBulk(ctx, allRecipients)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// collectApprovalWorkflowRecipients gathers all users who are approvers in the workflow
|
|
func (p *LetterOutgoingRecipientProcessorImpl) collectApprovalWorkflowRecipients(
|
|
ctx context.Context,
|
|
letter *entities.LetterOutgoing,
|
|
existingUsers map[uuid.UUID]bool,
|
|
) []entities.LetterOutgoingRecipient {
|
|
var recipients []entities.LetterOutgoingRecipient
|
|
|
|
// If no approval workflow is assigned, return empty
|
|
if letter.ApprovalFlowID == nil {
|
|
return recipients
|
|
}
|
|
|
|
// Fetch the approval workflow
|
|
approvalFlow, err := p.approvalFlowRepo.Get(ctx, *letter.ApprovalFlowID)
|
|
if err != nil || approvalFlow == nil || len(approvalFlow.Steps) == 0 {
|
|
return recipients
|
|
}
|
|
|
|
// Add each approver as a recipient
|
|
for _, step := range approvalFlow.Steps {
|
|
if step.ApproverUserID == nil {
|
|
continue
|
|
}
|
|
|
|
userID := *step.ApproverUserID
|
|
|
|
// Skip if user is already added
|
|
if existingUsers[userID] {
|
|
continue
|
|
}
|
|
|
|
existingUsers[userID] = true
|
|
|
|
recipient := entities.LetterOutgoingRecipient{
|
|
LetterID: letter.ID,
|
|
UserID: &userID,
|
|
IsPrimary: false,
|
|
Status: "pending",
|
|
}
|
|
|
|
recipients = append(recipients, recipient)
|
|
}
|
|
|
|
return recipients
|
|
}
|
|
|
|
// collectDepartmentRecipients gathers all active users from a specific department
|
|
func (p *LetterOutgoingRecipientProcessorImpl) collectDepartmentRecipients(
|
|
ctx context.Context,
|
|
letterID uuid.UUID,
|
|
departmentID uuid.UUID,
|
|
existingUsers map[uuid.UUID]bool,
|
|
) []entities.LetterOutgoingRecipient {
|
|
var recipients []entities.LetterOutgoingRecipient
|
|
|
|
// If no department specified, return empty
|
|
if departmentID == uuid.Nil {
|
|
return recipients
|
|
}
|
|
|
|
// Fetch all active users in the department
|
|
userDepartmentMappings, err := p.userDeptRepo.ListActiveByDepartmentIDs(ctx, []uuid.UUID{departmentID})
|
|
if err != nil {
|
|
return recipients
|
|
}
|
|
|
|
// Add each department user as a recipient
|
|
for _, mapping := range userDepartmentMappings {
|
|
// Skip if user is already added (e.g., from approval workflow)
|
|
if existingUsers[mapping.UserID] {
|
|
continue
|
|
}
|
|
|
|
existingUsers[mapping.UserID] = true
|
|
|
|
recipient := entities.LetterOutgoingRecipient{
|
|
LetterID: letterID,
|
|
UserID: &mapping.UserID,
|
|
DepartmentID: &mapping.DepartmentID,
|
|
IsPrimary: false,
|
|
Status: "pending",
|
|
}
|
|
|
|
recipients = append(recipients, recipient)
|
|
}
|
|
|
|
return recipients
|
|
}
|
|
|
|
// UpdateRecipient updates an existing recipient's information
|
|
func (p *LetterOutgoingRecipientProcessorImpl) UpdateRecipient(
|
|
ctx context.Context,
|
|
recipient *entities.LetterOutgoingRecipient,
|
|
) error {
|
|
return p.recipientRepo.Update(ctx, recipient)
|
|
}
|
|
|
|
// RemoveRecipient removes a recipient from a letter
|
|
func (p *LetterOutgoingRecipientProcessorImpl) RemoveRecipient(
|
|
ctx context.Context,
|
|
letterID uuid.UUID,
|
|
recipientID uuid.UUID,
|
|
) error {
|
|
return p.recipientRepo.Delete(ctx, recipientID)
|
|
}
|
|
|
|
// GetRecipientsByLetterID retrieves all recipients for a specific letter
|
|
func (p *LetterOutgoingRecipientProcessorImpl) GetRecipientsByLetterID(
|
|
ctx context.Context,
|
|
letterID uuid.UUID,
|
|
) ([]entities.LetterOutgoingRecipient, error) {
|
|
recipientMap, err := p.recipientRepo.ListByLetterIDs(ctx, []uuid.UUID{letterID})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if recipients, ok := recipientMap[letterID]; ok {
|
|
return recipients, nil
|
|
}
|
|
|
|
return []entities.LetterOutgoingRecipient{}, nil
|
|
} |