update unique letter number

This commit is contained in:
efrilm 2025-10-20 22:50:08 +07:00
parent 0c3e1db502
commit 88ad35c5d0
5 changed files with 76 additions and 25 deletions

View File

@ -17,6 +17,7 @@ import (
type LetterOutgoingProcessor interface {
CreateOutgoingLetter(ctx context.Context, letter *entities.LetterOutgoing, attachments []entities.LetterOutgoingAttachment, userID, departmentID uuid.UUID) error
GetOutgoingLetterByID(ctx context.Context, id uuid.UUID) (*entities.LetterOutgoing, error)
GetOutgoingLetterByReferenceNumber(ctx context.Context, referenceNumber *string) (*entities.LetterOutgoing, error)
ListOutgoingLetters(ctx context.Context, filter repository.ListOutgoingLettersFilter, limit, offset int) ([]entities.LetterOutgoing, int64, error)
SearchOutgoingLetters(ctx context.Context, filters map[string]interface{}, page, limit int, sortBy, sortOrder string) ([]entities.LetterOutgoing, int64, error)
UpdateOutgoingLetter(ctx context.Context, letter *entities.LetterOutgoing, userID uuid.UUID) error
@ -110,6 +111,11 @@ func NewLetterOutgoingProcessor(
}
func (p *LetterOutgoingProcessorImpl) CreateOutgoingLetter(ctx context.Context, letter *entities.LetterOutgoing, attachments []entities.LetterOutgoingAttachment, userID, departmentID uuid.UUID) error {
existingOutgoing, err := p.letterRepo.GetByReferenceNumber(ctx, letter.ReferenceNumber)
if err == nil && existingOutgoing != nil {
return fmt.Errorf("surat dengan nomor %s sudah ada", *letter.ReferenceNumber)
}
return p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
// Step 1: Assign approval flow from department if not provided
if err := p.assignApprovalFlowFromDepartment(txCtx, letter, departmentID); err != nil {
@ -148,6 +154,10 @@ func (p *LetterOutgoingProcessorImpl) CreateOutgoingLetter(ctx context.Context,
})
}
func (p *LetterOutgoingProcessorImpl) GetOutgoingLetterByReferenceNumber(ctx context.Context, referenceNumber *string) (*entities.LetterOutgoing, error) {
return p.letterRepo.GetByReferenceNumber(ctx, referenceNumber)
}
func (p *LetterOutgoingProcessorImpl) assignApprovalFlowFromDepartment(ctx context.Context, letter *entities.LetterOutgoing, departmentID uuid.UUID) error {
if letter.ApprovalFlowID != nil || departmentID == uuid.Nil {
return nil

View File

@ -60,6 +60,11 @@ func NewLetterProcessor(letterRepo *repository.LetterIncomingRepository, attachR
func (p *LetterProcessorImpl) CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error) {
userID := appcontext.FromGinContext(ctx).UserID
existingIncoming, err := p.letterRepo.GetByReferenceNumber(ctx, req.ReferenceNumber)
if err == nil && existingIncoming != nil {
return nil, fmt.Errorf("surat dengan nomor %s sudah ada", *req.ReferenceNumber)
}
letterType := entities.LetterIncomingTypeUtama
if req.Type == "TEMBUSAN" {
letterType = entities.LetterIncomingTypeTembusan

View File

@ -41,6 +41,25 @@ func (r *LetterOutgoingRepository) Get(ctx context.Context, id uuid.UUID) (*enti
return &e, nil
}
func (r *LetterOutgoingRepository) GetByReferenceNumber(ctx context.Context, refNumber *string) (*entities.LetterOutgoing, error) {
db := DBFromContext(ctx, r.db)
var e entities.LetterOutgoing
if err := db.WithContext(ctx).
Preload("Priority").
Preload("ReceiverInstitution").
Preload("Creator").
Preload("ApprovalFlow").
Preload("Recipients").
Preload("Attachments").
Preload("Approvals.Step").
Preload("Approvals.Approver").
Where("reference_number = ? AND deleted_at IS NULL", refNumber).
First(&e).Error; err != nil {
return nil, err
}
return &e, nil
}
func (r *LetterOutgoingRepository) Update(ctx context.Context, e *entities.LetterOutgoing) error {
db := DBFromContext(ctx, r.db)
return db.WithContext(ctx).Model(&entities.LetterOutgoing{}).Where("id = ? AND deleted_at IS NULL", e.ID).Updates(e).Error

View File

@ -29,6 +29,17 @@ func (r *LetterIncomingRepository) Get(ctx context.Context, id uuid.UUID) (*enti
return &e, nil
}
func (r *LetterIncomingRepository) GetByReferenceNumber(ctx context.Context, refNumber *string) (*entities.LetterIncoming, error) {
db := DBFromContext(ctx, r.db)
var e entities.LetterIncoming
if err := db.WithContext(ctx).
Where("reference_number = ? AND deleted_at IS NULL", refNumber).
First(&e).Error; err != nil {
return nil, err
}
return &e, nil
}
func (r *LetterIncomingRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.LetterIncoming, error) {
return r.Get(ctx, id)
}

View File

@ -94,6 +94,12 @@ func (s *LetterOutgoingServiceImpl) CreateOutgoingLetter(ctx context.Context, re
departmentID := getDepartmentIDFromContext(ctx)
userID := getUserIDFromContext(ctx)
existingOutgoing, err := s.processor.GetOutgoingLetterByReferenceNumber(ctx, req.ReferenceNumber)
if err == nil && existingOutgoing != nil {
return nil, fmt.Errorf("surat dengan nomor %s sudah ada", *req.ReferenceNumber)
}
// Create letter entity
letter := &entities.LetterOutgoing{
Subject: req.Subject,
@ -125,7 +131,7 @@ func (s *LetterOutgoingServiceImpl) CreateOutgoingLetter(ctx context.Context, re
}
// Execute creation with transaction in service layer
err := s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
err = s.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
// Step 1: Validate letter
if err := s.validationProcessor.ValidateCreateOutgoingLetter(txCtx, letter); err != nil {
return err