320 lines
11 KiB
Go
320 lines
11 KiB
Go
package processor
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"eslogad-be/internal/appcontext"
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/entities"
|
|
"eslogad-be/internal/repository"
|
|
"eslogad-be/internal/transformer"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type LetterProcessorImpl struct {
|
|
letterRepo *repository.LetterIncomingRepository
|
|
attachRepo *repository.LetterIncomingAttachmentRepository
|
|
txManager *repository.TxManager
|
|
activity *ActivityLogProcessorImpl
|
|
// new repos for dispositions
|
|
dispositionRepo *repository.LetterDispositionRepository
|
|
dispositionActionSelRepo *repository.LetterDispositionActionSelectionRepository
|
|
dispositionNoteRepo *repository.DispositionNoteRepository
|
|
// discussion repo
|
|
discussionRepo *repository.LetterDiscussionRepository
|
|
}
|
|
|
|
func NewLetterProcessor(letterRepo *repository.LetterIncomingRepository, attachRepo *repository.LetterIncomingAttachmentRepository, txManager *repository.TxManager, activity *ActivityLogProcessorImpl, dispRepo *repository.LetterDispositionRepository, dispSelRepo *repository.LetterDispositionActionSelectionRepository, noteRepo *repository.DispositionNoteRepository, discussionRepo *repository.LetterDiscussionRepository) *LetterProcessorImpl {
|
|
return &LetterProcessorImpl{letterRepo: letterRepo, attachRepo: attachRepo, txManager: txManager, activity: activity, dispositionRepo: dispRepo, dispositionActionSelRepo: dispSelRepo, dispositionNoteRepo: noteRepo, discussionRepo: discussionRepo}
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error) {
|
|
var result *contract.IncomingLetterResponse
|
|
err := p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
entity := &entities.LetterIncoming{
|
|
ReferenceNumber: req.ReferenceNumber,
|
|
Subject: req.Subject,
|
|
Description: req.Description,
|
|
PriorityID: req.PriorityID,
|
|
SenderInstitutionID: req.SenderInstitutionID,
|
|
ReceivedDate: req.ReceivedDate,
|
|
DueDate: req.DueDate,
|
|
Status: entities.LetterIncomingStatusNew,
|
|
CreatedBy: userID,
|
|
}
|
|
if err := p.letterRepo.Create(txCtx, entity); err != nil {
|
|
return err
|
|
}
|
|
|
|
if p.activity != nil {
|
|
action := "letter.created"
|
|
if err := p.activity.Log(txCtx, entity.ID, action, &userID, nil, nil, nil, nil, nil, map[string]interface{}{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
attachments := make([]entities.LetterIncomingAttachment, 0, len(req.Attachments))
|
|
for _, a := range req.Attachments {
|
|
attachments = append(attachments, entities.LetterIncomingAttachment{
|
|
LetterID: entity.ID,
|
|
FileURL: a.FileURL,
|
|
FileName: a.FileName,
|
|
FileType: a.FileType,
|
|
UploadedBy: &userID,
|
|
})
|
|
}
|
|
if len(attachments) > 0 {
|
|
if err := p.attachRepo.CreateBulk(txCtx, attachments); err != nil {
|
|
return err
|
|
}
|
|
if p.activity != nil {
|
|
action := "attachment.uploaded"
|
|
for _, a := range attachments {
|
|
ctxMap := map[string]interface{}{"file_name": a.FileName, "file_type": a.FileType}
|
|
if err := p.activity.Log(txCtx, entity.ID, action, &userID, nil, nil, nil, nil, nil, ctxMap); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
savedAttachments, _ := p.attachRepo.ListByLetter(txCtx, entity.ID)
|
|
result = transformer.LetterEntityToContract(entity, savedAttachments)
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) GetIncomingLetterByID(ctx context.Context, id uuid.UUID) (*contract.IncomingLetterResponse, error) {
|
|
entity, err := p.letterRepo.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
atts, _ := p.attachRepo.ListByLetter(ctx, id)
|
|
return transformer.LetterEntityToContract(entity, atts), nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) ListIncomingLetters(ctx context.Context, req *contract.ListIncomingLettersRequest) (*contract.ListIncomingLettersResponse, error) {
|
|
page, limit := req.Page, req.Limit
|
|
if page <= 0 {
|
|
page = 1
|
|
}
|
|
if limit <= 0 {
|
|
limit = 10
|
|
}
|
|
filter := repository.ListIncomingLettersFilter{Status: req.Status, Query: req.Query}
|
|
list, total, err := p.letterRepo.List(ctx, filter, limit, (page-1)*limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
respList := make([]contract.IncomingLetterResponse, 0, len(list))
|
|
for _, e := range list {
|
|
atts, _ := p.attachRepo.ListByLetter(ctx, e.ID)
|
|
resp := transformer.LetterEntityToContract(&e, atts)
|
|
respList = append(respList, *resp)
|
|
}
|
|
return &contract.ListIncomingLettersResponse{Letters: respList, Pagination: transformer.CreatePaginationResponse(int(total), page, limit)}, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) UpdateIncomingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateIncomingLetterRequest) (*contract.IncomingLetterResponse, error) {
|
|
var out *contract.IncomingLetterResponse
|
|
err := p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
entity, err := p.letterRepo.Get(txCtx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fromStatus := string(entity.Status)
|
|
if req.ReferenceNumber != nil {
|
|
entity.ReferenceNumber = req.ReferenceNumber
|
|
}
|
|
if req.Subject != nil {
|
|
entity.Subject = *req.Subject
|
|
}
|
|
if req.Description != nil {
|
|
entity.Description = req.Description
|
|
}
|
|
if req.PriorityID != nil {
|
|
entity.PriorityID = req.PriorityID
|
|
}
|
|
if req.SenderInstitutionID != nil {
|
|
entity.SenderInstitutionID = req.SenderInstitutionID
|
|
}
|
|
if req.ReceivedDate != nil {
|
|
entity.ReceivedDate = *req.ReceivedDate
|
|
}
|
|
if req.DueDate != nil {
|
|
entity.DueDate = req.DueDate
|
|
}
|
|
if req.Status != nil {
|
|
entity.Status = entities.LetterIncomingStatus(*req.Status)
|
|
}
|
|
if err := p.letterRepo.Update(txCtx, entity); err != nil {
|
|
return err
|
|
}
|
|
toStatus := string(entity.Status)
|
|
if p.activity != nil && fromStatus != toStatus {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
action := "status.changed"
|
|
if err := p.activity.Log(txCtx, id, action, &userID, nil, nil, nil, &fromStatus, &toStatus, map[string]interface{}{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
atts, _ := p.attachRepo.ListByLetter(txCtx, id)
|
|
out = transformer.LetterEntityToContract(entity, atts)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error {
|
|
return p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
if err := p.letterRepo.SoftDelete(txCtx, id); err != nil {
|
|
return err
|
|
}
|
|
if p.activity != nil {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
action := "letter.deleted"
|
|
if err := p.activity.Log(txCtx, id, action, &userID, nil, nil, nil, nil, nil, map[string]interface{}{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error) {
|
|
var out *contract.ListDispositionsResponse
|
|
err := p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
created := make([]entities.LetterDisposition, 0, len(req.ToDepartmentIDs))
|
|
for _, toDept := range req.ToDepartmentIDs {
|
|
disp := entities.LetterDisposition{
|
|
LetterID: req.LetterID,
|
|
FromDepartmentID: nil,
|
|
ToDepartmentID: &toDept,
|
|
Notes: req.Notes,
|
|
Status: entities.DispositionPending,
|
|
CreatedBy: userID,
|
|
}
|
|
if err := p.dispositionRepo.Create(txCtx, &disp); err != nil {
|
|
return err
|
|
}
|
|
created = append(created, disp)
|
|
|
|
if len(req.SelectedActions) > 0 {
|
|
selections := make([]entities.LetterDispositionActionSelection, 0, len(req.SelectedActions))
|
|
for _, sel := range req.SelectedActions {
|
|
selections = append(selections, entities.LetterDispositionActionSelection{
|
|
DispositionID: disp.ID,
|
|
ActionID: sel.ActionID,
|
|
Note: sel.Note,
|
|
CreatedBy: userID,
|
|
})
|
|
}
|
|
if err := p.dispositionActionSelRepo.CreateBulk(txCtx, selections); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if p.activity != nil {
|
|
action := "disposition.created"
|
|
for _, d := range created {
|
|
ctxMap := map[string]interface{}{"to_department_id": d.ToDepartmentID}
|
|
if err := p.activity.Log(txCtx, req.LetterID, action, &userID, nil, nil, &d.ID, nil, nil, ctxMap); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
out = &contract.ListDispositionsResponse{Dispositions: transformer.DispositionsToContract(created)}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) ListDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListDispositionsResponse, error) {
|
|
list, err := p.dispositionRepo.ListByLetter(ctx, letterID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &contract.ListDispositionsResponse{Dispositions: transformer.DispositionsToContract(list)}, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
|
|
var out *contract.LetterDiscussionResponse
|
|
err := p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
mentions := entities.JSONB(nil)
|
|
if req.Mentions != nil {
|
|
mentions = entities.JSONB(req.Mentions)
|
|
}
|
|
disc := &entities.LetterDiscussion{LetterID: letterID, ParentID: req.ParentID, UserID: userID, Message: req.Message, Mentions: mentions}
|
|
if err := p.discussionRepo.Create(txCtx, disc); err != nil {
|
|
return err
|
|
}
|
|
if p.activity != nil {
|
|
action := "discussion.created"
|
|
tgt := "discussion"
|
|
ctxMap := map[string]interface{}{"message": req.Message, "parent_id": req.ParentID}
|
|
if err := p.activity.Log(txCtx, letterID, action, &userID, nil, &tgt, &disc.ID, nil, nil, ctxMap); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
out = transformer.DiscussionEntityToContract(disc)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (p *LetterProcessorImpl) UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
|
|
var out *contract.LetterDiscussionResponse
|
|
err := p.txManager.WithTransaction(ctx, func(txCtx context.Context) error {
|
|
disc, err := p.discussionRepo.Get(txCtx, discussionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
oldMessage := disc.Message
|
|
disc.Message = req.Message
|
|
if req.Mentions != nil {
|
|
disc.Mentions = entities.JSONB(req.Mentions)
|
|
}
|
|
now := time.Now()
|
|
disc.EditedAt = &now
|
|
if err := p.discussionRepo.Update(txCtx, disc); err != nil {
|
|
return err
|
|
}
|
|
if p.activity != nil {
|
|
userID := appcontext.FromGinContext(txCtx).UserID
|
|
action := "discussion.updated"
|
|
tgt := "discussion"
|
|
ctxMap := map[string]interface{}{"old_message": oldMessage, "new_message": req.Message}
|
|
if err := p.activity.Log(txCtx, letterID, action, &userID, nil, &tgt, &disc.ID, nil, nil, ctxMap); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
out = transformer.DiscussionEntityToContract(disc)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|