2025-08-09 18:58:22 +07:00
|
|
|
package transformer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"eslogad-be/internal/contract"
|
|
|
|
|
"eslogad-be/internal/entities"
|
2025-08-15 21:17:19 +07:00
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
2025-08-09 18:58:22 +07:00
|
|
|
)
|
|
|
|
|
|
2025-08-15 21:17:19 +07:00
|
|
|
func LetterEntityToContract(e *entities.LetterIncoming, attachments []entities.LetterIncomingAttachment, refs ...interface{}) *contract.IncomingLetterResponse {
|
2025-08-09 18:58:22 +07:00
|
|
|
resp := &contract.IncomingLetterResponse{
|
2025-08-15 21:17:19 +07:00
|
|
|
ID: e.ID,
|
|
|
|
|
LetterNumber: e.LetterNumber,
|
|
|
|
|
ReferenceNumber: e.ReferenceNumber,
|
|
|
|
|
Subject: e.Subject,
|
|
|
|
|
Description: e.Description,
|
|
|
|
|
ReceivedDate: e.ReceivedDate,
|
|
|
|
|
DueDate: e.DueDate,
|
|
|
|
|
Status: string(e.Status),
|
|
|
|
|
CreatedBy: e.CreatedBy,
|
|
|
|
|
CreatedAt: e.CreatedAt,
|
|
|
|
|
UpdatedAt: e.UpdatedAt,
|
|
|
|
|
Attachments: make([]contract.IncomingLetterAttachmentResponse, 0, len(attachments)),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// optional refs: allow passing already-fetched related objects
|
|
|
|
|
// expected ordering (if provided): *entities.Priority, *entities.Institution
|
|
|
|
|
for _, r := range refs {
|
|
|
|
|
switch v := r.(type) {
|
|
|
|
|
case *entities.Priority:
|
|
|
|
|
if v != nil {
|
|
|
|
|
resp.Priority = &contract.PriorityResponse{
|
|
|
|
|
ID: v.ID.String(),
|
|
|
|
|
Name: v.Name,
|
|
|
|
|
Level: v.Level,
|
|
|
|
|
CreatedAt: v.CreatedAt,
|
|
|
|
|
UpdatedAt: v.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case *entities.Institution:
|
|
|
|
|
if v != nil {
|
|
|
|
|
resp.SenderInstitution = &contract.InstitutionResponse{
|
|
|
|
|
ID: v.ID.String(),
|
|
|
|
|
Name: v.Name,
|
|
|
|
|
Type: string(v.Type),
|
|
|
|
|
Address: v.Address,
|
|
|
|
|
ContactPerson: v.ContactPerson,
|
|
|
|
|
Phone: v.Phone,
|
|
|
|
|
Email: v.Email,
|
|
|
|
|
CreatedAt: v.CreatedAt,
|
|
|
|
|
UpdatedAt: v.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-09 18:58:22 +07:00
|
|
|
}
|
|
|
|
|
for _, a := range attachments {
|
|
|
|
|
resp.Attachments = append(resp.Attachments, contract.IncomingLetterAttachmentResponse{
|
|
|
|
|
ID: a.ID,
|
|
|
|
|
FileURL: a.FileURL,
|
|
|
|
|
FileName: a.FileName,
|
|
|
|
|
FileType: a.FileType,
|
|
|
|
|
UploadedAt: a.UploadedAt,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return resp
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:17:19 +07:00
|
|
|
func DispositionsToContract(list []entities.LetterIncomingDisposition) []contract.DispositionResponse {
|
2025-08-09 18:58:22 +07:00
|
|
|
out := make([]contract.DispositionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
2025-08-15 21:17:19 +07:00
|
|
|
out = append(out, DispoToContract(d))
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispoToContract(d entities.LetterIncomingDisposition) contract.DispositionResponse {
|
|
|
|
|
return contract.DispositionResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
LetterID: d.LetterID,
|
|
|
|
|
DepartmentID: d.DepartmentID,
|
|
|
|
|
Notes: d.Notes,
|
|
|
|
|
ReadAt: d.ReadAt,
|
|
|
|
|
CreatedBy: d.CreatedBy,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
UpdatedAt: d.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func EnhancedDispositionsToContract(list []entities.LetterIncomingDisposition) []contract.EnhancedDispositionResponse {
|
|
|
|
|
out := make([]contract.EnhancedDispositionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.EnhancedDispositionResponse{
|
2025-08-09 18:58:22 +07:00
|
|
|
ID: d.ID,
|
|
|
|
|
LetterID: d.LetterID,
|
2025-08-15 21:17:19 +07:00
|
|
|
DepartmentID: d.DepartmentID,
|
2025-08-09 18:58:22 +07:00
|
|
|
Notes: d.Notes,
|
2025-08-15 21:17:19 +07:00
|
|
|
ReadAt: d.ReadAt,
|
2025-08-09 18:58:22 +07:00
|
|
|
CreatedBy: d.CreatedBy,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
2025-08-15 21:17:19 +07:00
|
|
|
UpdatedAt: d.UpdatedAt,
|
|
|
|
|
Departments: []contract.DispositionDepartmentResponse{},
|
|
|
|
|
Actions: []contract.DispositionActionSelectionResponse{},
|
|
|
|
|
DispositionNotes: []contract.DispositionNoteResponse{},
|
|
|
|
|
}
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionDepartmentsToContract(list []entities.LetterIncomingDispositionDepartment) []contract.DispositionDepartmentResponse {
|
|
|
|
|
out := make([]contract.DispositionDepartmentResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionDepartmentResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
DepartmentID: d.DepartmentID,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionDepartmentsWithDetailsToContract(list []entities.LetterIncomingDispositionDepartment) []contract.DispositionDepartmentResponse {
|
|
|
|
|
out := make([]contract.DispositionDepartmentResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionDepartmentResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
DepartmentID: d.DepartmentID,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include department details if preloaded
|
|
|
|
|
if d.Department != nil {
|
|
|
|
|
resp.Department = &contract.DepartmentResponse{
|
|
|
|
|
ID: d.Department.ID,
|
|
|
|
|
Name: d.Department.Name,
|
|
|
|
|
Code: d.Department.Code,
|
|
|
|
|
Path: d.Department.Path,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionActionSelectionsToContract(list []entities.LetterDispositionActionSelection) []contract.DispositionActionSelectionResponse {
|
|
|
|
|
out := make([]contract.DispositionActionSelectionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionActionSelectionResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
ActionID: d.ActionID,
|
|
|
|
|
Action: nil, // Will be populated by processor
|
|
|
|
|
Note: d.Note,
|
|
|
|
|
CreatedBy: d.CreatedBy,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionActionSelectionsWithDetailsToContract(list []entities.LetterDispositionActionSelection) []contract.DispositionActionSelectionResponse {
|
|
|
|
|
out := make([]contract.DispositionActionSelectionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionActionSelectionResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
ActionID: d.ActionID,
|
|
|
|
|
Action: nil, // Will be populated by processor
|
|
|
|
|
Note: d.Note,
|
|
|
|
|
CreatedBy: d.CreatedBy,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include action details if preloaded
|
|
|
|
|
if d.Action != nil {
|
|
|
|
|
resp.Action = &contract.DispositionActionResponse{
|
|
|
|
|
ID: d.Action.ID.String(),
|
|
|
|
|
Code: d.Action.Code,
|
|
|
|
|
Label: d.Action.Label,
|
|
|
|
|
Description: d.Action.Description,
|
|
|
|
|
RequiresNote: d.Action.RequiresNote,
|
|
|
|
|
GroupName: d.Action.GroupName,
|
|
|
|
|
SortOrder: d.Action.SortOrder,
|
|
|
|
|
IsActive: d.Action.IsActive,
|
|
|
|
|
CreatedAt: d.Action.CreatedAt,
|
|
|
|
|
UpdatedAt: d.Action.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionNotesToContract(list []entities.DispositionNote) []contract.DispositionNoteResponse {
|
|
|
|
|
out := make([]contract.DispositionNoteResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionNoteResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
UserID: d.UserID,
|
|
|
|
|
Note: d.Note,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DispositionNotesWithDetailsToContract(list []entities.DispositionNote) []contract.DispositionNoteResponse {
|
|
|
|
|
out := make([]contract.DispositionNoteResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.DispositionNoteResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
UserID: d.UserID,
|
|
|
|
|
Note: d.Note,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include user details if preloaded
|
|
|
|
|
if d.User != nil {
|
|
|
|
|
resp.User = &contract.UserResponse{
|
|
|
|
|
ID: d.User.ID,
|
|
|
|
|
Name: d.User.Name,
|
|
|
|
|
Email: d.User.Email,
|
|
|
|
|
IsActive: d.User.IsActive,
|
|
|
|
|
CreatedAt: d.User.CreatedAt,
|
|
|
|
|
UpdatedAt: d.User.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = append(out, resp)
|
2025-08-09 18:58:22 +07:00
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func DiscussionEntityToContract(e *entities.LetterDiscussion) *contract.LetterDiscussionResponse {
|
|
|
|
|
var mentions map[string]interface{}
|
|
|
|
|
if e.Mentions != nil {
|
|
|
|
|
mentions = map[string]interface{}(e.Mentions)
|
|
|
|
|
}
|
|
|
|
|
return &contract.LetterDiscussionResponse{
|
|
|
|
|
ID: e.ID,
|
|
|
|
|
LetterID: e.LetterID,
|
|
|
|
|
ParentID: e.ParentID,
|
|
|
|
|
UserID: e.UserID,
|
|
|
|
|
Message: e.Message,
|
|
|
|
|
Mentions: mentions,
|
|
|
|
|
CreatedAt: e.CreatedAt,
|
|
|
|
|
UpdatedAt: e.UpdatedAt,
|
|
|
|
|
EditedAt: e.EditedAt,
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-15 21:17:19 +07:00
|
|
|
|
|
|
|
|
func DiscussionsWithPreloadedDataToContract(list []entities.LetterDiscussion, mentionedUsers []entities.User) []contract.LetterDiscussionResponse {
|
|
|
|
|
// Create a map for efficient user lookup
|
|
|
|
|
userMap := make(map[uuid.UUID]entities.User)
|
|
|
|
|
for _, user := range mentionedUsers {
|
|
|
|
|
userMap[user.ID] = user
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out := make([]contract.LetterDiscussionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.LetterDiscussionResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
LetterID: d.LetterID,
|
|
|
|
|
ParentID: d.ParentID,
|
|
|
|
|
UserID: d.UserID,
|
|
|
|
|
Message: d.Message,
|
|
|
|
|
Mentions: map[string]interface{}(d.Mentions),
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
UpdatedAt: d.UpdatedAt,
|
|
|
|
|
EditedAt: d.EditedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include user profile if preloaded
|
|
|
|
|
if d.User != nil {
|
|
|
|
|
resp.User = &contract.UserResponse{
|
|
|
|
|
ID: d.User.ID,
|
|
|
|
|
Name: d.User.Name,
|
|
|
|
|
Email: d.User.Email,
|
|
|
|
|
IsActive: d.User.IsActive,
|
|
|
|
|
CreatedAt: d.User.CreatedAt,
|
|
|
|
|
UpdatedAt: d.User.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include user profile if available
|
|
|
|
|
if d.User.Profile != nil {
|
|
|
|
|
resp.User.Profile = &contract.UserProfileResponse{
|
|
|
|
|
UserID: d.User.Profile.UserID,
|
|
|
|
|
FullName: d.User.Profile.FullName,
|
|
|
|
|
DisplayName: d.User.Profile.DisplayName,
|
|
|
|
|
Phone: d.User.Profile.Phone,
|
|
|
|
|
AvatarURL: d.User.Profile.AvatarURL,
|
|
|
|
|
JobTitle: d.User.Profile.JobTitle,
|
|
|
|
|
EmployeeNo: d.User.Profile.EmployeeNo,
|
|
|
|
|
Bio: d.User.Profile.Bio,
|
|
|
|
|
Timezone: d.User.Profile.Timezone,
|
|
|
|
|
Locale: d.User.Profile.Locale,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process mentions to get mentioned users with profiles
|
|
|
|
|
if d.Mentions != nil {
|
|
|
|
|
mentions := map[string]interface{}(d.Mentions)
|
|
|
|
|
if userIDs, ok := mentions["user_ids"]; ok {
|
|
|
|
|
if userIDList, ok := userIDs.([]interface{}); ok {
|
|
|
|
|
mentionedUsersList := make([]contract.UserResponse, 0)
|
|
|
|
|
for _, userID := range userIDList {
|
|
|
|
|
if userIDStr, ok := userID.(string); ok {
|
|
|
|
|
if userUUID, err := uuid.Parse(userIDStr); err == nil {
|
|
|
|
|
if user, exists := userMap[userUUID]; exists {
|
|
|
|
|
userResp := contract.UserResponse{
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
Name: user.Name,
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
IsActive: user.IsActive,
|
|
|
|
|
CreatedAt: user.CreatedAt,
|
|
|
|
|
UpdatedAt: user.UpdatedAt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include user profile if available
|
|
|
|
|
if user.Profile != nil {
|
|
|
|
|
userResp.Profile = &contract.UserProfileResponse{
|
|
|
|
|
UserID: user.Profile.UserID,
|
|
|
|
|
FullName: user.Profile.FullName,
|
|
|
|
|
DisplayName: user.Profile.DisplayName,
|
|
|
|
|
Phone: user.Profile.Phone,
|
|
|
|
|
AvatarURL: user.Profile.AvatarURL,
|
|
|
|
|
JobTitle: user.Profile.JobTitle,
|
|
|
|
|
EmployeeNo: user.Profile.EmployeeNo,
|
|
|
|
|
Bio: user.Profile.Bio,
|
|
|
|
|
Timezone: user.Profile.Timezone,
|
|
|
|
|
Locale: user.Profile.Locale,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mentionedUsersList = append(mentionedUsersList, userResp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
resp.MentionedUsers = mentionedUsersList
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func EnhancedDispositionsWithPreloadedDataToContract(list []entities.LetterIncomingDisposition) []contract.EnhancedDispositionResponse {
|
|
|
|
|
out := make([]contract.EnhancedDispositionResponse, 0, len(list))
|
|
|
|
|
for _, d := range list {
|
|
|
|
|
resp := contract.EnhancedDispositionResponse{
|
|
|
|
|
ID: d.ID,
|
|
|
|
|
LetterID: d.LetterID,
|
|
|
|
|
DepartmentID: d.DepartmentID,
|
|
|
|
|
Notes: d.Notes,
|
|
|
|
|
ReadAt: d.ReadAt,
|
|
|
|
|
CreatedBy: d.CreatedBy,
|
|
|
|
|
CreatedAt: d.CreatedAt,
|
|
|
|
|
UpdatedAt: d.UpdatedAt,
|
|
|
|
|
Departments: []contract.DispositionDepartmentResponse{},
|
|
|
|
|
Actions: []contract.DispositionActionSelectionResponse{},
|
|
|
|
|
DispositionNotes: []contract.DispositionNoteResponse{},
|
|
|
|
|
Department: DepartmentToContract(d.Department),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(d.Departments) > 0 {
|
|
|
|
|
resp.Departments = DispositionDepartmentsWithDetailsToContract(d.Departments)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include preloaded action selections with details
|
|
|
|
|
if len(d.ActionSelections) > 0 {
|
|
|
|
|
resp.Actions = DispositionActionSelectionsWithDetailsToContract(d.ActionSelections)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include preloaded notes with user details
|
|
|
|
|
if len(d.DispositionNotes) > 0 {
|
|
|
|
|
resp.DispositionNotes = DispositionNotesWithDetailsToContract(d.DispositionNotes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = append(out, resp)
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|