feat: Add support for project cancellation status across the application

This commit is contained in:
2025-09-11 16:19:46 +02:00
parent 2735d46552
commit 95ef139843
13 changed files with 116 additions and 50 deletions

View File

@@ -8,6 +8,7 @@ import {
deleteProject,
} from "@/lib/queries/projects";
import { logFieldChange } from "@/lib/queries/fieldHistory";
import { addNoteToProject } from "@/lib/queries/notes";
import initializeDatabase from "@/lib/init-db";
import { NextResponse } from "next/server";
import { withReadAuth, withUserAuth } from "@/lib/middleware/auth";
@@ -42,57 +43,85 @@ async function getProjectHandler(req, { params }) {
}
async function updateProjectHandler(req, { params }) {
const { id } = await params;
const data = await req.json();
try {
const { id } = await params;
const data = await req.json();
// Get user ID from authenticated request
const userId = req.user?.id;
// Get user ID from authenticated request
const userId = req.user?.id;
// Get original project data for audit log and field tracking
const originalProject = getProjectById(parseInt(id));
// Get original project data for audit log and field tracking
const originalProject = getProjectById(parseInt(id));
if (!originalProject) {
return NextResponse.json({ error: "Project not found" }, { status: 404 });
}
if (!originalProject) {
return NextResponse.json({ error: "Project not found" }, { status: 404 });
}
// Track field changes for specific fields we want to monitor
const fieldsToTrack = ['finish_date', 'project_status', 'assigned_to', 'contract_id'];
for (const fieldName of fieldsToTrack) {
if (data.hasOwnProperty(fieldName)) {
const oldValue = originalProject[fieldName];
const newValue = data[fieldName];
if (oldValue !== newValue) {
try {
logFieldChange('projects', parseInt(id), fieldName, oldValue, newValue, userId);
} catch (error) {
console.error(`Failed to log field change for ${fieldName}:`, error);
// Track field changes for specific fields we want to monitor
const fieldsToTrack = ['finish_date', 'project_status', 'assigned_to', 'contract_id'];
for (const fieldName of fieldsToTrack) {
if (data.hasOwnProperty(fieldName)) {
const oldValue = originalProject[fieldName];
const newValue = data[fieldName];
if (oldValue !== newValue) {
try {
logFieldChange('projects', parseInt(id), fieldName, oldValue, newValue, userId);
} catch (error) {
console.error(`Failed to log field change for ${fieldName}:`, error);
}
}
}
}
}
updateProject(parseInt(id), data, userId);
// Get updated project
const updatedProject = getProjectById(parseInt(id));
// Log project update
await logApiActionSafe(
req,
AUDIT_ACTIONS.PROJECT_UPDATE,
RESOURCE_TYPES.PROJECT,
id,
req.auth, // Use req.auth instead of req.session
{
originalData: originalProject,
updatedData: data,
changedFields: Object.keys(data),
// Special handling for project cancellation
if (data.project_status === 'cancelled' && originalProject.project_status !== 'cancelled') {
const now = new Date();
const cancellationDate = now.toLocaleDateString('pl-PL', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
const cancellationNote = `Projekt został wycofany w dniu ${cancellationDate}`;
try {
addNoteToProject(parseInt(id), cancellationNote, userId, true); // true for is_system
} catch (error) {
console.error('Failed to log project cancellation:', error);
}
}
);
return NextResponse.json(updatedProject);
updateProject(parseInt(id), data, userId);
// Get updated project
const updatedProject = getProjectById(parseInt(id));
// Log project update
await logApiActionSafe(
req,
AUDIT_ACTIONS.PROJECT_UPDATE,
RESOURCE_TYPES.PROJECT,
id,
req.auth, // Use req.auth instead of req.session
{
originalData: originalProject,
updatedData: data,
changedFields: Object.keys(data),
}
);
return NextResponse.json(updatedProject);
} catch (error) {
console.error("Error in updateProjectHandler:", error);
return NextResponse.json(
{ error: "Internal server error", details: error.message },
{ status: 500 }
);
}
}
async function deleteProjectHandler(req, { params }) {