letter incoming
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"eslogad-be/internal/entities"
|
||||
"eslogad-be/internal/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ActivityLogProcessorImpl struct {
|
||||
repo *repository.LetterIncomingActivityLogRepository
|
||||
}
|
||||
|
||||
func NewActivityLogProcessor(repo *repository.LetterIncomingActivityLogRepository) *ActivityLogProcessorImpl {
|
||||
return &ActivityLogProcessorImpl{repo: repo}
|
||||
}
|
||||
|
||||
func (p *ActivityLogProcessorImpl) Log(ctx context.Context, letterID uuid.UUID, actionType string, actorUserID *uuid.UUID, actorDepartmentID *uuid.UUID, targetType *string, targetID *uuid.UUID, fromStatus *string, toStatus *string, contextData map[string]interface{}) error {
|
||||
ctxJSON := entities.JSONB{}
|
||||
for k, v := range contextData {
|
||||
ctxJSON[k] = v
|
||||
}
|
||||
entry := &entities.LetterIncomingActivityLog{
|
||||
LetterID: letterID,
|
||||
ActionType: actionType,
|
||||
ActorUserID: actorUserID,
|
||||
ActorDepartmentID: actorDepartmentID,
|
||||
TargetType: targetType,
|
||||
TargetID: targetID,
|
||||
FromStatus: fromStatus,
|
||||
ToStatus: toStatus,
|
||||
Context: ctxJSON,
|
||||
}
|
||||
return p.repo.Create(ctx, entry)
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user