surat keluar approval
This commit is contained in:
parent
acb9f75a18
commit
646af36795
@ -401,6 +401,7 @@ func (a *App) initServices(processors *processors, repos *repositories, cfg *con
|
|||||||
processors.letterApprovalProcessor,
|
processors.letterApprovalProcessor,
|
||||||
processors.letterAttachmentProcessor,
|
processors.letterAttachmentProcessor,
|
||||||
processors.letterOutgoingRecipientProcessor,
|
processors.letterOutgoingRecipientProcessor,
|
||||||
|
processors.notificationProcessor,
|
||||||
processors.letterActivityProcessor,
|
processors.letterActivityProcessor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ type NotificationProcessor interface {
|
|||||||
|
|
||||||
// Letter notifications
|
// Letter notifications
|
||||||
SendIncomingLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error
|
SendIncomingLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error
|
||||||
|
SendOutgoingLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationProcessorImpl struct {
|
type NotificationProcessorImpl struct {
|
||||||
@ -359,3 +360,30 @@ func (p *NovuProvider) SendNotification(ctx context.Context, payload Notificatio
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *NotificationProcessorImpl) SendOutgoingLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error {
|
||||||
|
// Ensure subscriber exists
|
||||||
|
if err := p.provider.EnsureSubscriberExists(ctx, recipientUserID); err != nil {
|
||||||
|
return fmt.Errorf("failed to ensure subscriber exists: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build notification URL for outgoing letters
|
||||||
|
url := fmt.Sprintf("/en/apps/surat-menyurat/keluar-detail/%s", letterID.String())
|
||||||
|
|
||||||
|
// Use workflow ID from config (defaults to "notification-dashbpard")
|
||||||
|
workflowID := p.workflowID
|
||||||
|
if workflowID == "" {
|
||||||
|
workflowID = "notification-dashbpard"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
return p.provider.SendNotification(ctx, NotificationPayload{
|
||||||
|
RecipientID: recipientUserID,
|
||||||
|
EventName: workflowID,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"subject": subject,
|
||||||
|
"body": body,
|
||||||
|
"url": url,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ type LetterOutgoingServiceImpl struct {
|
|||||||
approvalProcessor processor.LetterApprovalProcessor
|
approvalProcessor processor.LetterApprovalProcessor
|
||||||
attachmentProcessor processor.LetterAttachmentProcessor
|
attachmentProcessor processor.LetterAttachmentProcessor
|
||||||
recipientProcessor processor.LetterOutgoingRecipientProcessor
|
recipientProcessor processor.LetterOutgoingRecipientProcessor
|
||||||
|
notificationProcessor processor.NotificationProcessor
|
||||||
activityProcessor processor.LetterActivityProcessor
|
activityProcessor processor.LetterActivityProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +73,7 @@ func NewLetterOutgoingService(
|
|||||||
approvalProcessor processor.LetterApprovalProcessor,
|
approvalProcessor processor.LetterApprovalProcessor,
|
||||||
attachmentProcessor processor.LetterAttachmentProcessor,
|
attachmentProcessor processor.LetterAttachmentProcessor,
|
||||||
recipientProcessor processor.LetterOutgoingRecipientProcessor,
|
recipientProcessor processor.LetterOutgoingRecipientProcessor,
|
||||||
|
notificationProcessor processor.NotificationProcessor,
|
||||||
activityProcessor processor.LetterActivityProcessor,
|
activityProcessor processor.LetterActivityProcessor,
|
||||||
) *LetterOutgoingServiceImpl {
|
) *LetterOutgoingServiceImpl {
|
||||||
return &LetterOutgoingServiceImpl{
|
return &LetterOutgoingServiceImpl{
|
||||||
@ -81,6 +84,7 @@ func NewLetterOutgoingService(
|
|||||||
approvalProcessor: approvalProcessor,
|
approvalProcessor: approvalProcessor,
|
||||||
attachmentProcessor: attachmentProcessor,
|
attachmentProcessor: attachmentProcessor,
|
||||||
recipientProcessor: recipientProcessor,
|
recipientProcessor: recipientProcessor,
|
||||||
|
notificationProcessor: notificationProcessor,
|
||||||
activityProcessor: activityProcessor,
|
activityProcessor: activityProcessor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,6 +172,15 @@ func (s *LetterOutgoingServiceImpl) CreateOutgoingLetter(ctx context.Context, re
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send notifications if letter needs approval
|
||||||
|
log.Printf("[DEBUG] createOutgoingLetter Finsig")
|
||||||
|
log.Printf("[DEBUG] NotificationProcessor is nil: %v", s.notificationProcessor == nil)
|
||||||
|
if s.notificationProcessor != nil && len(result.Approvals) > 0 {
|
||||||
|
log.Printf("[DEBUG] sendFirstStepApprovalNotifications start")
|
||||||
|
go s.sendStepApprovalNotifications(context.Background(), result.ID, result.Subject, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return transformLetterToResponse(result), nil
|
return transformLetterToResponse(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +470,24 @@ func (s *LetterOutgoingServiceImpl) ApproveOutgoingLetter(ctx context.Context, l
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.processor.ProcessApproval(ctx, letterID, currentApproval, userID, allApproved)
|
err = s.processor.ProcessApproval(ctx, letterID, currentApproval, userID, allApproved)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notifications after successful approval
|
||||||
|
if s.notificationProcessor != nil {
|
||||||
|
// Step approved but not final - notify creator about step completion AND next approvers
|
||||||
|
creatorMessage := fmt.Sprintf("Surat keluar '%s' telah disetujui pada tahap %d, menunggu persetujuan tahap berikutnya", letter.Subject, currentApproval.StepOrder)
|
||||||
|
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Disetujui Tahap " + fmt.Sprintf("%d", currentApproval.StepOrder), creatorMessage)
|
||||||
|
|
||||||
|
// Notify next step approvers
|
||||||
|
nextStepOrder := currentApproval.StepOrder + 1
|
||||||
|
go s.sendStepApprovalNotifications(context.Background(), letterID, letter.Subject, nextStepOrder)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LetterOutgoingServiceImpl) RejectOutgoingLetter(ctx context.Context, letterID uuid.UUID, req *contract.RejectLetterRequest) error {
|
func (s *LetterOutgoingServiceImpl) RejectOutgoingLetter(ctx context.Context, letterID uuid.UUID, req *contract.RejectLetterRequest) error {
|
||||||
@ -495,7 +525,18 @@ func (s *LetterOutgoingServiceImpl) RejectOutgoingLetter(ctx context.Context, le
|
|||||||
|
|
||||||
currentApproval.Remarks = &req.Reason
|
currentApproval.Remarks = &req.Reason
|
||||||
|
|
||||||
return s.processor.ProcessRejection(ctx, letterID, currentApproval, userID)
|
err = s.processor.ProcessRejection(ctx, letterID, currentApproval, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notification to letter creator (rejection always notifies creator)
|
||||||
|
if s.notificationProcessor != nil {
|
||||||
|
message := fmt.Sprintf("Surat keluar '%s' ditolak pada tahap %d dengan alasan: %s", letter.Subject, currentApproval.StepOrder, req.Reason)
|
||||||
|
go s.sendApprovalNotificationToCreator(context.Background(), letterID, letter.CreatedBy, "Surat Keluar Ditolak", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LetterOutgoingServiceImpl) SendOutgoingLetter(ctx context.Context, letterID uuid.UUID) error {
|
func (s *LetterOutgoingServiceImpl) SendOutgoingLetter(ctx context.Context, letterID uuid.UUID) error {
|
||||||
@ -1539,3 +1580,56 @@ func (s *LetterOutgoingServiceImpl) BulkArchiveOutgoingLetters(ctx context.Conte
|
|||||||
ArchivedCount: int(archivedCount),
|
ArchivedCount: int(archivedCount),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *LetterOutgoingServiceImpl) sendStepApprovalNotifications(ctx context.Context, letterID uuid.UUID, subject string, stepOrder int) {
|
||||||
|
log.Printf("[DEBUG] sendStepApprovalNotifications START - LetterID: %s, StepOrder: %d", letterID.String(), stepOrder)
|
||||||
|
|
||||||
|
approvals, err := s.processor.GetApprovalsByLetter(ctx, letterID)
|
||||||
|
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 step
|
||||||
|
for _, approval := range approvals {
|
||||||
|
log.Printf("[DEBUG] Checking approval: Step=%d, Status=%s, ApproverID=%v",
|
||||||
|
approval.StepOrder, approval.Status, approval.ApproverID)
|
||||||
|
|
||||||
|
if approval.StepOrder == stepOrder {
|
||||||
|
log.Printf("[DEBUG] Sending notification to approver %s for step %d", approval.ApproverID.String(), stepOrder)
|
||||||
|
|
||||||
|
err := s.notificationProcessor.SendOutgoingLetterNotification(
|
||||||
|
ctx,
|
||||||
|
letterID,
|
||||||
|
*approval.ApproverID,
|
||||||
|
"Surat Keluar Perlu Persetujuan",
|
||||||
|
fmt.Sprintf("Surat keluar '%s' memerlukan persetujuan Anda pada tahap %d", subject, stepOrder))
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kirim notifikasi ke creator
|
||||||
|
func (s *LetterOutgoingServiceImpl) sendApprovalNotificationToCreator(ctx context.Context, letterID uuid.UUID, creatorID uuid.UUID, title string, message string) {
|
||||||
|
log.Printf("[DEBUG] sendApprovalNotificationToCreator START - LetterID: %s, CreatorID: %s", letterID.String(), creatorID.String())
|
||||||
|
|
||||||
|
err := s.notificationProcessor.SendOutgoingLetterNotification(
|
||||||
|
ctx,
|
||||||
|
letterID,
|
||||||
|
creatorID,
|
||||||
|
title,
|
||||||
|
message)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to send notification to creator %s: %v", creatorID.String(), err)
|
||||||
|
} else {
|
||||||
|
log.Printf("[DEBUG] Successfully sent notification to creator %s", creatorID.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user