This commit is contained in:
@@ -2,6 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -542,3 +543,116 @@ func ListAttendanceShiftsHandler(db *gorm.DB) fiber.Handler {
|
||||
return c.JSON(fiber.Map{"data": out, "date": date, "dayOfWeek": dayOfWeek})
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/classes/:rkId/leave-requests
|
||||
func GetLeaveRequestsHandler(db *gorm.DB, qldtClient *qldt.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
classRkID, _ := strconv.ParseInt(c.Params("rkId"), 10, 64)
|
||||
courseID, _ := strconv.ParseInt(c.Query("courseId"), 10, 64)
|
||||
date := c.Query("date", qldt.NowDateVN())
|
||||
|
||||
if courseID == 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Missing courseId"})
|
||||
}
|
||||
|
||||
token := GetQldtToken(db)
|
||||
if token == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "QLDT_TOKEN chưa cấu hình"})
|
||||
}
|
||||
|
||||
body, err := qldtClient.GetLeaveRequests(context.Background(), token, classRkID, courseID, date)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
var data any
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to parse QLDT response"})
|
||||
}
|
||||
|
||||
return c.JSON(data)
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/classes/:rkId/leave-requests/:leaveId/status
|
||||
func UpdateLeaveStatusHandler(db *gorm.DB, qldtClient *qldt.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
classRkID, _ := strconv.ParseInt(c.Params("rkId"), 10, 64)
|
||||
leaveID, _ := strconv.ParseInt(c.Params("leaveId"), 10, 64)
|
||||
|
||||
var req struct {
|
||||
Status string `json:"status"` // "Phê duyệt" or "Từ chối"
|
||||
StudentRkID int64 `json:"studentRkId"`
|
||||
Date string `json:"date"`
|
||||
Period int `json:"period"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid body payload"})
|
||||
}
|
||||
|
||||
if req.Status != "Phê duyệt" && req.Status != "Từ chối" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Trạng thái phê duyệt không hợp lệ"})
|
||||
}
|
||||
|
||||
token := GetQldtToken(db)
|
||||
if token == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "QLDT_TOKEN chưa cấu hình"})
|
||||
}
|
||||
|
||||
// 1. Gửi lệnh cập nhật status qua QLDT Portal API
|
||||
body, err := qldtClient.UpdateLeaveStatus(context.Background(), token, leaveID, req.Status)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error(), "body": string(body)})
|
||||
}
|
||||
|
||||
// 2. Nếu status là "Phê duyệt", tự động cập nhật điểm danh trong hệ thống của chúng ta thành "Nghỉ có phép"
|
||||
if req.Status == "Phê duyệt" {
|
||||
if req.StudentRkID == 0 || req.Date == "" || req.Period == 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Thiếu thông tin cập nhật điểm danh (studentRkId, date, period)"})
|
||||
}
|
||||
|
||||
dayOfWeek, err := scheduleDayFromDate(req.Date)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Ngày không hợp lệ"})
|
||||
}
|
||||
|
||||
sched, err := resolveScheduleForPeriod(db, classRkID, dayOfWeek, req.Period)
|
||||
if err != nil || sched == nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Không tìm thấy lịch học cho ca này"})
|
||||
}
|
||||
|
||||
// Cập nhật hoặc Tạo mới AttendanceResult
|
||||
var row models.AttendanceResult
|
||||
errFind := db.Where("class_rk_id = ? AND session_date = ? AND period = ? AND student_rk_id = ?",
|
||||
classRkID, req.Date, req.Period, req.StudentRkID).First(&row).Error
|
||||
|
||||
if errFind == nil {
|
||||
// Cập nhật hàng có sẵn
|
||||
row.Status = 1 // Nghỉ có phép
|
||||
row.StatusLabel = "Nghỉ có phép"
|
||||
row.StatusEditedByTeacher = true
|
||||
if err := db.Save(&row).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Lỗi lưu điểm danh: " + err.Error()})
|
||||
}
|
||||
} else if errFind == gorm.ErrRecordNotFound {
|
||||
// Tạo mới hàng
|
||||
row = models.AttendanceResult{
|
||||
ClassRkID: classRkID,
|
||||
SessionDate: req.Date,
|
||||
Period: req.Period,
|
||||
StudentRkID: req.StudentRkID,
|
||||
Status: 1,
|
||||
StatusLabel: "Nghỉ có phép",
|
||||
StatusEditedByTeacher: true,
|
||||
}
|
||||
if err := db.Create(&row).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Lỗi tạo điểm danh: " + err.Error()})
|
||||
}
|
||||
} else {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": errFind.Error()})
|
||||
}
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{"ok": true, "message": "Cập nhật đơn xin nghỉ thành công!"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package qldt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -198,3 +199,65 @@ func (c *Client) GetClassDashboard(ctx context.Context, token string, classID, c
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetLeaveRequests(ctx context.Context, token string, classID, courseID int64, date string) ([]byte, error) {
|
||||
u := fmt.Sprintf("%s/request-leave?classId=%d&courseId=%d&date=%s", c.baseURL, classID, courseID, date)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.setAuthHeaders(req, token)
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return nil, fmt.Errorf("qldt request-leave http %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateLeaveStatus(ctx context.Context, token string, leaveID int64, status string) ([]byte, error) {
|
||||
payload := map[string]string{"status": status}
|
||||
jsonData, _ := json.Marshal(payload)
|
||||
|
||||
u := fmt.Sprintf("%s/request-leave/%d/status", c.baseURL, leaveID)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, u, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
c.setAuthHeaders(req, token)
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
// Fallback to POST method if PATCH is Method Not Allowed or Not Found
|
||||
if resp.StatusCode == http.StatusMethodNotAllowed || resp.StatusCode == http.StatusNotFound {
|
||||
req2, err2 := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewBuffer(jsonData))
|
||||
if err2 == nil {
|
||||
req2.Header.Set("Content-Type", "application/json")
|
||||
c.setAuthHeaders(req2, token)
|
||||
resp2, errOr := c.http.Do(req2)
|
||||
if errOr == nil {
|
||||
defer resp2.Body.Close()
|
||||
body2, _ := io.ReadAll(resp2.Body)
|
||||
if resp2.StatusCode >= 200 && resp2.StatusCode < 300 {
|
||||
return body2, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("qldt request-leave/%d/status http %d: %s", leaveID, resp.StatusCode, string(body))
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
@@ -166,6 +166,8 @@ func main() {
|
||||
staff.Put("/classes/:rkId/attendance/status", handlers.UpdateAttendanceStatusHandler(gormDB))
|
||||
staff.Put("/classes/:rkId/attendance/bulk-status", handlers.UpdateAttendanceBulkStatusHandler(gormDB))
|
||||
staff.Post("/classes/:rkId/attendance/push-qldt", handlers.PushAttendanceToQLDTHandler(gormDB, qldtClient))
|
||||
staff.Get("/classes/:rkId/leave-requests", handlers.GetLeaveRequestsHandler(gormDB, qldtClient))
|
||||
staff.Post("/classes/:rkId/leave-requests/:leaveId/status", handlers.UpdateLeaveStatusHandler(gormDB, qldtClient))
|
||||
|
||||
// Chat & quản lý tài khoản
|
||||
staff.Get("/chat/students", handlers.SearchChatStudentsHandler(gormDB))
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user