bulk delete incoming letter

This commit is contained in:
efrilm 2025-10-30 11:36:49 +07:00
parent 7f67f6db4f
commit 9e4481a0bd
6 changed files with 67 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package handler
import (
"context"
"eslogad-be/internal/appcontext"
"fmt"
"net/http"
"strconv"
"strings"
@ -23,6 +24,7 @@ type LetterService interface {
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
BulkSoftDeleteIncomingLetters(ctx context.Context, ids []uuid.UUID) error
BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (*contract.BulkArchiveLettersResponse, error)
ArchiveIncomingLetter(ctx context.Context, letterID uuid.UUID) error
@ -282,6 +284,29 @@ func (h *LetterHandler) DeleteIncomingLetter(c *gin.Context) {
})
}
func (h *LetterHandler) BulkDeleteIncomingLetters(c *gin.Context) {
var req struct {
IDs []uuid.UUID `json:"ids" binding:"required,min=1"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Message: "Invalid request body",
Error: err.Error(),
})
return
}
if err := h.svc.BulkSoftDeleteIncomingLetters(c.Request.Context(), req.IDs); err != nil {
h.handleServiceError(c, err)
return
}
h.respondSuccess(c, http.StatusOK, &contract.SuccessResponse{
Message: fmt.Sprintf("%d letters deleted successfully", len(req.IDs)),
})
}
func (h *LetterHandler) CreateDispositions(c *gin.Context) {
var req contract.CreateLetterDispositionRequest
if !h.bindJSON(c, &req) {

View File

@ -352,6 +352,32 @@ func (p *LetterProcessorImpl) SoftDeleteIncomingLetter(ctx context.Context, id u
})
}
func (p *LetterProcessorImpl) BulkSoftDeleteIncomingLetters(ctx context.Context, ids []uuid.UUID) error {
if len(ids) == 0 {
return nil
}
return p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
if err := p.letterRepo.BulkSoftDelete(txCtx, ids); err != nil {
return err
}
if p.activity != nil {
userID := appcontext.FromGinContext(txCtx).UserID
action := "letter.bulk_deleted"
// Log activity untuk setiap letter yang dihapus
for _, id := range ids {
if err := p.activity.Log(txCtx, id, action, &userID, nil, nil, nil, nil, nil, map[string]interface{}{}); err != nil {
return err
}
}
}
return nil
})
}
// CreateDispositions creates a new disposition with modular helper functions
func (p *LetterProcessorImpl) CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error) {
// Transaction should be handled at service layer

View File

@ -54,6 +54,15 @@ func (r *LetterIncomingRepository) SoftDelete(ctx context.Context, id uuid.UUID)
return db.WithContext(ctx).Exec("UPDATE letters_incoming SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL", id).Error
}
func (r *LetterIncomingRepository) BulkSoftDelete(ctx context.Context, ids []uuid.UUID) error {
if len(ids) == 0 {
return nil
}
db := DBFromContext(ctx, r.db)
return db.WithContext(ctx).Exec("UPDATE letters_incoming SET deleted_at = CURRENT_TIMESTAMP WHERE id IN ? AND deleted_at IS NULL", ids).Error
}
func (r *LetterIncomingRepository) BulkArchive(ctx context.Context, letterIDs []uuid.UUID) (int64, error) {
db := DBFromContext(ctx, r.db)
now := time.Now()

View File

@ -82,6 +82,7 @@ type LetterHandler interface {
MarkOutgoingLetterAsRead(c *gin.Context)
UpdateIncomingLetter(c *gin.Context)
DeleteIncomingLetter(c *gin.Context)
BulkDeleteIncomingLetters(c *gin.Context)
BulkArchiveIncomingLetters(c *gin.Context)
ArchiveIncomingLetter(c *gin.Context)

View File

@ -181,6 +181,7 @@ func (r *Router) addAppRoutes(rg *gin.Engine) {
lettersch.PUT("/incoming/:id", r.letterHandler.UpdateIncomingLetter)
lettersch.PUT("/incoming/:id/read", r.letterHandler.MarkIncomingLetterAsRead)
lettersch.DELETE("/incoming/:id", r.letterHandler.DeleteIncomingLetter)
lettersch.DELETE("/incoming/delete", r.letterHandler.BulkDeleteIncomingLetters)
lettersch.POST("/incoming/archive", r.letterHandler.BulkArchiveIncomingLetters)
lettersch.PUT("/incoming/:id/archive", r.letterHandler.ArchiveIncomingLetter)

View File

@ -31,6 +31,7 @@ type LetterProcessor interface {
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
BulkSoftDeleteIncomingLetters(ctx context.Context, ids []uuid.UUID) error
BulkArchiveIncomingLetters(ctx context.Context, letterIDs []uuid.UUID) (int64, error)
ArchiveIncomingLetter(ctx context.Context, letterID uuid.UUID) error
BulkArchiveIncomingLettersForUser(ctx context.Context, letterIDs []uuid.UUID, userID uuid.UUID) (int64, error)
@ -465,6 +466,10 @@ func (s *LetterServiceImpl) SoftDeleteIncomingLetter(ctx context.Context, id uui
return s.processor.SoftDeleteIncomingLetter(ctx, id)
}
func (s *LetterServiceImpl) BulkSoftDeleteIncomingLetters(ctx context.Context, ids []uuid.UUID) error {
return s.processor.BulkSoftDeleteIncomingLetters(ctx, ids)
}
func (s *LetterServiceImpl) SearchIncomingLetters(ctx context.Context, req *contract.SearchIncomingLettersRequest) (*contract.SearchIncomingLettersResponse, error) {
appCtx := appcontext.FromGinContext(ctx)
userID := appCtx.UserID