593 lines
20 KiB
Go
593 lines
20 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"eslogad-be/internal/appcontext"
|
|
"eslogad-be/internal/constant"
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/entities"
|
|
"eslogad-be/internal/processor"
|
|
"eslogad-be/internal/repository"
|
|
"eslogad-be/internal/transformer"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
DefaultIncomingLetterID = "ESLI"
|
|
)
|
|
|
|
type LetterProcessor interface {
|
|
CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
|
|
GetIncomingLetterByID(ctx context.Context, id uuid.UUID) (*contract.IncomingLetterResponse, error)
|
|
ListIncomingLetters(ctx context.Context, filter repository.ListIncomingLettersFilter, page, limit int) ([]entities.LetterIncoming, int64, error)
|
|
GetLetterUnreadCounts(ctx context.Context) (*contract.LetterUnreadCountResponse, error)
|
|
MarkIncomingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error)
|
|
MarkOutgoingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error)
|
|
UpdateIncomingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
|
|
SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error
|
|
BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (int64, error)
|
|
BulkArchiveIncomingLettersForUser(ctx context.Context, letterIDs []uuid.UUID, userID uuid.UUID) (int64, error)
|
|
|
|
// Batch loading methods
|
|
GetBatchAttachments(ctx context.Context, letterIDs []uuid.UUID) (map[uuid.UUID][]entities.LetterIncomingAttachment, 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)
|
|
GetBatchRecipientsByUser(ctx context.Context, letterIDs []uuid.UUID, userID uuid.UUID) (map[uuid.UUID]*entities.LetterIncomingRecipient, error)
|
|
CountUnreadByUser(ctx context.Context, userID uuid.UUID) (int, error)
|
|
|
|
CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error)
|
|
GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error)
|
|
|
|
CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
|
|
UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, string, error)
|
|
|
|
GetDepartmentDispositionStatus(ctx context.Context, req *contract.GetDepartmentDispositionStatusRequest) (*contract.ListDepartmentDispositionStatusResponse, error)
|
|
UpdateDispositionStatus(ctx context.Context, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error)
|
|
|
|
GetLetterCTA(ctx context.Context, letterID uuid.UUID, departmentID uuid.UUID) (*contract.LetterCTAResponse, error)
|
|
}
|
|
|
|
type LetterServiceImpl struct {
|
|
processor LetterProcessor
|
|
txManager *repository.TxManager
|
|
numberGenerator NumberGenerator
|
|
recipientProcessor RecipientProcessor
|
|
activityLogger ActivityLogger
|
|
letterDispositionProcessor LetterDispositionProcessor
|
|
notificationProcessor processor.NotificationProcessor
|
|
activityProcessor ActivityLogger
|
|
}
|
|
|
|
type NumberGenerator interface {
|
|
GenerateNumber(ctx context.Context, prefixKey, sequenceKey, defaultPrefix string) (string, error)
|
|
}
|
|
|
|
type RecipientProcessor interface {
|
|
CreateDefaultRecipients(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingRecipient, error)
|
|
CreateRecipients(ctx context.Context, letterID uuid.UUID, departmentIDs []uuid.UUID) ([]entities.LetterIncomingRecipient, error)
|
|
CreateSingleRecipient(ctx context.Context, recipient *entities.LetterIncomingRecipient) error
|
|
}
|
|
|
|
type ActivityLogger interface {
|
|
LogLetterCreated(ctx context.Context, letterID uuid.UUID, userID uuid.UUID, letterNumber string) error
|
|
LogAttachmentUploaded(ctx context.Context, letterID uuid.UUID, userID uuid.UUID, fileName string, fileType string) error
|
|
LogLetterDispositionStatusUpdate(ctx context.Context, letterID uuid.UUID, userID uuid.UUID, status string) error
|
|
}
|
|
|
|
type LetterDispositionProcessor interface {
|
|
CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error)
|
|
}
|
|
|
|
func NewLetterService(
|
|
processor LetterProcessor,
|
|
txManager *repository.TxManager,
|
|
numberGenerator NumberGenerator,
|
|
recipientProcessor RecipientProcessor,
|
|
activityLogger ActivityLogger,
|
|
letterDispositionProcessor LetterDispositionProcessor,
|
|
notificationProcessor processor.NotificationProcessor,
|
|
activityProc ActivityLogger,
|
|
) *LetterServiceImpl {
|
|
return &LetterServiceImpl{
|
|
processor: processor,
|
|
txManager: txManager,
|
|
numberGenerator: numberGenerator,
|
|
recipientProcessor: recipientProcessor,
|
|
activityLogger: activityLogger,
|
|
letterDispositionProcessor: letterDispositionProcessor,
|
|
notificationProcessor: notificationProcessor,
|
|
activityProcessor: activityProc,
|
|
}
|
|
}
|
|
|
|
func (s *LetterServiceImpl) CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error) {
|
|
var result *contract.IncomingLetterResponse
|
|
var recipients []entities.LetterIncomingRecipient
|
|
|
|
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
letterNumber, err := s.generateLetterNumber(txCtx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.LetterNumber = letterNumber
|
|
|
|
result, err = s.processor.CreateIncomingLetter(txCtx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
recipients, err = s.createDefaultRecipients(txCtx, result.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := s.createDispositionsForRecipients(txCtx, result.ID, recipients); err != nil {
|
|
return err
|
|
}
|
|
|
|
s.logLetterCreation(txCtx, result.ID, letterNumber)
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if s.notificationProcessor != nil && len(recipients) > 0 {
|
|
go s.sendLetterNotifications(context.Background(), result, recipients)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) generateLetterNumber(ctx context.Context) (string, error) {
|
|
return s.numberGenerator.GenerateNumber(
|
|
ctx,
|
|
contract.SettingIncomingLetterPrefix,
|
|
contract.SettingIncomingLetterSequence,
|
|
DefaultIncomingLetterID,
|
|
)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) createDefaultRecipients(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingRecipient, error) {
|
|
return s.recipientProcessor.CreateDefaultRecipients(ctx, letterID)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) createDispositionsForRecipients(ctx context.Context, letterID uuid.UUID, recipients []entities.LetterIncomingRecipient) error {
|
|
if len(recipients) == 0 || s.letterDispositionProcessor == nil {
|
|
return nil
|
|
}
|
|
|
|
departmentIDs := s.extractUniqueDepartmentIDs(recipients)
|
|
if len(departmentIDs) == 0 {
|
|
return nil
|
|
}
|
|
|
|
systemDeptID := constant.SystemDepartmentID
|
|
systemUserID := constant.SystemUserID
|
|
|
|
dispositionReq := &contract.CreateLetterDispositionRequest{
|
|
FromDepartment: systemDeptID,
|
|
LetterID: letterID,
|
|
ToDepartmentIDs: departmentIDs,
|
|
Notes: nil,
|
|
CreatedBy: systemUserID,
|
|
}
|
|
|
|
_, err := s.letterDispositionProcessor.CreateDispositions(ctx, dispositionReq)
|
|
return err
|
|
}
|
|
|
|
func (s *LetterServiceImpl) extractUniqueDepartmentIDs(recipients []entities.LetterIncomingRecipient) []uuid.UUID {
|
|
deptMap := make(map[uuid.UUID]bool)
|
|
var departmentIDs []uuid.UUID
|
|
|
|
for _, recipient := range recipients {
|
|
if recipient.RecipientDepartmentID != nil && !deptMap[*recipient.RecipientDepartmentID] {
|
|
deptMap[*recipient.RecipientDepartmentID] = true
|
|
departmentIDs = append(departmentIDs, *recipient.RecipientDepartmentID)
|
|
}
|
|
}
|
|
|
|
return departmentIDs
|
|
}
|
|
|
|
func (s *LetterServiceImpl) logLetterCreation(ctx context.Context, letterID uuid.UUID, letterNumber string) {
|
|
if s.activityLogger == nil {
|
|
return
|
|
}
|
|
|
|
userID := appcontext.FromGinContext(ctx).UserID
|
|
err := s.activityLogger.LogLetterCreated(ctx, letterID, userID, letterNumber)
|
|
if err != nil {
|
|
// Log error but don't fail the operation
|
|
}
|
|
}
|
|
|
|
func (s *LetterServiceImpl) addCreatorAsRecipient(ctx context.Context, letterID uuid.UUID, creatorID uuid.UUID) (*entities.LetterIncomingRecipient, error) {
|
|
// Check if creator is already a recipient (to avoid duplicates)
|
|
existingRecipients, err := s.processor.GetBatchRecipientsByUser(ctx, []uuid.UUID{letterID}, creatorID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If creator is already a recipient, skip
|
|
if _, exists := existingRecipients[letterID]; exists {
|
|
return nil, nil
|
|
}
|
|
|
|
// Create recipient entry for the creator
|
|
recipient := entities.LetterIncomingRecipient{
|
|
ID: uuid.New(),
|
|
LetterID: letterID,
|
|
RecipientUserID: &creatorID,
|
|
Status: entities.RecipientStatusNew,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
// Save the recipient
|
|
if err := s.recipientProcessor.CreateSingleRecipient(ctx, &recipient); err != nil {
|
|
// Failed to add creator as recipient
|
|
return nil, err
|
|
}
|
|
|
|
return &recipient, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) sendLetterNotifications(ctx context.Context, letter *contract.IncomingLetterResponse, recipients []entities.LetterIncomingRecipient) {
|
|
for _, recipient := range recipients {
|
|
if recipient.Status != "completed" {
|
|
err := s.notificationProcessor.SendIncomingLetterNotification(
|
|
ctx,
|
|
letter.ID,
|
|
*recipient.RecipientUserID,
|
|
"Surat Masuk",
|
|
fmt.Sprintf("%s: %s", letter.SenderInstitution.Name, letter.Subject))
|
|
|
|
if err != nil {
|
|
// Failed to send notification, continue anyway
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *LetterServiceImpl) sendDispositionNotifications(ctx context.Context, letterID uuid.UUID, recipients []entities.LetterIncomingRecipient) {
|
|
// Get letter details for notification
|
|
appContext := appcontext.FromGinContext(ctx)
|
|
letter, err := s.processor.GetIncomingLetterByID(ctx, letterID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, recipient := range recipients {
|
|
if recipient.RecipientUserID != nil && recipient.Status != entities.RecipientStatusCompleted {
|
|
subject := "Surat Masuk"
|
|
message := fmt.Sprintf("Disposisi surat dari %s: %s", appContext.UserName, letter.Subject)
|
|
|
|
err := s.notificationProcessor.SendIncomingLetterNotification(
|
|
ctx,
|
|
letterID,
|
|
*recipient.RecipientUserID,
|
|
subject,
|
|
message)
|
|
|
|
if err != nil {
|
|
// Failed to send notification, continue anyway
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *LetterServiceImpl) GetIncomingLetterByID(ctx context.Context, id uuid.UUID) (*contract.IncomingLetterResponse, error) {
|
|
return s.processor.GetIncomingLetterByID(ctx, id)
|
|
}
|
|
func (s *LetterServiceImpl) ListIncomingLetters(ctx context.Context, req *contract.ListIncomingLettersRequest) (*contract.ListIncomingLettersResponse, error) {
|
|
appCtx := appcontext.FromGinContext(ctx)
|
|
userID := appCtx.UserID
|
|
departmentID := appCtx.DepartmentID
|
|
|
|
filter := repository.ListIncomingLettersFilter{
|
|
Status: req.Status,
|
|
Query: req.Query,
|
|
DepartmentID: &departmentID,
|
|
UserID: &userID,
|
|
IsRead: req.IsRead,
|
|
PriorityIDs: req.PriorityIDs,
|
|
IsDispositioned: req.IsDispositioned,
|
|
IsArchived: req.IsArchived,
|
|
}
|
|
|
|
letters, total, err := s.processor.ListIncomingLetters(ctx, filter, req.Page, req.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(letters) == 0 {
|
|
return &contract.ListIncomingLettersResponse{
|
|
Letters: []contract.IncomingLetterResponse{},
|
|
Pagination: transformer.CreatePaginationResponse(int(total), req.Page, req.Limit),
|
|
TotalUnread: 0,
|
|
}, nil
|
|
}
|
|
|
|
letterIDs := make([]uuid.UUID, 0, len(letters))
|
|
priorityIDSet := make(map[uuid.UUID]bool)
|
|
institutionIDSet := make(map[uuid.UUID]bool)
|
|
|
|
for _, letter := range letters {
|
|
letterIDs = append(letterIDs, letter.ID)
|
|
if letter.PriorityID != nil {
|
|
priorityIDSet[*letter.PriorityID] = true
|
|
}
|
|
if letter.SenderInstitutionID != nil {
|
|
institutionIDSet[*letter.SenderInstitutionID] = true
|
|
}
|
|
}
|
|
|
|
priorityIDs := make([]uuid.UUID, 0, len(priorityIDSet))
|
|
for id := range priorityIDSet {
|
|
priorityIDs = append(priorityIDs, id)
|
|
}
|
|
|
|
institutionIDs := make([]uuid.UUID, 0, len(institutionIDSet))
|
|
for id := range institutionIDSet {
|
|
institutionIDs = append(institutionIDs, id)
|
|
}
|
|
|
|
type batchResult struct {
|
|
attachments map[uuid.UUID][]entities.LetterIncomingAttachment
|
|
priorities map[uuid.UUID]*entities.Priority
|
|
institutions map[uuid.UUID]*entities.Institution
|
|
recipients map[uuid.UUID]*entities.LetterIncomingRecipient
|
|
err error
|
|
}
|
|
|
|
resultChan := make(chan batchResult, 1)
|
|
|
|
go func() {
|
|
result := batchResult{
|
|
attachments: make(map[uuid.UUID][]entities.LetterIncomingAttachment),
|
|
priorities: make(map[uuid.UUID]*entities.Priority),
|
|
institutions: make(map[uuid.UUID]*entities.Institution),
|
|
recipients: make(map[uuid.UUID]*entities.LetterIncomingRecipient),
|
|
}
|
|
|
|
errChan := make(chan error, 4)
|
|
|
|
go func() {
|
|
var err error
|
|
result.attachments, err = s.processor.GetBatchAttachments(ctx, letterIDs)
|
|
errChan <- err
|
|
}()
|
|
|
|
go func() {
|
|
var err error
|
|
result.priorities, err = s.processor.GetBatchPriorities(ctx, priorityIDs)
|
|
errChan <- err
|
|
}()
|
|
|
|
go func() {
|
|
var err error
|
|
result.institutions, err = s.processor.GetBatchInstitutions(ctx, institutionIDs)
|
|
errChan <- err
|
|
}()
|
|
|
|
go func() {
|
|
var err error
|
|
result.recipients, err = s.processor.GetBatchRecipientsByUser(ctx, letterIDs, userID)
|
|
errChan <- err
|
|
}()
|
|
|
|
for i := 0; i < 4; i++ {
|
|
if err := <-errChan; err != nil {
|
|
// Batch load error, continue anyway
|
|
}
|
|
}
|
|
|
|
resultChan <- result
|
|
}()
|
|
|
|
batchData := <-resultChan
|
|
|
|
respList := make([]contract.IncomingLetterResponse, 0, len(letters))
|
|
for _, letter := range letters {
|
|
attachments := batchData.attachments[letter.ID]
|
|
if attachments == nil {
|
|
attachments = []entities.LetterIncomingAttachment{}
|
|
}
|
|
|
|
var priority *entities.Priority
|
|
if letter.PriorityID != nil {
|
|
priority = batchData.priorities[*letter.PriorityID]
|
|
}
|
|
|
|
var institution *entities.Institution
|
|
if letter.SenderInstitutionID != nil {
|
|
institution = batchData.institutions[*letter.SenderInstitutionID]
|
|
}
|
|
|
|
isRead := false
|
|
if recipient, exists := batchData.recipients[letter.ID]; exists && recipient != nil {
|
|
isRead = recipient.ReadAt != nil
|
|
}
|
|
|
|
resp := transformer.LetterEntityToContract(&letter, attachments, priority, institution)
|
|
resp.IsRead = isRead
|
|
respList = append(respList, *resp)
|
|
}
|
|
|
|
totalUnread, _ := s.processor.CountUnreadByUser(ctx, userID)
|
|
|
|
return &contract.ListIncomingLettersResponse{
|
|
Letters: respList,
|
|
Pagination: transformer.CreatePaginationResponse(int(total), req.Page, req.Limit),
|
|
TotalUnread: totalUnread,
|
|
}, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) GetLetterUnreadCounts(ctx context.Context) (*contract.LetterUnreadCountResponse, error) {
|
|
return s.processor.GetLetterUnreadCounts(ctx)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) MarkIncomingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error) {
|
|
return s.processor.MarkIncomingLetterAsRead(ctx, letterID)
|
|
}
|
|
func (s *LetterServiceImpl) MarkOutgoingLetterAsRead(ctx context.Context, letterID uuid.UUID) (*contract.MarkLetterReadResponse, error) {
|
|
return s.processor.MarkOutgoingLetterAsRead(ctx, letterID)
|
|
}
|
|
func (s *LetterServiceImpl) UpdateIncomingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateIncomingLetterRequest) (*contract.IncomingLetterResponse, error) {
|
|
return s.processor.UpdateIncomingLetter(ctx, id, req)
|
|
}
|
|
func (s *LetterServiceImpl) SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error {
|
|
return s.processor.SoftDeleteIncomingLetter(ctx, id)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error) {
|
|
userID := appcontext.FromGinContext(ctx).UserID
|
|
req.CreatedBy = userID
|
|
|
|
if req.FromDepartment == uuid.Nil {
|
|
req.FromDepartment = appcontext.FromGinContext(ctx).DepartmentID
|
|
}
|
|
|
|
var result *contract.ListDispositionsResponse
|
|
var recipients []entities.LetterIncomingRecipient
|
|
|
|
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
var err error
|
|
result, err = s.processor.CreateDispositions(txCtx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(req.ToDepartmentIDs) > 0 && s.recipientProcessor != nil {
|
|
recipients, err = s.recipientProcessor.CreateRecipients(txCtx, req.LetterID, req.ToDepartmentIDs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if s.activityLogger != nil && result != nil && len(result.Dispositions) > 0 {
|
|
if err := s.activityLogger.LogLetterDispositionStatusUpdate(txCtx, req.LetterID, userID, "disposition_created"); err != nil {
|
|
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Send notifications to newly created recipients asynchronously
|
|
if s.notificationProcessor != nil && len(recipients) > 0 {
|
|
go s.sendDispositionNotifications(context.Background(), req.LetterID, recipients)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error) {
|
|
return s.processor.GetEnhancedDispositionsByLetter(ctx, letterID)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
|
|
userID := appcontext.FromGinContext(ctx).UserID
|
|
|
|
var result *contract.LetterDiscussionResponse
|
|
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
var err error
|
|
result, err = s.processor.CreateDiscussion(txCtx, letterID, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Log activity for discussion creation
|
|
if s.activityLogger != nil && result != nil {
|
|
// Create a simple activity log
|
|
if err := s.activityLogger.LogLetterDispositionStatusUpdate(txCtx, letterID, userID, "discussion_created"); err != nil {
|
|
// Don't fail the transaction for logging errors
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
|
|
userID := appcontext.FromGinContext(ctx).UserID
|
|
|
|
var result *contract.LetterDiscussionResponse
|
|
|
|
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
var err error
|
|
var oldMessage string
|
|
result, oldMessage, err = s.processor.UpdateDiscussion(txCtx, letterID, discussionID, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Log activity for discussion update (could use oldMessage for more detailed logging)
|
|
if s.activityLogger != nil && result != nil {
|
|
// Create a simple activity log - oldMessage could be included in a more detailed log
|
|
_ = oldMessage // Mark as intentionally unused for now
|
|
if err := s.activityLogger.LogLetterDispositionStatusUpdate(txCtx, letterID, userID, "discussion_updated"); err != nil {
|
|
// Don't fail the transaction for logging errors
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (s *LetterServiceImpl) GetDepartmentDispositionStatus(ctx context.Context, req *contract.GetDepartmentDispositionStatusRequest) (*contract.ListDepartmentDispositionStatusResponse, error) {
|
|
return s.processor.GetDepartmentDispositionStatus(ctx, req)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) UpdateDispositionStatus(ctx context.Context, req *contract.UpdateDispositionStatusRequest) (*contract.DepartmentDispositionStatusResponse, error) {
|
|
// For now, delegate to the processor which handles this
|
|
// The processor needs to be refactored to remove context extraction
|
|
return s.processor.UpdateDispositionStatus(ctx, req)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) GetLetterCTA(ctx context.Context, letterID uuid.UUID) (*contract.LetterCTAResponse, error) {
|
|
departmentID := appcontext.FromGinContext(ctx).DepartmentID
|
|
return s.processor.GetLetterCTA(ctx, letterID, departmentID)
|
|
}
|
|
|
|
func (s *LetterServiceImpl) BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (*contract.BulkArchiveLettersResponse, error) {
|
|
// Extract user context to archive only for the current user
|
|
appCtx := appcontext.FromGinContext(ctx)
|
|
userID := appCtx.UserID
|
|
|
|
// Archive letters only for the current user
|
|
archivedCount, err := s.processor.BulkArchiveIncomingLettersForUser(ctx, letterIDs, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &contract.BulkArchiveLettersResponse{
|
|
Success: true,
|
|
Message: "Letters archived successfully",
|
|
ArchivedCount: int(archivedCount),
|
|
}, nil
|
|
}
|