update api incoming letter

This commit is contained in:
efrilm 2025-10-17 00:04:21 +07:00
parent 58128495a6
commit 92440953cb
5 changed files with 128 additions and 59 deletions

View File

@ -7,19 +7,19 @@ import (
) )
type SearchIncomingLettersRequest struct { type SearchIncomingLettersRequest struct {
Query string `json:"query" form:"query"` Query string `json:"query" form:"query"`
LetterNumber string `json:"letter_number" form:"letter_number"` LetterNumber string `json:"letter_number" form:"letter_number"`
Subject string `json:"subject" form:"subject"` Subject string `json:"subject" form:"subject"`
Status string `json:"status" form:"status"` Status string `json:"status" form:"status"`
PriorityID *uuid.UUID `json:"priority_id" form:"priority_id"` PriorityID *uuid.UUID `json:"priority_id" form:"priority_id"`
InstitutionID *uuid.UUID `json:"institution_id" form:"institution_id"` InstitutionID *uuid.UUID `json:"institution_id" form:"institution_id"`
CreatedBy *uuid.UUID `json:"created_by" form:"created_by"` CreatedBy *uuid.UUID `json:"created_by" form:"created_by"`
DateFrom *time.Time `json:"date_from" form:"date_from"` DateFrom *time.Time `json:"date_from" form:"date_from"`
DateTo *time.Time `json:"date_to" form:"date_to"` DateTo *time.Time `json:"date_to" form:"date_to"`
Page int `json:"page" form:"page"` Page int `json:"page" form:"page"`
Limit int `json:"limit" form:"limit"` Limit int `json:"limit" form:"limit"`
SortBy string `json:"sort_by" form:"sort_by"` SortBy string `json:"sort_by" form:"sort_by"`
SortOrder string `json:"sort_order" form:"sort_order"` SortOrder string `json:"sort_order" form:"sort_order"`
} }
type SearchIncomingLettersResponse struct { type SearchIncomingLettersResponse struct {
@ -77,6 +77,7 @@ type IncomingLetterResponse struct {
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Attachments []IncomingLetterAttachmentResponse `json:"attachments"` Attachments []IncomingLetterAttachmentResponse `json:"attachments"`
IsRead bool `json:"is_read"` IsRead bool `json:"is_read"`
Dispositions []EnhancedDispositionResponse `json:"dispositions"`
} }
type UpdateIncomingLetterRequest struct { type UpdateIncomingLetterRequest struct {

View File

@ -101,6 +101,7 @@ func (p *LetterProcessorImpl) GetIncomingLetterByID(ctx context.Context, id uuid
return nil, err return nil, err
} }
atts, _ := p.attachRepo.ListByLetter(ctx, id) atts, _ := p.attachRepo.ListByLetter(ctx, id)
dispo, _ := p.dispositionRepo.ListByLetter(ctx, id)
var pr *entities.Priority var pr *entities.Priority
if entity.PriorityID != nil && p.priorityRepo != nil { if entity.PriorityID != nil && p.priorityRepo != nil {
if got, err := p.priorityRepo.Get(ctx, *entity.PriorityID); err == nil { if got, err := p.priorityRepo.Get(ctx, *entity.PriorityID); err == nil {
@ -119,10 +120,11 @@ func (p *LetterProcessorImpl) GetIncomingLetterByID(ctx context.Context, id uuid
if p.recipientRepo != nil { if p.recipientRepo != nil {
if recipient, err := p.recipientRepo.GetByLetterAndUser(ctx, id, userID); err == nil { if recipient, err := p.recipientRepo.GetByLetterAndUser(ctx, id, userID); err == nil {
isRead = recipient.ReadAt != nil isRead = recipient.ReadAt != nil
fmt.Printf("Recipient: %+v\n", recipient)
} }
} }
resp := transformer.LetterEntityToContract(entity, atts, pr, inst) resp := transformer.LetterEntityToContract(entity, atts, dispo, pr, inst)
resp.IsRead = isRead resp.IsRead = isRead
// Include created_by if the current user is the creator // Include created_by if the current user is the creator
@ -209,6 +211,13 @@ func (p *LetterProcessorImpl) GetBatchAttachments(ctx context.Context, letterIDs
return p.attachRepo.ListByLetterIDs(ctx, letterIDs) return p.attachRepo.ListByLetterIDs(ctx, letterIDs)
} }
func (p *LetterProcessorImpl) GetBatchDispositions(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingDisposition, error) {
if p.dispositionRepo == nil || len(letterIDs) == 0 {
return make(map[uuid.UUID][]entities.LetterIncomingDisposition), nil
}
return p.dispositionRepo.ListByLetterIDs(ctx, letterIDs)
}
func (p *LetterProcessorImpl) GetBatchPriorities(ctx context.Context, priorityIDs []uuid.UUID) (map[uuid.UUID]*entities.Priority, error) { func (p *LetterProcessorImpl) GetBatchPriorities(ctx context.Context, priorityIDs []uuid.UUID) (map[uuid.UUID]*entities.Priority, error) {
if p.priorityRepo == nil || len(priorityIDs) == 0 { if p.priorityRepo == nil || len(priorityIDs) == 0 {
return make(map[uuid.UUID]*entities.Priority), nil return make(map[uuid.UUID]*entities.Priority), nil
@ -290,6 +299,7 @@ func (p *LetterProcessorImpl) UpdateIncomingLetter(ctx context.Context, id uuid.
} }
} }
atts, _ := p.attachRepo.ListByLetter(txCtx, id) atts, _ := p.attachRepo.ListByLetter(txCtx, id)
dispo, _ := p.dispositionRepo.ListByLetter(txCtx, id)
var pr *entities.Priority var pr *entities.Priority
if entity.PriorityID != nil && p.priorityRepo != nil { if entity.PriorityID != nil && p.priorityRepo != nil {
if got, err := p.priorityRepo.Get(txCtx, *entity.PriorityID); err == nil { if got, err := p.priorityRepo.Get(txCtx, *entity.PriorityID); err == nil {
@ -302,7 +312,7 @@ func (p *LetterProcessorImpl) UpdateIncomingLetter(ctx context.Context, id uuid.
inst = got inst = got
} }
} }
out = transformer.LetterEntityToContract(entity, atts, pr, inst) out = transformer.LetterEntityToContract(entity, atts, dispo, pr, inst)
return nil return nil
}) })
if err != nil { if err != nil {
@ -601,6 +611,7 @@ func (p *LetterProcessorImpl) SearchIncomingLetters(ctx context.Context, filters
func (p *LetterProcessorImpl) buildLetterResponse(ctx context.Context, entity *entities.LetterIncoming) (*contract.IncomingLetterResponse, error) { func (p *LetterProcessorImpl) buildLetterResponse(ctx context.Context, entity *entities.LetterIncoming) (*contract.IncomingLetterResponse, error) {
savedAttachments, _ := p.attachRepo.ListByLetter(ctx, entity.ID) savedAttachments, _ := p.attachRepo.ListByLetter(ctx, entity.ID)
dispo, _ := p.dispositionRepo.ListByLetter(ctx, entity.ID)
var pr *entities.Priority var pr *entities.Priority
if entity.PriorityID != nil && p.priorityRepo != nil { if entity.PriorityID != nil && p.priorityRepo != nil {
@ -616,7 +627,7 @@ func (p *LetterProcessorImpl) buildLetterResponse(ctx context.Context, entity *e
} }
} }
return transformer.LetterEntityToContract(entity, savedAttachments, pr, inst), nil return transformer.LetterEntityToContract(entity, savedAttachments, dispo, pr, inst), nil
} }
func (p *LetterProcessorImpl) BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (int64, error) { func (p *LetterProcessorImpl) BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (int64, error) {

View File

@ -463,6 +463,33 @@ func (r *LetterIncomingDispositionRepository) ListByLetter(ctx context.Context,
return list, nil return list, nil
} }
func (r *LetterIncomingDispositionRepository) ListByLetterIDs(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingDisposition, error) {
if len(letterIDs) == 0 {
return make(map[uuid.UUID][]entities.LetterIncomingDisposition), nil
}
db := DBFromContext(ctx, r.db)
var dispositions []entities.LetterIncomingDisposition
if err := db.WithContext(ctx).Where("letter_id IN ?", letterIDs).
Preload("Department").
Preload("Departments.Department").
Preload("ActionSelections.Action").
Preload("DispositionNotes.User").
Order("created_at ASC").
Find(&dispositions).Error; err != nil {
return nil, err
}
// Group by letter ID
result := make(map[uuid.UUID][]entities.LetterIncomingDisposition)
for i := range dispositions { // Gunakan index, bukan value
letterID := dispositions[i].LetterID
result[letterID] = append(result[letterID], dispositions[i])
}
return result, nil
}
func (r *LetterIncomingDispositionRepository) GetByLetterIncomingID(ctx context.Context, letterIncomingID uuid.UUID) ([]entities.LetterIncomingDisposition, error) { func (r *LetterIncomingDispositionRepository) GetByLetterIncomingID(ctx context.Context, letterIncomingID uuid.UUID) ([]entities.LetterIncomingDisposition, error) {
db := DBFromContext(ctx, r.db) db := DBFromContext(ctx, r.db)
var list []entities.LetterIncomingDisposition var list []entities.LetterIncomingDisposition

View File

@ -37,6 +37,7 @@ type LetterProcessor interface {
// Batch loading methods // Batch loading methods
GetBatchAttachments(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingAttachment, error) GetBatchAttachments(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingAttachment, error)
GetBatchDispositions(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingDisposition, error)
GetBatchPriorities(ctx context.Context, priorityIDs []uuid.UUID) (map[uuid.UUID]*entities.Priority, error) GetBatchPriorities(ctx context.Context, priorityIDs []uuid.UUID) (map[uuid.UUID]*entities.Priority, error)
GetBatchInstitutions(ctx context.Context, institutionIDs []uuid.UUID) (map[uuid.UUID]*entities.Institution, error) GetBatchInstitutions(ctx context.Context, institutionIDs []uuid.UUID) (map[uuid.UUID]*entities.Institution, error)
GetBatchRecipientsByUser(ctx context.Context, letterIDs []uuid.UUID, userID uuid.UUID) (map[uuid.UUID]*entities.LetterIncomingRecipient, error) GetBatchRecipientsByUser(ctx context.Context, letterIDs []uuid.UUID, userID uuid.UUID) (map[uuid.UUID]*entities.LetterIncomingRecipient, error)
@ -347,6 +348,7 @@ func (s *LetterServiceImpl) ListIncomingLetters(ctx context.Context, req *contra
priorities map[uuid.UUID]*entities.Priority priorities map[uuid.UUID]*entities.Priority
institutions map[uuid.UUID]*entities.Institution institutions map[uuid.UUID]*entities.Institution
recipients map[uuid.UUID]*entities.LetterIncomingRecipient recipients map[uuid.UUID]*entities.LetterIncomingRecipient
dispostions map[uuid.UUID][]entities.LetterIncomingDisposition
err error err error
} }
@ -358,9 +360,10 @@ func (s *LetterServiceImpl) ListIncomingLetters(ctx context.Context, req *contra
priorities: make(map[uuid.UUID]*entities.Priority), priorities: make(map[uuid.UUID]*entities.Priority),
institutions: make(map[uuid.UUID]*entities.Institution), institutions: make(map[uuid.UUID]*entities.Institution),
recipients: make(map[uuid.UUID]*entities.LetterIncomingRecipient), recipients: make(map[uuid.UUID]*entities.LetterIncomingRecipient),
dispostions: make(map[uuid.UUID][]entities.LetterIncomingDisposition),
} }
errChan := make(chan error, 4) errChan := make(chan error, 5)
go func() { go func() {
var err error var err error
@ -386,7 +389,13 @@ func (s *LetterServiceImpl) ListIncomingLetters(ctx context.Context, req *contra
errChan <- err errChan <- err
}() }()
for i := 0; i < 4; i++ { go func() {
var err error
result.dispostions, err = s.processor.GetBatchDispositions(ctx, letterIDs)
errChan <- err
}()
for i := 0; i < 5; i++ {
if err := <-errChan; err != nil { if err := <-errChan; err != nil {
// Batch load error, continue anyway // Batch load error, continue anyway
} }
@ -414,12 +423,17 @@ func (s *LetterServiceImpl) ListIncomingLetters(ctx context.Context, req *contra
institution = batchData.institutions[*letter.SenderInstitutionID] institution = batchData.institutions[*letter.SenderInstitutionID]
} }
dispositions := batchData.dispostions[letter.ID]
if dispositions == nil {
dispositions = []entities.LetterIncomingDisposition{}
}
isRead := false isRead := false
if recipient, exists := batchData.recipients[letter.ID]; exists && recipient != nil { if recipient, exists := batchData.recipients[letter.ID]; exists && recipient != nil {
isRead = recipient.ReadAt != nil isRead = recipient.ReadAt != nil
} }
resp := transformer.LetterEntityToContract(&letter, attachments, priority, institution) resp := transformer.LetterEntityToContract(&letter, attachments, dispositions, priority, institution)
resp.IsRead = isRead resp.IsRead = isRead
respList = append(respList, *resp) respList = append(respList, *resp)
} }
@ -697,7 +711,7 @@ func (s *LetterServiceImpl) CreateDispositions(ctx context.Context, req *contrac
if len(recipients) > 0 { if len(recipients) > 0 {
go s.sendDispositionNotifications(context.Background(), req.LetterID, recipients) go s.sendDispositionNotifications(context.Background(), req.LetterID, recipients)
} }
// Send notification to letter creator about new disposition // Send notification to letter creator about new disposition
go s.sendDispositionCreatorNotification(context.Background(), req.LetterID, userID) go s.sendDispositionCreatorNotification(context.Background(), req.LetterID, userID)
} }
@ -711,7 +725,7 @@ func (s *LetterServiceImpl) GetEnhancedDispositionsByLetter(ctx context.Context,
func (s *LetterServiceImpl) CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) { func (s *LetterServiceImpl) CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
userID := appcontext.FromGinContext(ctx).UserID userID := appcontext.FromGinContext(ctx).UserID
var result *contract.LetterDiscussionResponse var result *contract.LetterDiscussionResponse
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error { err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
var err error var err error
@ -719,34 +733,34 @@ func (s *LetterServiceImpl) CreateDiscussion(ctx context.Context, letterID uuid.
if err != nil { if err != nil {
return err return err
} }
// Log activity for discussion creation // Log activity for discussion creation
if s.activityLogger != nil && result != nil { if s.activityLogger != nil && result != nil {
if err := s.activityLogger.LogLetterDispositionStatusUpdate(txCtx, letterID, userID, "discussion_created"); err != nil { if err := s.activityLogger.LogLetterDispositionStatusUpdate(txCtx, letterID, userID, "discussion_created"); err != nil {
// Don't fail the transaction for logging errors // Don't fail the transaction for logging errors
} }
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Send notifications to mentioned users asynchronously // Send notifications to mentioned users asynchronously
if s.notificationProcessor != nil && req.Mentions != nil { if s.notificationProcessor != nil && req.Mentions != nil {
go s.sendDiscussionMentionNotifications(context.Background(), letterID, userID, req.Mentions, req.Message) go s.sendDiscussionMentionNotifications(context.Background(), letterID, userID, req.Mentions, req.Message)
} }
return result, nil return result, nil
} }
func (s *LetterServiceImpl) UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) { func (s *LetterServiceImpl) UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
userID := appcontext.FromGinContext(ctx).UserID userID := appcontext.FromGinContext(ctx).UserID
var result *contract.LetterDiscussionResponse var result *contract.LetterDiscussionResponse
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error { err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
var err error var err error
var oldMessage string var oldMessage string
@ -754,7 +768,7 @@ func (s *LetterServiceImpl) UpdateDiscussion(ctx context.Context, letterID uuid.
if err != nil { if err != nil {
return err return err
} }
// Log activity for discussion update (could use oldMessage for more detailed logging) // Log activity for discussion update (could use oldMessage for more detailed logging)
if s.activityLogger != nil && result != nil { if s.activityLogger != nil && result != nil {
// Create a simple activity log - oldMessage could be included in a more detailed log // Create a simple activity log - oldMessage could be included in a more detailed log
@ -763,14 +777,14 @@ func (s *LetterServiceImpl) UpdateDiscussion(ctx context.Context, letterID uuid.
// Don't fail the transaction for logging errors // Don't fail the transaction for logging errors
} }
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result, nil return result, nil
} }
@ -780,14 +794,14 @@ func (s *LetterServiceImpl) GetDepartmentDispositionStatus(ctx context.Context,
func (s *LetterServiceImpl) UpdateDispositionStatus(ctx context.Context, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error) { func (s *LetterServiceImpl) UpdateDispositionStatus(ctx context.Context, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error) {
var result *contract.DepartmentDispositionStatusResponse var result *contract.DepartmentDispositionStatusResponse
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error { err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
var err error var err error
result, err = s.processor.UpdateDispositionStatus(txCtx, req) result, err = s.processor.UpdateDispositionStatus(txCtx, req)
if err != nil { if err != nil {
return err return err
} }
// Log activity for disposition status update // Log activity for disposition status update
if s.activityLogger != nil && result != nil { if s.activityLogger != nil && result != nil {
userID := appcontext.FromGinContext(txCtx).UserID userID := appcontext.FromGinContext(txCtx).UserID
@ -795,19 +809,19 @@ func (s *LetterServiceImpl) UpdateDispositionStatus(ctx context.Context, req *co
// Don't fail the transaction for logging errors // Don't fail the transaction for logging errors
} }
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Send notification to letter creator asynchronously // Send notification to letter creator asynchronously
if s.notificationProcessor != nil && result != nil { if s.notificationProcessor != nil && result != nil {
go s.sendDispositionStatusUpdateNotification(context.Background(), req.LetterIncomingID, req.Status) go s.sendDispositionStatusUpdateNotification(context.Background(), req.LetterIncomingID, req.Status)
} }
return result, nil return result, nil
} }
@ -840,34 +854,34 @@ func (s *LetterServiceImpl) sendDiscussionMentionNotifications(ctx context.Conte
if len(userIDs) == 0 { if len(userIDs) == 0 {
return return
} }
// Get letter details for notification // Get letter details for notification
letter, err := s.processor.GetIncomingLetterByID(ctx, letterID) letter, err := s.processor.GetIncomingLetterByID(ctx, letterID)
if err != nil { if err != nil {
return return
} }
// Get sender user name (you might need to implement this) // Get sender user name (you might need to implement this)
appContext := appcontext.FromGinContext(ctx) appContext := appcontext.FromGinContext(ctx)
senderName := appContext.UserName // or get from user service senderName := appContext.UserName // or get from user service
// Send notification to each mentioned user // Send notification to each mentioned user
for _, mentionedUserID := range userIDs { for _, mentionedUserID := range userIDs {
// Don't send notification to the sender themselves // Don't send notification to the sender themselves
if mentionedUserID == senderUserID { if mentionedUserID == senderUserID {
continue continue
} }
subject := "Anda Disebutkan dalam Diskusi" subject := "Anda Disebutkan dalam Diskusi"
notificationMessage := fmt.Sprintf("%s menyebutkan Anda dalam diskusi surat: %s", senderName, letter.Subject) notificationMessage := fmt.Sprintf("%s menyebutkan Anda dalam diskusi surat: %s", senderName, letter.Subject)
err := s.notificationProcessor.SendIncomingLetterNotification( err := s.notificationProcessor.SendIncomingLetterNotification(
ctx, ctx,
letterID, letterID,
mentionedUserID, mentionedUserID,
subject, subject,
notificationMessage) notificationMessage)
if err != nil { if err != nil {
// Log error but continue with other notifications // Log error but continue with other notifications
} }
@ -876,7 +890,7 @@ func (s *LetterServiceImpl) sendDiscussionMentionNotifications(ctx context.Conte
func (s *LetterServiceImpl) extractUserIDsFromMentions(mentions map[string]interface{}) []uuid.UUID { func (s *LetterServiceImpl) extractUserIDsFromMentions(mentions map[string]interface{}) []uuid.UUID {
userIDs := make([]uuid.UUID, 0) userIDs := make([]uuid.UUID, 0)
if userIDsInterface, exists := mentions["user_ids"]; exists { if userIDsInterface, exists := mentions["user_ids"]; exists {
switch userIDsValue := userIDsInterface.(type) { switch userIDsValue := userIDsInterface.(type) {
case []interface{}: case []interface{}:
@ -895,7 +909,7 @@ func (s *LetterServiceImpl) extractUserIDsFromMentions(mentions map[string]inter
} }
} }
} }
return userIDs return userIDs
} }
@ -909,8 +923,6 @@ func (s *LetterServiceImpl) sendDispositionCreatorNotification(ctx context.Conte
fmt.Printf("[DEBUG] Starting sendDispositionCreatorNotification for letterID: %s\n", letterID.String()) fmt.Printf("[DEBUG] Starting sendDispositionCreatorNotification for letterID: %s\n", letterID.String())
fmt.Printf("[DEBUG] Successfully retrieved letter: %s\n", letter.Subject) fmt.Printf("[DEBUG] Successfully retrieved letter: %s\n", letter.Subject)
fmt.Printf("[DEBUG] Successfully retrieved letter: %s\n", letter.CreatedBy) fmt.Printf("[DEBUG] Successfully retrieved letter: %s\n", letter.CreatedBy)
letterCreatorID := letter.CreatedBy letterCreatorID := letter.CreatedBy
@ -924,7 +936,7 @@ func (s *LetterServiceImpl) sendDispositionCreatorNotification(ctx context.Conte
dispositionCreatorName := appContext.UserName dispositionCreatorName := appContext.UserName
subject := "Disposisi Baru pada Surat Anda" subject := "Disposisi Baru pada Surat Anda"
message := fmt.Sprintf("Surat yang Anda buat telah didisposisikan %s: %s", message := fmt.Sprintf("Surat yang Anda buat telah didisposisikan %s: %s",
dispositionCreatorName, letter.Subject) dispositionCreatorName, letter.Subject)
err = s.notificationProcessor.SendIncomingLetterNotification( err = s.notificationProcessor.SendIncomingLetterNotification(
@ -947,19 +959,19 @@ func (s *LetterServiceImpl) sendDispositionStatusUpdateNotification(ctx context.
// Log error but don't fail // Log error but don't fail
return return
} }
// Get current user context (the one updating the status) // Get current user context (the one updating the status)
appContext := appcontext.FromGinContext(ctx) appContext := appcontext.FromGinContext(ctx)
updaterUserID := appContext.UserID updaterUserID := appContext.UserID
updaterName := appContext.UserName updaterName := appContext.UserName
letterCreatorID := letter.CreatedBy letterCreatorID := letter.CreatedBy
// Don't send notification if the updater is the same as letter creator // Don't send notification if the updater is the same as letter creator
if letterCreatorID == updaterUserID { if letterCreatorID == updaterUserID {
return return
} }
// Create status-specific notification message // Create status-specific notification message
var statusMessage string var statusMessage string
switch newStatus { switch newStatus {
@ -974,20 +986,20 @@ func (s *LetterServiceImpl) sendDispositionStatusUpdateNotification(ctx context.
default: default:
statusMessage = fmt.Sprintf("diubah statusnya menjadi %s", newStatus) statusMessage = fmt.Sprintf("diubah statusnya menjadi %s", newStatus)
} }
subject := "Status Disposisi Surat Diperbarui" subject := "Status Disposisi Surat Diperbarui"
message := fmt.Sprintf("Disposisi surat '%s' %s %s", message := fmt.Sprintf("Disposisi surat '%s' %s %s",
letter.Subject, statusMessage, updaterName) letter.Subject, statusMessage, updaterName)
err = s.notificationProcessor.SendIncomingLetterNotification( err = s.notificationProcessor.SendIncomingLetterNotification(
ctx, ctx,
letterID, letterID,
letterCreatorID, letterCreatorID,
subject, subject,
message) message)
if err != nil { if err != nil {
// Log error but don't fail the operation // Log error but don't fail the operation
// You might want to add proper logging here // You might want to add proper logging here
} }
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
func LetterEntityToContract(e *entities.LetterIncoming, attachments []entities.LetterIncomingAttachment, refs ...interface{}) *contract.IncomingLetterResponse { func LetterEntityToContract(e *entities.LetterIncoming, attachments []entities.LetterIncomingAttachment, dispositions []entities.LetterIncomingDisposition, refs ...interface{}) *contract.IncomingLetterResponse {
resp := &contract.IncomingLetterResponse{ resp := &contract.IncomingLetterResponse{
ID: e.ID, ID: e.ID,
LetterNumber: e.LetterNumber, LetterNumber: e.LetterNumber,
@ -24,6 +24,7 @@ func LetterEntityToContract(e *entities.LetterIncoming, attachments []entities.L
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
Attachments: make([]contract.IncomingLetterAttachmentResponse, 0, len(attachments)), Attachments: make([]contract.IncomingLetterAttachmentResponse, 0, len(attachments)),
Dispositions: make([]contract.EnhancedDispositionResponse, 0, len(dispositions)),
} }
// optional refs: allow passing already-fetched related objects // optional refs: allow passing already-fetched related objects
@ -65,6 +66,23 @@ func LetterEntityToContract(e *entities.LetterIncoming, attachments []entities.L
UploadedAt: a.UploadedAt, UploadedAt: a.UploadedAt,
}) })
} }
for _, d := range dispositions {
resp.Dispositions = append(resp.Dispositions, contract.EnhancedDispositionResponse{
ID: d.ID,
LetterID: d.LetterID,
DepartmentID: d.DepartmentID,
Notes: d.Notes,
ReadAt: d.ReadAt,
CreatedBy: d.CreatedBy,
CreatedAt: d.CreatedAt,
UpdatedAt: d.UpdatedAt,
Departments: DispositionDepartmentsWithDetailsToContract(d.Departments),
Actions: DispositionActionSelectionsWithDetailsToContract(d.ActionSelections),
DispositionNotes: DispositionNotesWithDetailsToContract(d.DispositionNotes),
Department: DepartmentToContract(d.Department),
})
}
return resp return resp
} }