mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 21:41:55 +00:00
add api summary and update status
This commit is contained in:
@@ -53,6 +53,81 @@ func (u *DailyChecklistController) GetAll(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *DailyChecklistController) GetSummary(c *fiber.Ctx) error {
|
||||
query := &validation.SummaryQuery{
|
||||
DateFrom: c.Query("date_from"),
|
||||
DateTo: c.Query("date_to"),
|
||||
Category: c.Query("category"),
|
||||
}
|
||||
|
||||
if query.DateFrom == "" || query.DateTo == "" {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "date_from and date_to are required")
|
||||
}
|
||||
|
||||
if kandangParam := c.Query("kandang_id"); kandangParam != "" {
|
||||
kandangID, err := strconv.ParseUint(kandangParam, 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid kandang_id")
|
||||
}
|
||||
value := uint(kandangID)
|
||||
query.KandangID = &value
|
||||
}
|
||||
|
||||
result, err := u.DailyChecklistService.GetSummary(c, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type summaryResponse struct {
|
||||
PerformanceOverview []dto.DailyChecklistPerformanceOverviewDTO `json:"performance_overview"`
|
||||
TrackingABK []dto.DailyChecklistSummaryDTO `json:"tracking_abk"`
|
||||
}
|
||||
|
||||
performanceMap := make(map[uint]*dto.DailyChecklistPerformanceOverviewDTO)
|
||||
tracking := make([]dto.DailyChecklistSummaryDTO, len(result))
|
||||
|
||||
for i, summary := range result {
|
||||
tracking[i] = dto.DailyChecklistSummaryDTO{
|
||||
EmployeeID: summary.EmployeeID,
|
||||
EmployeeName: summary.EmployeeName,
|
||||
KandangID: summary.KandangID,
|
||||
KandangName: summary.KandangName,
|
||||
TotalActivity: summary.TotalActivity,
|
||||
ActivityDone: summary.ActivityDone,
|
||||
ActivityLeft: summary.ActivityLeft,
|
||||
CompletionRate: summary.CompletionRate,
|
||||
LastActivity: summary.LastActivity,
|
||||
}
|
||||
|
||||
if _, ok := performanceMap[summary.EmployeeID]; !ok {
|
||||
performanceMap[summary.EmployeeID] = &dto.DailyChecklistPerformanceOverviewDTO{
|
||||
EmployeeID: summary.EmployeeID,
|
||||
EmployeeName: summary.EmployeeName,
|
||||
}
|
||||
}
|
||||
|
||||
performanceMap[summary.EmployeeID].TotalActivity += summary.TotalActivity
|
||||
performanceMap[summary.EmployeeID].ActivityDone += summary.ActivityDone
|
||||
performanceMap[summary.EmployeeID].ActivityLeft += summary.ActivityLeft
|
||||
}
|
||||
|
||||
performance := make([]dto.DailyChecklistPerformanceOverviewDTO, 0, len(performanceMap))
|
||||
for _, v := range performanceMap {
|
||||
performance = append(performance, *v)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.Success{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Get daily checklist summary successfully",
|
||||
Data: summaryResponse{
|
||||
PerformanceOverview: performance,
|
||||
TrackingABK: tracking,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (u *DailyChecklistController) GetOne(c *fiber.Ctx) error {
|
||||
param := c.Params("idDailyChecklist")
|
||||
|
||||
@@ -98,7 +173,7 @@ func (u *DailyChecklistController) CreateOne(c *fiber.Ctx) error {
|
||||
|
||||
func (u *DailyChecklistController) UpdateOne(c *fiber.Ctx) error {
|
||||
req := new(validation.Update)
|
||||
param := c.Params("id")
|
||||
param := c.Params("idDailyChecklist")
|
||||
|
||||
id, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
|
||||
@@ -39,6 +39,26 @@ type DailyChecklistDetailDTO struct {
|
||||
Progress float64 `json:"progress"`
|
||||
}
|
||||
|
||||
type DailyChecklistSummaryDTO struct {
|
||||
EmployeeID uint `json:"employee_id"`
|
||||
EmployeeName string `json:"employee_name"`
|
||||
KandangID uint `json:"kandang_id"`
|
||||
KandangName string `json:"kandang_name"`
|
||||
TotalActivity int `json:"total_activity"`
|
||||
ActivityDone int `json:"activity_done"`
|
||||
ActivityLeft int `json:"activity_left"`
|
||||
CompletionRate int `json:"completion_rate"`
|
||||
LastActivity *time.Time `json:"last_activity,omitempty"`
|
||||
}
|
||||
|
||||
type DailyChecklistPerformanceOverviewDTO struct {
|
||||
EmployeeID uint `json:"employee_id"`
|
||||
EmployeeName string `json:"employee_name"`
|
||||
TotalActivity int `json:"total_activity"`
|
||||
ActivityDone int `json:"activity_done"`
|
||||
ActivityLeft int `json:"activity_left"`
|
||||
}
|
||||
|
||||
type DailyChecklistPhaseDTO struct {
|
||||
Id uint `json:"id"`
|
||||
PhaseId uint `json:"phase_id"`
|
||||
|
||||
@@ -17,6 +17,8 @@ func DailyChecklistRoutes(v1 fiber.Router, u user.UserService, s dailyChecklist.
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
|
||||
route.Get("/summary", ctrl.GetSummary)
|
||||
|
||||
// create daily checklist
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
|
||||
@@ -53,6 +55,6 @@ func DailyChecklistRoutes(v1 fiber.Router, u user.UserService, s dailyChecklist.
|
||||
*/
|
||||
route.Post("/assignment", ctrl.UpdateAssignment)
|
||||
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Patch("/:idDailyChecklist", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type DailyChecklistService interface {
|
||||
UpdateAssignment(ctx *fiber.Ctx, req *validation.UpdateAssignment) error
|
||||
GetChecklistPhaseIDs(ctx *fiber.Ctx, checklistID uint) ([]uint, error)
|
||||
GetDetail(ctx *fiber.Ctx, id uint) (*DailyChecklistDetail, error)
|
||||
GetSummary(ctx *fiber.Ctx, params *validation.SummaryQuery) ([]DailyChecklistSummary, error)
|
||||
}
|
||||
|
||||
type dailyChecklistService struct {
|
||||
@@ -52,6 +53,18 @@ type DailyChecklistDetail struct {
|
||||
Progress float64
|
||||
}
|
||||
|
||||
type DailyChecklistSummary struct {
|
||||
EmployeeID uint
|
||||
EmployeeName string
|
||||
KandangID uint
|
||||
KandangName string
|
||||
TotalActivity int
|
||||
ActivityDone int
|
||||
ActivityLeft int
|
||||
CompletionRate int
|
||||
LastActivity *time.Time
|
||||
}
|
||||
|
||||
func NewDailyChecklistService(repo repository.DailyChecklistRepository, phaseRepo phaseRepo.PhasesRepository, validate *validator.Validate) DailyChecklistService {
|
||||
return &dailyChecklistService{
|
||||
Log: utils.Log,
|
||||
@@ -202,14 +215,12 @@ func (s dailyChecklistService) UpdateOne(c *fiber.Ctx, req *validation.Update, i
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateBody := make(map[string]any)
|
||||
|
||||
if req.Name != nil {
|
||||
updateBody["name"] = *req.Name
|
||||
updateBody := map[string]any{
|
||||
"status": req.Status,
|
||||
}
|
||||
|
||||
if len(updateBody) == 0 {
|
||||
return s.GetOne(c, id)
|
||||
if req.RejectReason != nil {
|
||||
updateBody["reject_reason"] = *req.RejectReason
|
||||
}
|
||||
|
||||
if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
||||
@@ -579,3 +590,86 @@ func (s dailyChecklistService) AssignTasks(c *fiber.Ctx, id uint, req *validatio
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s dailyChecklistService) GetSummary(c *fiber.Ctx, params *validation.SummaryQuery) ([]DailyChecklistSummary, error) {
|
||||
if err := s.Validate.Struct(params); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dateFrom, err := time.Parse("2006-01-02", params.DateFrom)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "invalid date_from format, use YYYY-MM-DD")
|
||||
}
|
||||
|
||||
dateTo, err := time.Parse("2006-01-02", params.DateTo)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "invalid date_to format, use YYYY-MM-DD")
|
||||
}
|
||||
|
||||
type summaryRow struct {
|
||||
EmployeeID uint
|
||||
EmployeeName string
|
||||
KandangID uint
|
||||
KandangName string
|
||||
TotalActivity int64
|
||||
ActivityDone int64
|
||||
ActivityLeft int64
|
||||
LastActivity *time.Time
|
||||
}
|
||||
|
||||
rows := make([]summaryRow, 0)
|
||||
db := s.Repository.DB().WithContext(c.Context()).
|
||||
Table("daily_checklist_activity_task_assignments AS a").
|
||||
Select(`
|
||||
a.employee_id,
|
||||
e.name AS employee_name,
|
||||
d.kandang_id,
|
||||
k.name AS kandang_name,
|
||||
COUNT(*) AS total_activity,
|
||||
SUM(CASE WHEN a.checked THEN 1 ELSE 0 END) AS activity_done,
|
||||
SUM(CASE WHEN NOT a.checked THEN 1 ELSE 0 END) AS activity_left,
|
||||
MAX(a.updated_at) AS last_activity`).
|
||||
Joins("JOIN daily_checklist_activity_tasks t ON t.id = a.task_id").
|
||||
Joins("JOIN daily_checklists d ON d.id = t.checklist_id").
|
||||
Joins("JOIN kandangs k ON k.id = d.kandang_id").
|
||||
Joins("JOIN employees e ON e.id = a.employee_id").
|
||||
Where("d.date BETWEEN ? AND ?", dateFrom, dateTo)
|
||||
|
||||
if params.Category != "" {
|
||||
db = db.Where("d.category = ?", params.Category)
|
||||
}
|
||||
|
||||
if params.KandangID != nil {
|
||||
db = db.Where("d.kandang_id = ?", *params.KandangID)
|
||||
}
|
||||
|
||||
if err := db.
|
||||
Group("a.employee_id, e.name, d.kandang_id, k.name").
|
||||
Order("e.name ASC").
|
||||
Find(&rows).Error; err != nil {
|
||||
s.Log.Errorf("Failed to get daily checklist summary: %+v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summaries := make([]DailyChecklistSummary, len(rows))
|
||||
for i, row := range rows {
|
||||
completionRate := 0
|
||||
if row.TotalActivity > 0 {
|
||||
completionRate = int(math.Round(float64(row.ActivityDone) / float64(row.TotalActivity) * 100))
|
||||
}
|
||||
|
||||
summaries[i] = DailyChecklistSummary{
|
||||
EmployeeID: row.EmployeeID,
|
||||
EmployeeName: row.EmployeeName,
|
||||
KandangID: row.KandangID,
|
||||
KandangName: row.KandangName,
|
||||
TotalActivity: int(row.TotalActivity),
|
||||
ActivityDone: int(row.ActivityDone),
|
||||
ActivityLeft: int(row.ActivityLeft),
|
||||
CompletionRate: completionRate,
|
||||
LastActivity: row.LastActivity,
|
||||
}
|
||||
}
|
||||
|
||||
return summaries, nil
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ type Create struct {
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty"`
|
||||
Status string `json:"status" validate:"required"`
|
||||
RejectReason *string `json:"reject_reason" validate:"required"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
@@ -31,3 +32,10 @@ type UpdateAssignment struct {
|
||||
Checked *bool `json:"checked,omitempty"`
|
||||
Note *string `json:"note,omitempty"`
|
||||
}
|
||||
|
||||
type SummaryQuery struct {
|
||||
DateFrom string `query:"date_from" validate:"required"`
|
||||
DateTo string `query:"date_to" validate:"required"`
|
||||
Category string `query:"category" validate:"omitempty"`
|
||||
KandangID *uint `query:"kandang_id" validate:"omitempty"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user