416 lines
12 KiB
JavaScript
416 lines
12 KiB
JavaScript
import db from "../db.js";
|
|
import { addNoteToTask } from "./notes.js";
|
|
import { getUserLanguage, serverT, translateStatus, translatePriority } from "../serverTranslations.js";
|
|
|
|
// Get all task templates (for dropdown selection)
|
|
export function getAllTaskTemplates() {
|
|
return db
|
|
.prepare("SELECT * FROM tasks WHERE is_standard = 1 ORDER BY name ASC")
|
|
.all();
|
|
}
|
|
|
|
// Get all project tasks across all projects
|
|
export function getAllProjectTasks() {
|
|
return db
|
|
.prepare(
|
|
`
|
|
SELECT
|
|
pt.*,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name,
|
|
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
|
|
COALESCE(pt.custom_description, t.description) as description,
|
|
CASE
|
|
WHEN pt.task_template_id IS NOT NULL THEN 'template'
|
|
ELSE 'custom'
|
|
END as task_type,
|
|
p.project_name,
|
|
p.wp,
|
|
p.plot,
|
|
p.city,
|
|
p.address,
|
|
p.finish_date,
|
|
creator.name as created_by_name,
|
|
creator.username as created_by_username,
|
|
assignee.name as assigned_to_name,
|
|
assignee.username as assigned_to_username
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
LEFT JOIN projects p ON pt.project_id = p.project_id
|
|
LEFT JOIN users creator ON pt.created_by = creator.id
|
|
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
|
|
ORDER BY pt.date_added DESC
|
|
`
|
|
)
|
|
.all();
|
|
}
|
|
|
|
// Get project tasks for a specific project
|
|
export function getProjectTasks(projectId) {
|
|
return db
|
|
.prepare(
|
|
`
|
|
SELECT
|
|
pt.*,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name,
|
|
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
|
|
COALESCE(pt.custom_description, t.description) as description,
|
|
CASE
|
|
WHEN pt.task_template_id IS NOT NULL THEN 'template'
|
|
ELSE 'custom'
|
|
END as task_type,
|
|
creator.name as created_by_name,
|
|
creator.username as created_by_username,
|
|
assignee.name as assigned_to_name,
|
|
assignee.username as assigned_to_username
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
LEFT JOIN users creator ON pt.created_by = creator.id
|
|
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
|
|
WHERE pt.project_id = ?
|
|
ORDER BY pt.date_added DESC
|
|
`
|
|
)
|
|
.all(projectId);
|
|
}
|
|
|
|
// Create a new project task
|
|
export function createProjectTask(data) {
|
|
let result;
|
|
let taskName;
|
|
|
|
if (data.task_template_id) {
|
|
// Creating from template - explicitly set custom_max_wait_days to NULL so COALESCE uses template value
|
|
const stmt = db.prepare(`
|
|
INSERT INTO project_tasks (
|
|
project_id, task_template_id, custom_max_wait_days, status, priority,
|
|
created_by, assigned_to, created_at, updated_at
|
|
)
|
|
VALUES (?, ?, NULL, ?, ?, ?, ?, datetime('now', 'localtime'), datetime('now', 'localtime'))
|
|
`);
|
|
result = stmt.run(
|
|
data.project_id,
|
|
data.task_template_id,
|
|
data.status || "pending",
|
|
data.priority || "normal",
|
|
data.created_by || null,
|
|
data.assigned_to || null
|
|
);
|
|
|
|
// Get the template name for the log
|
|
const templateStmt = db.prepare("SELECT name FROM tasks WHERE task_id = ?");
|
|
const template = templateStmt.get(data.task_template_id);
|
|
taskName = template?.name || "Unknown template";
|
|
} else {
|
|
// Creating custom task
|
|
const stmt = db.prepare(`
|
|
INSERT INTO project_tasks (
|
|
project_id, custom_task_name, custom_max_wait_days, custom_description,
|
|
status, priority, created_by, assigned_to, created_at, updated_at
|
|
)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now', 'localtime'), datetime('now', 'localtime'))
|
|
`);
|
|
result = stmt.run(
|
|
data.project_id,
|
|
data.custom_task_name,
|
|
data.custom_max_wait_days || 0,
|
|
data.custom_description || "",
|
|
data.status || "pending",
|
|
data.priority || "normal",
|
|
data.created_by || null,
|
|
data.assigned_to || null
|
|
);
|
|
|
|
taskName = data.custom_task_name;
|
|
}
|
|
|
|
// Add system note for task creation
|
|
if (result.lastInsertRowid) {
|
|
const language = getUserLanguage();
|
|
const priority = data.priority || "normal";
|
|
const status = data.status || "pending";
|
|
const translatedPriority = translatePriority(priority, language);
|
|
const translatedStatus = translateStatus(status, language);
|
|
const logMessage = `${serverT("Task created", language)} "${taskName}" ${serverT("with priority", language)}: ${translatedPriority}, ${serverT("status", language)}: ${translatedStatus}`;
|
|
addNoteToTask(result.lastInsertRowid, logMessage, true, data.created_by);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Update project task status
|
|
export function updateProjectTaskStatus(taskId, status, userId = null) {
|
|
// First get the current task details for logging
|
|
const getCurrentTask = db.prepare(`
|
|
SELECT
|
|
pt.status,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
WHERE pt.id = ?
|
|
`);
|
|
const currentTask = getCurrentTask.get(taskId);
|
|
|
|
if (!currentTask) {
|
|
throw new Error(`Task with ID ${taskId} not found`);
|
|
}
|
|
|
|
const oldStatus = currentTask.status;
|
|
let stmt;
|
|
let result;
|
|
|
|
if (oldStatus === "pending" && status === "in_progress") {
|
|
// Starting a task - set date_started
|
|
stmt = db.prepare(`
|
|
UPDATE project_tasks
|
|
SET status = ?, date_started = datetime('now', 'localtime'), updated_at = datetime('now', 'localtime')
|
|
WHERE id = ?
|
|
`);
|
|
result = stmt.run(status, taskId);
|
|
} else if (status === "completed") {
|
|
// Completing a task - set date_completed
|
|
stmt = db.prepare(`
|
|
UPDATE project_tasks
|
|
SET status = ?, date_completed = datetime('now', 'localtime'), updated_at = datetime('now', 'localtime')
|
|
WHERE id = ?
|
|
`);
|
|
result = stmt.run(status, taskId);
|
|
} else {
|
|
// Just updating status without changing timestamps
|
|
stmt = db.prepare(`
|
|
UPDATE project_tasks
|
|
SET status = ?, updated_at = datetime('now', 'localtime')
|
|
WHERE id = ?
|
|
`);
|
|
result = stmt.run(status, taskId);
|
|
}
|
|
|
|
// Add system note for status change (only if status actually changed)
|
|
if (result.changes > 0 && oldStatus !== status) {
|
|
const language = getUserLanguage(); // Default to Polish for now
|
|
const fromStatus = translateStatus(oldStatus, language);
|
|
const toStatus = translateStatus(status, language);
|
|
const logMessage = `${serverT("Status changed from", language)} "${fromStatus}" ${serverT("to", language)} "${toStatus}"`;
|
|
addNoteToTask(taskId, logMessage, true, userId);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Delete a project task
|
|
export function deleteProjectTask(taskId) {
|
|
// First delete all related task notes
|
|
const deleteNotesStmt = db.prepare("DELETE FROM notes WHERE task_id = ?");
|
|
deleteNotesStmt.run(taskId);
|
|
|
|
// Then delete the task itself
|
|
const deleteTaskStmt = db.prepare("DELETE FROM project_tasks WHERE id = ?");
|
|
return deleteTaskStmt.run(taskId);
|
|
}
|
|
|
|
// Get project tasks assigned to a specific user
|
|
export function getProjectTasksByAssignedUser(userId) {
|
|
return db
|
|
.prepare(
|
|
`
|
|
SELECT
|
|
pt.*,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name,
|
|
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
|
|
COALESCE(pt.custom_description, t.description) as description,
|
|
CASE
|
|
WHEN pt.task_template_id IS NOT NULL THEN 'template'
|
|
ELSE 'custom'
|
|
END as task_type,
|
|
p.project_name,
|
|
p.wp,
|
|
p.plot,
|
|
p.city,
|
|
p.address,
|
|
p.finish_date,
|
|
creator.name as created_by_name,
|
|
creator.username as created_by_username,
|
|
assignee.name as assigned_to_name,
|
|
assignee.username as assigned_to_username
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
LEFT JOIN projects p ON pt.project_id = p.project_id
|
|
LEFT JOIN users creator ON pt.created_by = creator.id
|
|
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
|
|
WHERE pt.assigned_to = ?
|
|
ORDER BY pt.date_added DESC
|
|
`
|
|
)
|
|
.all(userId);
|
|
}
|
|
|
|
// Get project tasks created by a specific user
|
|
export function getProjectTasksByCreator(userId) {
|
|
return db
|
|
.prepare(
|
|
`
|
|
SELECT
|
|
pt.*,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name,
|
|
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
|
|
COALESCE(pt.custom_description, t.description) as description,
|
|
CASE
|
|
WHEN pt.task_template_id IS NOT NULL THEN 'template'
|
|
ELSE 'custom'
|
|
END as task_type,
|
|
p.project_name,
|
|
p.wp,
|
|
p.plot,
|
|
p.city,
|
|
p.address,
|
|
p.finish_date,
|
|
creator.name as created_by_name,
|
|
creator.username as created_by_username,
|
|
assignee.name as assigned_to_name,
|
|
assignee.username as assigned_to_username
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
LEFT JOIN projects p ON pt.project_id = p.project_id
|
|
LEFT JOIN users creator ON pt.created_by = creator.id
|
|
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
|
|
WHERE pt.created_by = ?
|
|
ORDER BY pt.date_added DESC
|
|
`
|
|
)
|
|
.all(userId);
|
|
}
|
|
|
|
// Update project task assignment
|
|
export function updateProjectTaskAssignment(taskId, assignedToUserId) {
|
|
const stmt = db.prepare(`
|
|
UPDATE project_tasks
|
|
SET assigned_to = ?, updated_at = datetime('now', 'localtime')
|
|
WHERE id = ?
|
|
`);
|
|
return stmt.run(assignedToUserId, taskId);
|
|
}
|
|
|
|
// Get active users for task assignment (same as projects)
|
|
export function getAllUsersForTaskAssignment() {
|
|
return db
|
|
.prepare(
|
|
`
|
|
SELECT id, name, username, role
|
|
FROM users
|
|
WHERE is_active = 1 AND role != 'admin'
|
|
ORDER BY name ASC
|
|
`
|
|
)
|
|
.all();
|
|
}
|
|
|
|
// Update project task (general update for edit modal)
|
|
export function updateProjectTask(taskId, updates, userId = null) {
|
|
// Get current task for logging
|
|
const getCurrentTask = db.prepare(`
|
|
SELECT
|
|
pt.*,
|
|
COALESCE(pt.custom_task_name, t.name) as task_name
|
|
FROM project_tasks pt
|
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
|
WHERE pt.id = ?
|
|
`);
|
|
const currentTask = getCurrentTask.get(taskId);
|
|
|
|
if (!currentTask) {
|
|
throw new Error(`Task with ID ${taskId} not found`);
|
|
}
|
|
|
|
// Build dynamic update query
|
|
const fields = [];
|
|
const values = [];
|
|
|
|
if (updates.priority !== undefined) {
|
|
fields.push("priority = ?");
|
|
values.push(updates.priority);
|
|
}
|
|
|
|
if (updates.status !== undefined) {
|
|
fields.push("status = ?");
|
|
values.push(updates.status);
|
|
|
|
// Handle status-specific timestamp updates
|
|
if (currentTask.status === "pending" && updates.status === "in_progress") {
|
|
fields.push("date_started = datetime('now', 'localtime')");
|
|
} else if (updates.status === "completed") {
|
|
fields.push("date_completed = datetime('now', 'localtime')");
|
|
}
|
|
}
|
|
|
|
if (updates.assigned_to !== undefined) {
|
|
fields.push("assigned_to = ?");
|
|
values.push(updates.assigned_to || null);
|
|
}
|
|
|
|
if (updates.date_started !== undefined) {
|
|
fields.push("date_started = ?");
|
|
values.push(updates.date_started || null);
|
|
}
|
|
|
|
// Always update the updated_at timestamp
|
|
fields.push("updated_at = datetime('now', 'localtime')");
|
|
values.push(taskId);
|
|
|
|
const stmt = db.prepare(`
|
|
UPDATE project_tasks
|
|
SET ${fields.join(", ")}
|
|
WHERE id = ?
|
|
`);
|
|
|
|
const result = stmt.run(...values);
|
|
|
|
// Log the update
|
|
if (userId) {
|
|
const language = getUserLanguage(); // Default to Polish for now
|
|
const changes = [];
|
|
|
|
if (
|
|
updates.priority !== undefined &&
|
|
updates.priority !== currentTask.priority
|
|
) {
|
|
const oldPriority = translatePriority(currentTask.priority, language) || serverT("None", language);
|
|
const newPriority = translatePriority(updates.priority, language) || serverT("None", language);
|
|
changes.push(
|
|
`${serverT("Priority", language)}: ${oldPriority} → ${newPriority}`
|
|
);
|
|
}
|
|
|
|
if (updates.status !== undefined && updates.status !== currentTask.status) {
|
|
const oldStatus = translateStatus(currentTask.status, language) || serverT("None", language);
|
|
const newStatus = translateStatus(updates.status, language) || serverT("None", language);
|
|
changes.push(
|
|
`${serverT("Status", language)}: ${oldStatus} → ${newStatus}`
|
|
);
|
|
}
|
|
|
|
if (
|
|
updates.assigned_to !== undefined &&
|
|
updates.assigned_to !== currentTask.assigned_to
|
|
) {
|
|
changes.push(serverT("Assignment updated", language));
|
|
}
|
|
|
|
if (
|
|
updates.date_started !== undefined &&
|
|
updates.date_started !== currentTask.date_started
|
|
) {
|
|
const oldDate = currentTask.date_started || serverT("None", language);
|
|
const newDate = updates.date_started || serverT("None", language);
|
|
changes.push(
|
|
`${serverT("Date started", language)}: ${oldDate} → ${newDate}`
|
|
);
|
|
}
|
|
|
|
if (changes.length > 0) {
|
|
const logMessage = `${serverT("Task updated", language)}: ${changes.join(", ")}`;
|
|
addNoteToTask(taskId, logMessage, true, userId);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|