const express = require("express"); const { TimeEntry, User } = require("../models"); const { logActivity } = require("./activityLogs"); const { calculateWorkHours } = require("../utils/timeCalculator"); const { authenticate, authorizeAdmin, authorizeManager, } = require("../middleware/auth"); const { sequelize } = require("../models"); const router = express.Router(); // Get time entries for current user router.get("/", authenticate, async (req, res) => { try { console.log("Fetching entries for user:", req.user.id); const entries = await TimeEntry.findAll({ where: { userId: req.user.id }, order: [["date", "DESC"]], attributes: [ "id", "userId", "date", "reason", "hours", "startDate", "startTime", "endDate", "endTime", "status", "createdAt", "updatedAt", ], }).catch(async (error) => { // Если ошибка с колонками, используем только базовые поля if (error.message && error.message.includes("column")) { console.log("Fallback to basic attributes due to column error"); return await TimeEntry.findAll({ where: { userId: req.user.id }, order: [["date", "DESC"]], attributes: [ "id", "userId", "date", "reason", "hours", "createdAt", "updatedAt", ], }); } throw error; }); console.log("Found entries:", entries.length); res.json(entries); } catch (error) { console.error("Error fetching entries:", error); res.status(500).json({ message: "Server error" }); } }); // Get all time entries (admin and manager) router.get("/all", authenticate, authorizeManager, async (req, res) => { try { const entries = await TimeEntry.findAll({ attributes: [ "id", "userId", "date", "reason", "hours", "createdAt", "updatedAt", ], include: [{ model: User, attributes: ["username"] }], order: [["date", "DESC"]], }).catch(async (error) => { // Если ошибка с колонками, используем только базовые поля if (error.message && error.message.includes("column")) { console.log( "Fallback to basic attributes for admin view due to column error" ); return await TimeEntry.findAll({ attributes: [ "id", "userId", "date", "reason", "hours", "startDate", "startTime", "endDate", "endTime", "status", "createdAt", "updatedAt", ], include: [{ model: User, attributes: ["username"] }], order: [["date", "DESC"]], }); } throw error; }); // Log the export action await logActivity( req.user.id, "Экспорт общей таблицы", `Просмотрена общая таблица записей времени` ); res.json(entries); } catch (error) { res.status(500).json({ message: "Server error" }); } }); // Get time entries for specific user (admin and manager) router.get( "/user/:userId", authenticate, authorizeManager, async (req, res) => { try { const { userId } = req.params; console.log("Fetching entries for userId:", userId); const entries = await TimeEntry.findAll({ where: { userId }, order: [["date", "DESC"]], }); console.log("Found entries:", entries); // Get username for logging const user = await User.findByPk(userId); const username = user ? user.username : "Unknown"; // Log the export action for specific user await logActivity( req.user.id, "Экспорт таблицы пользователя", `Просмотрена таблица записей времени для пользователя: ${username}` ); res.json(entries); } catch (error) { console.error("Error fetching user entries:", error); res.status(500).json({ message: "Server error" }); } } ); // Create time entry router.post("/", authenticate, async (req, res) => { try { const { date, reason, hours, startDate, startTime, endDate, endTime, isAuto = false, } = req.body; console.log("Received data:", { date, reason, hours, startDate, startTime, endDate, endTime, isAuto, }); let calculatedHours = parseFloat(hours); let status = "closed"; // Если автоматический расчет if (isAuto && startDate && startTime) { try { console.log("Calculating work hours for:", { startDate, startTime, endDate, endTime, }); calculatedHours = calculateWorkHours( startDate, startTime, endDate, endTime ); console.log("Calculated hours:", calculatedHours); // Если нет даты окончания - запись активна (открытая) if (!endDate || !endTime) { status = "active"; } } catch (calcError) { console.error("Calculation error:", calcError); return res.status(400).json({ message: calcError.message }); } } console.log("Creating entry with data:", { userId: req.user.id, date: date || startDate, reason, hours: calculatedHours, startDate, startTime, endDate, endTime, status, }); const entryData = { userId: req.user.id, date: date || startDate, // Для совместимости с ручным вводом reason, hours: calculatedHours, }; // Добавляем новые поля только если они существуют в базе данных try { await sequelize.query('SELECT "startDate" FROM "TimeEntries" LIMIT 1;', { type: sequelize.QueryTypes.SELECT, }); entryData.startDate = startDate; entryData.startTime = startTime; entryData.endDate = endDate; entryData.endTime = endTime; entryData.status = status; } catch (columnError) { console.log("New columns do not exist yet, using basic fields only"); } const entry = await TimeEntry.create(entryData); console.log("Entry created successfully:", entry.id); res.status(201).json(entry); } catch (error) { console.error("Error creating time entry:", error); console.error("Error stack:", error.stack); console.error("Error message:", error.message); if (error.name === "SequelizeValidationError") { console.error("Validation errors:", error.errors); } res.status(500).json({ message: "Server error", error: error.message, stack: error.stack, }); } }); // Update time entry (own or admin) router.put("/:id", authenticate, async (req, res) => { try { const { date, reason, hours, startDate, startTime, endDate, endTime, isAuto = false, } = req.body; const entry = await TimeEntry.findByPk(req.params.id); if (!entry) { return res.status(404).json({ message: "Entry not found" }); } if (entry.userId !== req.user.id && req.user.role !== "admin") { return res.status(403).json({ message: "Access denied" }); } let calculatedHours = parseFloat(hours); let status = entry.status; // Если автоматический расчет или обновление активной записи if (isAuto || entry.status === "active") { try { calculatedHours = calculateWorkHours( startDate || entry.startDate, startTime || entry.startTime, endDate, endTime ); // Если добавили дату окончания - закрываем запись if ( (endDate && endTime) || (endDate && !endTime) || (!endDate && endTime) ) { status = "closed"; } else { status = "active"; } } catch (calcError) { return res.status(400).json({ message: calcError.message }); } } await entry.update({ date: date || entry.date, reason, hours: calculatedHours, startDate, startTime, endDate, endTime, status, }); res.json(entry); } catch (error) { console.error("Error updating time entry:", error); res.status(500).json({ message: "Server error" }); } }); // Delete all time entries for current user router.delete("/delete-all", authenticate, async (req, res) => { try { const deletedCount = await TimeEntry.destroy({ where: { userId: req.user.id }, }); // Log the delete all action await logActivity( req.user.id, "Удаление всех записей", `Удалены все записи времени (${deletedCount} записей)` ); res.json({ message: "All entries deleted", deletedCount }); } catch (error) { res.status(500).json({ message: "Server error" }); } }); // Delete time entry (own or admin) router.delete("/:id", authenticate, async (req, res) => { try { const entry = await TimeEntry.findByPk(req.params.id); if (!entry) { return res.status(404).json({ message: "Entry not found" }); } if (entry.userId !== req.user.id && req.user.role !== "admin") { return res.status(403).json({ message: "Access denied" }); } await entry.destroy(); res.json({ message: "Entry deleted" }); } catch (error) { res.status(500).json({ message: "Server error" }); } }); module.exports = router;