mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 15:25:43 +00:00
Merge branch 'feat/daily-checklist-upload-documents' into 'development'
[FEAT][BE]: add api upload documents daily checklist See merge request mbugroup/lti-api!154
This commit is contained in:
@@ -7,12 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Phases struct {
|
type Phases struct {
|
||||||
Id uint `gorm:"primaryKey"`
|
Id uint `gorm:"primaryKey"`
|
||||||
Name string `gorm:"not null"`
|
Name string `gorm:"not null"`
|
||||||
IsActive bool `gorm:"not null;default:true"`
|
IsActive bool `gorm:"not null;default:true"`
|
||||||
Category string `gorm:"type:category_code;not null"`
|
Category string `gorm:"type:category_code;not null"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
ActivityCount int `gorm:"-" json:"-"`
|
||||||
|
|
||||||
Activities []PhaseActivity `gorm:"foreignKey:PhaseId;references:Id"`
|
Activities []PhaseActivity `gorm:"foreignKey:PhaseId;references:Id"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ func (u *DailyChecklistController) GetAll(c *fiber.Ctx) error {
|
|||||||
Name: name,
|
Name: name,
|
||||||
Status: status,
|
Status: status,
|
||||||
Category: item.Category,
|
Category: item.Category,
|
||||||
|
RejectReason: item.RejectReason,
|
||||||
Date: item.Date,
|
Date: item.Date,
|
||||||
Kandang: kandang,
|
Kandang: kandang,
|
||||||
CreatedUser: nil,
|
CreatedUser: nil,
|
||||||
@@ -150,6 +151,10 @@ func (u *DailyChecklistController) GetSummary(c *fiber.Ctx) error {
|
|||||||
performanceMap[summary.EmployeeID] = &dto.DailyChecklistPerformanceOverviewDTO{
|
performanceMap[summary.EmployeeID] = &dto.DailyChecklistPerformanceOverviewDTO{
|
||||||
EmployeeID: summary.EmployeeID,
|
EmployeeID: summary.EmployeeID,
|
||||||
EmployeeName: summary.EmployeeName,
|
EmployeeName: summary.EmployeeName,
|
||||||
|
Kandang: dto.DailyChecklistReportEntityDTO{
|
||||||
|
Id: summary.KandangID,
|
||||||
|
Name: summary.KandangName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,12 +308,22 @@ func (u *DailyChecklistController) GetOne(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
documentDTOs := make([]dto.DailyChecklistDocumentDTO, len(detail.DocumentURLs))
|
||||||
|
for i, doc := range detail.DocumentURLs {
|
||||||
|
documentDTOs[i] = dto.DailyChecklistDocumentDTO{
|
||||||
|
Id: doc.ID,
|
||||||
|
Name: doc.Name,
|
||||||
|
Size: doc.Size,
|
||||||
|
URL: doc.URL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).
|
return c.Status(fiber.StatusOK).
|
||||||
JSON(response.Success{
|
JSON(response.Success{
|
||||||
Code: fiber.StatusOK,
|
Code: fiber.StatusOK,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Message: "Get dailyChecklist successfully",
|
Message: "Get dailyChecklist successfully",
|
||||||
Data: dto.ToDailyChecklistDetailDTO(detail.Checklist, detail.Phases, detail.Tasks, detail.AssignedEmployees, detail.TotalActivities, detail.Progress),
|
Data: dto.ToDailyChecklistDetailDTO(detail.Checklist, detail.Phases, detail.Tasks, detail.AssignedEmployees, detail.TotalActivities, detail.Progress, documentDTOs),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +357,12 @@ func (u *DailyChecklistController) UpdateOne(c *fiber.Ctx) error {
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form, err := c.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form")
|
||||||
|
}
|
||||||
|
req.Documents = form.File["documents"]
|
||||||
|
|
||||||
if err := c.BodyParser(req); err != nil {
|
if err := c.BodyParser(req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type DailyChecklistListDTO struct {
|
|||||||
TotalPhase int `json:"total_phase"`
|
TotalPhase int `json:"total_phase"`
|
||||||
TotalActivity int `json:"total_activity"`
|
TotalActivity int `json:"total_activity"`
|
||||||
Progress int `json:"progress"`
|
Progress int `json:"progress"`
|
||||||
|
RejectReason *string `json:"reject_reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistDetailDTO struct {
|
type DailyChecklistDetailDTO struct {
|
||||||
@@ -40,6 +41,14 @@ type DailyChecklistDetailDTO struct {
|
|||||||
AssignedEmployees []employeeDTO.EmployeesRelationDTO `json:"assigned_employees"`
|
AssignedEmployees []employeeDTO.EmployeesRelationDTO `json:"assigned_employees"`
|
||||||
TotalActivity int `json:"total_activity"`
|
TotalActivity int `json:"total_activity"`
|
||||||
Progress float64 `json:"progress"`
|
Progress float64 `json:"progress"`
|
||||||
|
DocumentURLs []DailyChecklistDocumentDTO `json:"document_urls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DailyChecklistDocumentDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size float64 `json:"size"`
|
||||||
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistSummaryDTO struct {
|
type DailyChecklistSummaryDTO struct {
|
||||||
@@ -55,11 +64,12 @@ type DailyChecklistSummaryDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistPerformanceOverviewDTO struct {
|
type DailyChecklistPerformanceOverviewDTO struct {
|
||||||
EmployeeID uint `json:"employee_id"`
|
EmployeeID uint `json:"employee_id"`
|
||||||
EmployeeName string `json:"employee_name"`
|
EmployeeName string `json:"employee_name"`
|
||||||
TotalActivity int `json:"total_activity"`
|
Kandang DailyChecklistReportEntityDTO `json:"kandang"`
|
||||||
ActivityDone int `json:"activity_done"`
|
TotalActivity int `json:"total_activity"`
|
||||||
ActivityLeft int `json:"activity_left"`
|
ActivityDone int `json:"activity_done"`
|
||||||
|
ActivityLeft int `json:"activity_left"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistReportDTO struct {
|
type DailyChecklistReportDTO struct {
|
||||||
@@ -165,10 +175,11 @@ func ToDailyChecklistListDTO(e entity.DailyChecklist) DailyChecklistListDTO {
|
|||||||
TotalPhase: 0,
|
TotalPhase: 0,
|
||||||
TotalActivity: 0,
|
TotalActivity: 0,
|
||||||
Progress: 0,
|
Progress: 0,
|
||||||
|
RejectReason: e.RejectReason,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToDailyChecklistDetailDTO(checklist entity.DailyChecklist, phases []entity.DailyChecklistPhase, tasks []entity.DailyChecklistActivityTask, assignedEmployees []entity.Employee, totalActivities int, progress float64) DailyChecklistDetailDTO {
|
func ToDailyChecklistDetailDTO(checklist entity.DailyChecklist, phases []entity.DailyChecklistPhase, tasks []entity.DailyChecklistActivityTask, assignedEmployees []entity.Employee, totalActivities int, progress float64, documentURLs []DailyChecklistDocumentDTO) DailyChecklistDetailDTO {
|
||||||
phaseDTOs := make([]DailyChecklistPhaseDTO, 0, len(phases))
|
phaseDTOs := make([]DailyChecklistPhaseDTO, 0, len(phases))
|
||||||
for _, phase := range phases {
|
for _, phase := range phases {
|
||||||
phaseDTOs = append(phaseDTOs, DailyChecklistPhaseDTO{
|
phaseDTOs = append(phaseDTOs, DailyChecklistPhaseDTO{
|
||||||
@@ -228,5 +239,6 @@ func ToDailyChecklistDetailDTO(checklist entity.DailyChecklist, phases []entity.
|
|||||||
AssignedEmployees: assignedDTOs,
|
AssignedEmployees: assignedDTOs,
|
||||||
TotalActivity: totalActivities,
|
TotalActivity: totalActivities,
|
||||||
Progress: progress,
|
Progress: progress,
|
||||||
|
DocumentURLs: documentURLs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package dailyChecklists
|
package dailyChecklists
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
|
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||||
rDailyChecklist "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/repositories"
|
rDailyChecklist "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/repositories"
|
||||||
sDailyChecklist "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/services"
|
sDailyChecklist "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/services"
|
||||||
rPhases "gitlab.com/mbugroup/lti-api.git/internal/modules/master/phasess/repositories"
|
rPhases "gitlab.com/mbugroup/lti-api.git/internal/modules/master/phasess/repositories"
|
||||||
@@ -19,8 +24,13 @@ func (DailyChecklistModule) RegisterRoutes(router fiber.Router, db *gorm.DB, val
|
|||||||
dailyChecklistRepo := rDailyChecklist.NewDailyChecklistRepository(db)
|
dailyChecklistRepo := rDailyChecklist.NewDailyChecklistRepository(db)
|
||||||
phasesRepo := rPhases.NewPhasesRepository(db)
|
phasesRepo := rPhases.NewPhasesRepository(db)
|
||||||
userRepo := rUser.NewUserRepository(db)
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
documentRepo := commonRepo.NewDocumentRepository(db)
|
||||||
|
documentSvc, err := commonSvc.NewDocumentServiceFromConfig(context.Background(), documentRepo)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to create document service: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
dailyChecklistService := sDailyChecklist.NewDailyChecklistService(dailyChecklistRepo, phasesRepo, validate)
|
dailyChecklistService := sDailyChecklist.NewDailyChecklistService(dailyChecklistRepo, phasesRepo, validate, documentSvc)
|
||||||
userService := sUser.NewUserService(userRepo, validate)
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
DailyChecklistRoutes(router, userService, dailyChecklistService)
|
DailyChecklistRoutes(router, userService, dailyChecklistService)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
middleware "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/repositories"
|
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/repositories"
|
||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/validations"
|
||||||
phaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/phasess/repositories"
|
phaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/phasess/repositories"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
@@ -39,10 +41,18 @@ type DailyChecklistService interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type dailyChecklistService struct {
|
type dailyChecklistService struct {
|
||||||
Log *logrus.Logger
|
Log *logrus.Logger
|
||||||
Validate *validator.Validate
|
Validate *validator.Validate
|
||||||
Repository repository.DailyChecklistRepository
|
Repository repository.DailyChecklistRepository
|
||||||
PhaseRepo phaseRepo.PhasesRepository
|
PhaseRepo phaseRepo.PhasesRepository
|
||||||
|
DocumentSvc commonSvc.DocumentService
|
||||||
|
}
|
||||||
|
|
||||||
|
type DailyChecklistDocument struct {
|
||||||
|
ID uint
|
||||||
|
Name string
|
||||||
|
Size float64
|
||||||
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistDetail struct {
|
type DailyChecklistDetail struct {
|
||||||
@@ -52,6 +62,7 @@ type DailyChecklistDetail struct {
|
|||||||
AssignedEmployees []entity.Employee
|
AssignedEmployees []entity.Employee
|
||||||
TotalActivities int
|
TotalActivities int
|
||||||
Progress float64
|
Progress float64
|
||||||
|
DocumentURLs []DailyChecklistDocument
|
||||||
}
|
}
|
||||||
|
|
||||||
type DailyChecklistListItem struct {
|
type DailyChecklistListItem struct {
|
||||||
@@ -60,6 +71,7 @@ type DailyChecklistListItem struct {
|
|||||||
Date time.Time
|
Date time.Time
|
||||||
Category string
|
Category string
|
||||||
Status *string
|
Status *string
|
||||||
|
RejectReason *string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
Kandang entity.Kandang
|
Kandang entity.Kandang
|
||||||
@@ -108,12 +120,13 @@ type DailyChecklistReportCategory struct {
|
|||||||
Baik int
|
Baik int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDailyChecklistService(repo repository.DailyChecklistRepository, phaseRepo phaseRepo.PhasesRepository, validate *validator.Validate) DailyChecklistService {
|
func NewDailyChecklistService(repo repository.DailyChecklistRepository, phaseRepo phaseRepo.PhasesRepository, validate *validator.Validate, documentSvc commonSvc.DocumentService) DailyChecklistService {
|
||||||
return &dailyChecklistService{
|
return &dailyChecklistService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
Validate: validate,
|
Validate: validate,
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
PhaseRepo: phaseRepo,
|
PhaseRepo: phaseRepo,
|
||||||
|
DocumentSvc: documentSvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +171,7 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
|
|
||||||
if params.Search != "" {
|
if params.Search != "" {
|
||||||
like := "%" + params.Search + "%"
|
like := "%" + params.Search + "%"
|
||||||
db = db.Where("(k.name ILIKE ? OR dc.category ILIKE ?)", like, like)
|
db = db.Where("(k.name ILIKE ? OR dc.category::text ILIKE ?)", like, like)
|
||||||
}
|
}
|
||||||
|
|
||||||
countDB := db.Session(&gorm.Session{})
|
countDB := db.Session(&gorm.Session{})
|
||||||
@@ -174,6 +187,7 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
Date time.Time
|
Date time.Time
|
||||||
Category string
|
Category string
|
||||||
Status *string
|
Status *string
|
||||||
|
RejectReason *string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
KandangID uint
|
KandangID uint
|
||||||
@@ -192,6 +206,7 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
dc.date,
|
dc.date,
|
||||||
dc.category,
|
dc.category,
|
||||||
dc.status,
|
dc.status,
|
||||||
|
dc.reject_reason,
|
||||||
dc.created_at,
|
dc.created_at,
|
||||||
dc.updated_at,
|
dc.updated_at,
|
||||||
dc.kandang_id,
|
dc.kandang_id,
|
||||||
@@ -265,6 +280,7 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
|||||||
Date: row.Date,
|
Date: row.Date,
|
||||||
Category: row.Category,
|
Category: row.Category,
|
||||||
Status: row.Status,
|
Status: row.Status,
|
||||||
|
RejectReason: row.RejectReason,
|
||||||
CreatedAt: row.CreatedAt,
|
CreatedAt: row.CreatedAt,
|
||||||
UpdatedAt: row.UpdatedAt,
|
UpdatedAt: row.UpdatedAt,
|
||||||
Kandang: kandangMap[row.KandangID],
|
Kandang: kandangMap[row.KandangID],
|
||||||
@@ -345,6 +361,29 @@ func (s dailyChecklistService) GetDetail(c *fiber.Ctx, id uint) (*DailyChecklist
|
|||||||
progress = math.Round((float64(completedAssignments) / float64(totalAssignments)) * 100)
|
progress = math.Round((float64(completedAssignments) / float64(totalAssignments)) * 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
documentURLs := make([]DailyChecklistDocument, 0)
|
||||||
|
if s.DocumentSvc != nil {
|
||||||
|
documents, err := s.DocumentSvc.ListByTarget(c.Context(), string(utils.DocumentTypeDailyChecklist), uint64(id))
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to list documents for daily checklist %d: %+v", id, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, doc := range documents {
|
||||||
|
url, err := s.DocumentSvc.PresignURL(c.Context(), doc, 0)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to presign document %d for daily checklist %d: %+v", doc.Id, id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
documentURLs = append(documentURLs, DailyChecklistDocument{
|
||||||
|
ID: doc.Id,
|
||||||
|
Name: doc.Name,
|
||||||
|
Size: doc.Size,
|
||||||
|
URL: url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &DailyChecklistDetail{
|
return &DailyChecklistDetail{
|
||||||
Checklist: *checklist,
|
Checklist: *checklist,
|
||||||
Phases: phases,
|
Phases: phases,
|
||||||
@@ -352,6 +391,7 @@ func (s dailyChecklistService) GetDetail(c *fiber.Ctx, id uint) (*DailyChecklist
|
|||||||
AssignedEmployees: assignedEmployees,
|
AssignedEmployees: assignedEmployees,
|
||||||
TotalActivities: totalActivities,
|
TotalActivities: totalActivities,
|
||||||
Progress: progress,
|
Progress: progress,
|
||||||
|
DocumentURLs: documentURLs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +417,7 @@ func (s *dailyChecklistService) CreateOne(c *fiber.Ctx, req *validation.Create)
|
|||||||
|
|
||||||
err = s.Repository.DB().WithContext(c.Context()).Clauses(clause.OnConflict{
|
err = s.Repository.DB().WithContext(c.Context()).Clauses(clause.OnConflict{
|
||||||
Columns: []clause.Column{{Name: "date"}, {Name: "kandang_id"}, {Name: "category"}},
|
Columns: []clause.Column{{Name: "date"}, {Name: "kandang_id"}, {Name: "category"}},
|
||||||
DoUpdates: clause.Assignments(map[string]any{"status": status, "updated_at": time.Now()}),
|
DoUpdates: clause.Assignments(map[string]any{"updated_at": time.Now()}),
|
||||||
}).Create(createBody).Error
|
}).Create(createBody).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Errorf("Failed to upsert dailyChecklist: %+v", err)
|
s.Log.Errorf("Failed to upsert dailyChecklist: %+v", err)
|
||||||
@@ -392,6 +432,22 @@ func (s dailyChecklistService) UpdateOne(c *fiber.Ctx, req *validation.Update, i
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deletedIDs := make([]uint, 0)
|
||||||
|
if req.DeletedDocumentIDs != nil {
|
||||||
|
parts := strings.Split(*req.DeletedDocumentIDs, ",")
|
||||||
|
for _, part := range parts {
|
||||||
|
part = strings.TrimSpace(part)
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parsedID, err := strconv.ParseUint(part, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "invalid deleted_document_ids")
|
||||||
|
}
|
||||||
|
deletedIDs = append(deletedIDs, uint(parsedID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateBody := map[string]any{
|
updateBody := map[string]any{
|
||||||
"status": req.Status,
|
"status": req.Status,
|
||||||
}
|
}
|
||||||
@@ -400,6 +456,40 @@ func (s dailyChecklistService) UpdateOne(c *fiber.Ctx, req *validation.Update, i
|
|||||||
updateBody["reject_reason"] = *req.RejectReason
|
updateBody["reject_reason"] = *req.RejectReason
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID, err := middleware.ActorIDFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return &entity.DailyChecklist{}, fiber.NewError(fiber.StatusUnauthorized, "Failed to get actor ID from context")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deletedIDs) > 0 && s.DocumentSvc != nil {
|
||||||
|
if err := s.DocumentSvc.DeleteDocuments(c.Context(), deletedIDs, true); err != nil {
|
||||||
|
s.Log.Errorf("Failed to delete daily checklist documents: %+v", err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete daily checklist documents")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Documents) > 0 {
|
||||||
|
documentFiles := make([]commonSvc.DocumentFile, 0, len(req.Documents))
|
||||||
|
for idx, file := range req.Documents {
|
||||||
|
documentFiles = append(documentFiles, commonSvc.DocumentFile{
|
||||||
|
File: file,
|
||||||
|
Type: string(utils.DocumentTypeDailyChecklist),
|
||||||
|
Index: &idx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{
|
||||||
|
DocumentableType: string(utils.DocumentTypeDailyChecklist),
|
||||||
|
DocumentableID: uint64(id),
|
||||||
|
CreatedBy: &actorID,
|
||||||
|
Files: documentFiles,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to upload daily checklist documents: %+v", err)
|
||||||
|
return &entity.DailyChecklist{}, fiber.NewError(fiber.StatusInternalServerError, "Failed to upload daily checklist documents")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "DailyChecklist not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "DailyChecklist not found")
|
||||||
@@ -869,7 +959,8 @@ func (s dailyChecklistService) GetReport(c *fiber.Ctx, params *validation.Report
|
|||||||
Joins("JOIN areas a ON a.id = loc.area_id").
|
Joins("JOIN areas a ON a.id = loc.area_id").
|
||||||
Joins("JOIN phases p ON p.id = dcat.phase_id").
|
Joins("JOIN phases p ON p.id = dcat.phase_id").
|
||||||
Where("EXTRACT(MONTH FROM dc.date) = ?", params.Month).
|
Where("EXTRACT(MONTH FROM dc.date) = ?", params.Month).
|
||||||
Where("EXTRACT(YEAR FROM dc.date) = ?", params.Year)
|
Where("EXTRACT(YEAR FROM dc.date) = ?", params.Year).
|
||||||
|
Where("dc.status = ?", "APPROVED")
|
||||||
|
|
||||||
if params.AreaID != nil {
|
if params.AreaID != nil {
|
||||||
db = db.Where("a.id = ?", *params.AreaID)
|
db = db.Where("a.id = ?", *params.AreaID)
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mime/multipart"
|
||||||
|
)
|
||||||
|
|
||||||
type Create struct {
|
type Create struct {
|
||||||
Date string `json:"date" validate:"required"`
|
Date string `json:"date" validate:"required"`
|
||||||
KandangId uint `json:"kandang_id" validate:"required"`
|
KandangId uint `json:"kandang_id" validate:"required"`
|
||||||
@@ -8,8 +12,10 @@ type Create struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
Status string `json:"status" validate:"required"`
|
Status string `form:"status" json:"status" validate:"required"`
|
||||||
RejectReason *string `json:"reject_reason"`
|
RejectReason *string `form:"reject_reason" json:"reject_reason"`
|
||||||
|
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
|
||||||
|
DeletedDocumentIDs *string `form:"deleted_document_ids" json:"deleted_document_ids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ type PhasesRelationDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PhasesListDTO struct {
|
type PhasesListDTO struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Category string `json:"category"`
|
Category string `json:"category"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
|
ActivityCount int `json:"activity_count"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PhasesDetailDTO struct {
|
type PhasesDetailDTO struct {
|
||||||
@@ -44,12 +45,13 @@ func ToPhasesListDTO(e entity.Phases) PhasesListDTO {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return PhasesListDTO{
|
return PhasesListDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
Category: e.Category,
|
Category: e.Category,
|
||||||
IsActive: e.IsActive,
|
IsActive: e.IsActive,
|
||||||
CreatedAt: e.CreatedAt,
|
ActivityCount: e.ActivityCount,
|
||||||
CreatedUser: createdUser,
|
CreatedAt: e.CreatedAt,
|
||||||
|
CreatedUser: createdUser,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,40 @@ func (s phasesService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.
|
|||||||
s.Log.Errorf("Failed to get phasess: %+v", err)
|
s.Log.Errorf("Failed to get phasess: %+v", err)
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(phasess) > 0 {
|
||||||
|
ids := make([]uint, 0, len(phasess))
|
||||||
|
for _, phase := range phasess {
|
||||||
|
ids = append(ids, phase.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
type activityCountRow struct {
|
||||||
|
PhaseID uint
|
||||||
|
Count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows []activityCountRow
|
||||||
|
if err := s.Repository.DB().WithContext(c.Context()).
|
||||||
|
Table("phase_activities").
|
||||||
|
Select("phase_id, COUNT(*) AS count").
|
||||||
|
Where("phase_id IN ? AND deleted_at IS NULL", ids).
|
||||||
|
Group("phase_id").
|
||||||
|
Scan(&rows).Error; err != nil {
|
||||||
|
s.Log.Errorf("Failed to count phase activities: %+v", err)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
countMap := make(map[uint]int64, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
countMap[row.PhaseID] = row.Count
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range phasess {
|
||||||
|
if count, ok := countMap[phasess[i].Id]; ok {
|
||||||
|
phasess[i].ActivityCount = int(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return phasess, total, nil
|
return phasess, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -432,6 +432,8 @@ const (
|
|||||||
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
||||||
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
||||||
DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM"
|
DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM"
|
||||||
|
|
||||||
|
DocumentTypeDailyChecklist DocumentType = "DAILY_CHECKLIST_DOCUMENT"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user