Update group approvals
This commit is contained in:
parent
92aba06d67
commit
e082d4fce5
@ -45,11 +45,11 @@ func (p *LetterApprovalProcessorImpl) CreateApprovalSteps(ctx context.Context, l
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the minimum step order (first step)
|
// Find the minimum parallel group
|
||||||
minStepOrder := flow.Steps[0].StepOrder
|
minParallelGroup := flow.Steps[0].ParallelGroup
|
||||||
for _, step := range flow.Steps {
|
for _, step := range flow.Steps {
|
||||||
if step.StepOrder < minStepOrder {
|
if step.ParallelGroup < minParallelGroup {
|
||||||
minStepOrder = step.StepOrder
|
minParallelGroup = step.ParallelGroup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ func (p *LetterApprovalProcessorImpl) CreateApprovalSteps(ctx context.Context, l
|
|||||||
ApproverID: step.ApproverUserID,
|
ApproverID: step.ApproverUserID,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set initial status
|
// Set initial status - all approvals in first parallel group are pending
|
||||||
if step.StepOrder == minStepOrder {
|
if step.ParallelGroup == minParallelGroup {
|
||||||
approval.Status = entities.ApprovalStatusPending
|
approval.Status = entities.ApprovalStatusPending
|
||||||
} else {
|
} else {
|
||||||
approval.Status = entities.ApprovalStatusNotStarted
|
approval.Status = entities.ApprovalStatusNotStarted
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package processor
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"eslogad-be/internal/contract"
|
"eslogad-be/internal/contract"
|
||||||
@ -502,22 +503,22 @@ func (p *LetterOutgoingProcessorImpl) ProcessApproval(ctx context.Context, lette
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Get all approvals FOR THE SAME REVISION and organize by step
|
// Step 2: Get all approvals FOR THE SAME REVISION and organize by parallel group
|
||||||
approvalsByStep, err := p.getApprovalsByStepForRevision(txCtx, letterID, approval.RevisionNumber)
|
approvalsByGroup, err := p.getApprovalsByParallelGroupForRevision(txCtx, letterID, approval.RevisionNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Check if current step is completed
|
// Step 3: Check if current parallel group is completed
|
||||||
if p.isStepCompleted(approvalsByStep[approval.StepOrder]) {
|
if p.isParallelGroupCompleted(approvalsByGroup[approval.ParallelGroup]) {
|
||||||
// Step 4: Activate next step if exists
|
// Step 4: Activate next parallel group if exists
|
||||||
if err := p.activateNextStepForRevision(txCtx, letterID, approval.StepOrder, approval.RevisionNumber, approvalsByStep); err != nil {
|
if err := p.activateNextParallelGroupForRevision(txCtx, letterID, approval.ParallelGroup, approval.RevisionNumber, approvalsByGroup); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Check if all required approvals are completed FOR THIS REVISION
|
// Step 5: Check if all required approvals are completed FOR THIS REVISION
|
||||||
if p.areAllRequiredApprovalsCompleted(approvalsByStep) {
|
if p.areAllRequiredApprovalsCompletedByGroup(approvalsByGroup) {
|
||||||
// Step 6: Update letter status to approved
|
// Step 6: Update letter status to approved
|
||||||
if err := p.letterRepo.UpdateStatus(txCtx, letterID, entities.LetterOutgoingStatusApproved); err != nil {
|
if err := p.letterRepo.UpdateStatus(txCtx, letterID, entities.LetterOutgoingStatusApproved); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -572,6 +573,24 @@ func (p *LetterOutgoingProcessorImpl) getApprovalsByStepForRevision(ctx context.
|
|||||||
return approvalsByStep, nil
|
return approvalsByStep, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getApprovalsByParallelGroupForRevision fetches approvals for a specific revision and organizes them by parallel group
|
||||||
|
func (p *LetterOutgoingProcessorImpl) getApprovalsByParallelGroupForRevision(ctx context.Context, letterID uuid.UUID, revisionNumber int) (map[int][]entities.LetterOutgoingApproval, error) {
|
||||||
|
allApprovals, err := p.approvalRepo.ListByLetter(ctx, letterID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
approvalsByGroup := make(map[int][]entities.LetterOutgoingApproval)
|
||||||
|
for _, approval := range allApprovals {
|
||||||
|
// Only include approvals from the same revision
|
||||||
|
if approval.RevisionNumber == revisionNumber {
|
||||||
|
approvalsByGroup[approval.ParallelGroup] = append(approvalsByGroup[approval.ParallelGroup], approval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return approvalsByGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
// isStepCompleted checks if all required approvals in a step are approved
|
// isStepCompleted checks if all required approvals in a step are approved
|
||||||
// For parallel groups, at least one approval per group must be completed
|
// For parallel groups, at least one approval per group must be completed
|
||||||
func (p *LetterOutgoingProcessorImpl) isStepCompleted(stepApprovals []entities.LetterOutgoingApproval) bool {
|
func (p *LetterOutgoingProcessorImpl) isStepCompleted(stepApprovals []entities.LetterOutgoingApproval) bool {
|
||||||
@ -741,6 +760,79 @@ func (p *LetterOutgoingProcessorImpl) areAllRequiredApprovalsCompleted(approvals
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isParallelGroupCompleted checks if all required approvals in a parallel group are approved
|
||||||
|
func (p *LetterOutgoingProcessorImpl) isParallelGroupCompleted(groupApprovals []entities.LetterOutgoingApproval) bool {
|
||||||
|
for _, approval := range groupApprovals {
|
||||||
|
if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// activateNextParallelGroupForRevision activates the next parallel group for a specific revision
|
||||||
|
func (p *LetterOutgoingProcessorImpl) activateNextParallelGroupForRevision(ctx context.Context, letterID uuid.UUID, currentGroup int, revisionNumber int, approvalsByGroup map[int][]entities.LetterOutgoingApproval) error {
|
||||||
|
// Find the next parallel group (handles non-sequential group numbers)
|
||||||
|
var groups []int
|
||||||
|
for group := range approvalsByGroup {
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
sort.Ints(groups)
|
||||||
|
|
||||||
|
var nextGroup int = -1
|
||||||
|
for _, group := range groups {
|
||||||
|
if group > currentGroup {
|
||||||
|
nextGroup = group
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextGroup == -1 {
|
||||||
|
return nil // No next group
|
||||||
|
}
|
||||||
|
|
||||||
|
nextGroupApprovals, exists := approvalsByGroup[nextGroup]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get existing recipients to avoid duplicates
|
||||||
|
existingUserIDs, err := p.getExistingRecipientUserIDs(ctx, letterID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each approval in the next group
|
||||||
|
for _, nextApproval := range nextGroupApprovals {
|
||||||
|
// Only process if it's the same revision
|
||||||
|
if nextApproval.RevisionNumber == revisionNumber {
|
||||||
|
// Activate approval if not started
|
||||||
|
if err := p.activateApprovalIfNotStarted(ctx, &nextApproval); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add approver as recipient if not already exists
|
||||||
|
if err := p.addApproverAsRecipientIfNeeded(ctx, letterID, nextApproval.ApproverID, existingUserIDs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// areAllRequiredApprovalsCompletedByGroup checks if all required approvals are completed (organized by parallel group)
|
||||||
|
func (p *LetterOutgoingProcessorImpl) areAllRequiredApprovalsCompletedByGroup(approvalsByGroup map[int][]entities.LetterOutgoingApproval) bool {
|
||||||
|
for _, groupApprovals := range approvalsByGroup {
|
||||||
|
for _, approval := range groupApprovals {
|
||||||
|
if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// logApprovalActivity creates an activity log for the approval action
|
// logApprovalActivity creates an activity log for the approval action
|
||||||
func (p *LetterOutgoingProcessorImpl) logApprovalActivity(ctx context.Context, letterID, approvalID uuid.UUID, userID uuid.UUID) error {
|
func (p *LetterOutgoingProcessorImpl) logApprovalActivity(ctx context.Context, letterID, approvalID uuid.UUID, userID uuid.UUID) error {
|
||||||
activityLog := &entities.LetterOutgoingActivityLog{
|
activityLog := &entities.LetterOutgoingActivityLog{
|
||||||
|
|||||||
@ -634,15 +634,14 @@ func (s *LetterOutgoingServiceImpl) ApproveOutgoingLetter(ctx context.Context, l
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find user's pending approval
|
||||||
var currentApproval *entities.LetterOutgoingApproval
|
var currentApproval *entities.LetterOutgoingApproval
|
||||||
for i := range approvals {
|
for i := range approvals {
|
||||||
if approvals[i].Status == entities.ApprovalStatusPending {
|
if approvals[i].Status == entities.ApprovalStatusPending &&
|
||||||
step := approvals[i].Step
|
approvals[i].ApproverID != nil &&
|
||||||
if (step.ApproverUserID != nil && *step.ApproverUserID == userID) ||
|
*approvals[i].ApproverID == userID {
|
||||||
(step.ApproverRoleID != nil && userHasRole(ctx, *step.ApproverRoleID)) {
|
currentApproval = &approvals[i]
|
||||||
currentApproval = &approvals[i]
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,14 +658,21 @@ func (s *LetterOutgoingServiceImpl) ApproveOutgoingLetter(ctx context.Context, l
|
|||||||
|
|
||||||
// Send notifications after successful approval
|
// Send notifications after successful approval
|
||||||
if s.notificationProcessor != nil {
|
if s.notificationProcessor != nil {
|
||||||
// Step approved but not final - notify creator about step completion AND next approvers
|
// Get next parallel group to determine notification message
|
||||||
creatorMessage := fmt.Sprintf("Surat keluar '%s' telah disetujui pada tahap %d, menunggu persetujuan tahap berikutnya", letter.Subject, currentApproval.StepOrder)
|
nextParallelGroup := s.getNextParallelGroup(approvals, currentApproval.ParallelGroup)
|
||||||
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Disetujui Tahap "+fmt.Sprintf("%d", currentApproval.StepOrder), creatorMessage)
|
|
||||||
|
|
||||||
// Notify next step approvers
|
if nextParallelGroup > 0 {
|
||||||
nextStepOrder := currentApproval.StepOrder + 1
|
// Notify creator about group completion AND next group approvers
|
||||||
go s.sendStepApprovalNotifications(context.Background(), letterID, letter.Subject, nextStepOrder)
|
creatorMessage := fmt.Sprintf("Surat keluar '%s' telah disetujui pada grup %d, menunggu persetujuan grup berikutnya", letter.Subject, currentApproval.ParallelGroup)
|
||||||
|
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Disetujui Grup "+fmt.Sprintf("%d", currentApproval.ParallelGroup), creatorMessage)
|
||||||
|
|
||||||
|
// Notify next parallel group approvers
|
||||||
|
go s.sendParallelGroupApprovalNotifications(context.Background(), letterID, letter.Subject, nextParallelGroup)
|
||||||
|
} else {
|
||||||
|
// All groups completed
|
||||||
|
creatorMessage := fmt.Sprintf("Surat keluar '%s' telah selesai disetujui", letter.Subject)
|
||||||
|
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Disetujui", creatorMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -690,15 +696,14 @@ func (s *LetterOutgoingServiceImpl) RejectOutgoingLetter(ctx context.Context, le
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find user's pending approval
|
||||||
var currentApproval *entities.LetterOutgoingApproval
|
var currentApproval *entities.LetterOutgoingApproval
|
||||||
for i := range approvals {
|
for i := range approvals {
|
||||||
if approvals[i].Status == entities.ApprovalStatusPending {
|
if approvals[i].Status == entities.ApprovalStatusPending &&
|
||||||
step := approvals[i].Step
|
approvals[i].ApproverID != nil &&
|
||||||
if (step.ApproverUserID != nil && *step.ApproverUserID == userID) ||
|
*approvals[i].ApproverID == userID {
|
||||||
(step.ApproverRoleID != nil && userHasRole(ctx, *step.ApproverRoleID)) {
|
currentApproval = &approvals[i]
|
||||||
currentApproval = &approvals[i]
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,7 +720,7 @@ func (s *LetterOutgoingServiceImpl) RejectOutgoingLetter(ctx context.Context, le
|
|||||||
|
|
||||||
// Send notification to letter creator (rejection always notifies creator)
|
// Send notification to letter creator (rejection always notifies creator)
|
||||||
if s.notificationProcessor != nil {
|
if s.notificationProcessor != nil {
|
||||||
message := fmt.Sprintf("Surat keluar '%s' ditolak pada tahap %d dengan alasan: %s", letter.Subject, currentApproval.StepOrder, req.Reason)
|
message := fmt.Sprintf("Surat keluar '%s' ditolak pada grup %d dengan alasan: %s", letter.Subject, currentApproval.ParallelGroup, req.Reason)
|
||||||
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Ditolak", message)
|
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Ditolak", message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -997,69 +1002,20 @@ func (s *LetterOutgoingServiceImpl) GetLetterApprovalInfo(ctx context.Context, l
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group approvals by step order and parallel group to understand the workflow
|
// Simple check: can user approve if they have a pending approval
|
||||||
approvalsByStepAndGroup := make(map[int]map[int][]entities.LetterOutgoingApproval)
|
|
||||||
for _, approval := range approvals {
|
|
||||||
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 canApprove bool
|
var canApprove bool
|
||||||
|
var userApproval *entities.LetterOutgoingApproval
|
||||||
|
|
||||||
// Find the minimum step order that has pending approvals
|
for i := range approvals {
|
||||||
for stepOrder, groupApprovals := range approvalsByStepAndGroup {
|
approval := approvals[i]
|
||||||
stepHasPending := false
|
|
||||||
|
|
||||||
// Check each parallel group in this step
|
// Check if this approval is pending and belongs to the current user
|
||||||
for _, groupMembers := range groupApprovals {
|
if approval.Status == entities.ApprovalStatusPending &&
|
||||||
groupHasPending := false
|
approval.ApproverID != nil &&
|
||||||
var userApprovalInGroup *entities.LetterOutgoingApproval
|
*approval.ApproverID == userID {
|
||||||
|
canApprove = true
|
||||||
// Check if this group has pending approvals and if user is in this group
|
userApproval = &approval
|
||||||
for i := range groupMembers {
|
break
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1933,6 +1889,80 @@ func (s *LetterOutgoingServiceImpl) sendApprovalNotificationToCreator(ctx contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to get the next parallel group number (handles non-sequential groups)
|
||||||
|
func (s *LetterOutgoingServiceImpl) getNextParallelGroup(approvals []entities.LetterOutgoingApproval, currentGroup int) int {
|
||||||
|
// Collect all unique parallel groups
|
||||||
|
groupsMap := make(map[int]bool)
|
||||||
|
for _, approval := range approvals {
|
||||||
|
groupsMap[approval.ParallelGroup] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to sorted slice
|
||||||
|
var groups []int
|
||||||
|
for group := range groupsMap {
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
sort.Ints(groups)
|
||||||
|
|
||||||
|
// Find the next group after current
|
||||||
|
for _, group := range groups {
|
||||||
|
if group > currentGroup {
|
||||||
|
// Check if this group has any pending approvals
|
||||||
|
for _, approval := range approvals {
|
||||||
|
if approval.ParallelGroup == group && approval.Status == entities.ApprovalStatusNotStarted {
|
||||||
|
return group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 // No next group
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notifications to approvers in a specific parallel group
|
||||||
|
func (s *LetterOutgoingServiceImpl) sendParallelGroupApprovalNotifications(ctx context.Context, letterID uuid.UUID, subject string, parallelGroup int) {
|
||||||
|
log.Printf("[DEBUG] sendParallelGroupApprovalNotifications START - LetterID: %s, ParallelGroup: %d", letterID.String(), parallelGroup)
|
||||||
|
|
||||||
|
// Get the letter to know the current revision
|
||||||
|
letter, err := s.processor.GetOutgoingLetterByID(ctx, letterID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to get letter: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get approvals for the current revision only
|
||||||
|
approvals, err := s.processor.GetApprovalsByLetterAndRevision(ctx, letterID, letter.RevisionNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to get approvals: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Found %d approvals", len(approvals))
|
||||||
|
|
||||||
|
// Find approvers for the specified parallel group
|
||||||
|
for _, approval := range approvals {
|
||||||
|
log.Printf("[DEBUG] Checking approval: ParallelGroup=%d, Status=%s, ApproverID=%v",
|
||||||
|
approval.ParallelGroup, approval.Status, approval.ApproverID)
|
||||||
|
|
||||||
|
if approval.ParallelGroup == parallelGroup && approval.ApproverID != nil {
|
||||||
|
log.Printf("[DEBUG] Sending notification to approver %s for parallel group %d", approval.ApproverID.String(), parallelGroup)
|
||||||
|
|
||||||
|
err := s.notificationProcessor.SendOutgoingLetterNotification(
|
||||||
|
ctx,
|
||||||
|
letterID,
|
||||||
|
*approval.ApproverID,
|
||||||
|
"Surat Keluar Perlu Persetujuan",
|
||||||
|
fmt.Sprintf("Surat keluar '%s' memerlukan persetujuan Anda pada grup %d", subject, parallelGroup))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to send notification to approver %s: %v", approval.ApproverID.String(), err)
|
||||||
|
} else {
|
||||||
|
log.Printf("[DEBUG] Successfully sent notification to approver %s", approval.ApproverID.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *LetterOutgoingServiceImpl) sendOutgoingDiscussionMentionNotifications(ctx context.Context, letterID uuid.UUID, senderUserID uuid.UUID, mentions map[string]interface{}, message string) {
|
func (s *LetterOutgoingServiceImpl) sendOutgoingDiscussionMentionNotifications(ctx context.Context, letterID uuid.UUID, senderUserID uuid.UUID, mentions map[string]interface{}, message string) {
|
||||||
log.Printf("[DEBUG] sendOutgoingDiscussionMentionNotifications START - LetterID: %s", letterID.String())
|
log.Printf("[DEBUG] sendOutgoingDiscussionMentionNotifications START - LetterID: %s", letterID.String())
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user