(Feat-Fix): Lots of fixes done, reporting system fixed, stricter types

This commit is contained in:
2025-12-19 18:48:05 +00:00
parent 01400ad4e1
commit 865e0bf00e
61 changed files with 10072 additions and 6645 deletions

View File

@@ -1,22 +1,30 @@
import { Router } from "@oak/oak";
import { db } from "../config/database.ts";
import { authenticateToken, authorize, getCurrentUser } from "../middleware/auth.ts";
import type { WorkAllocation } from "../types/index.ts";
import {
authenticateToken,
authorize,
getCurrentUser,
} from "../middleware/auth.ts";
import type { JWTPayload, WorkAllocation } from "../types/index.ts";
const router = new Router();
// Get completed work allocations for reporting (with optional filters)
router.get("/completed-allocations", authenticateToken, authorize("Supervisor", "SuperAdmin"), async (ctx) => {
try {
const currentUser = getCurrentUser(ctx);
const params = ctx.request.url.searchParams;
const startDate = params.get("startDate");
const endDate = params.get("endDate");
const departmentId = params.get("departmentId");
const contractorId = params.get("contractorId");
const employeeId = params.get("employeeId");
let query = `
router.get(
"/completed-allocations",
authenticateToken,
authorize("Supervisor", "SuperAdmin"),
async (ctx) => {
try {
const currentUser: JWTPayload = getCurrentUser(ctx);
const params: URLSearchParams = ctx.request.url.searchParams;
const startDate: string | null = params.get("startDate");
const endDate: string | null = params.get("endDate");
const departmentId: string | null = params.get("departmentId");
const contractorId: string | null = params.get("contractorId");
const employeeId: string | null = params.get("employeeId");
let query = `
SELECT wa.*,
e.name as employee_name, e.username as employee_username,
e.phone_number as employee_phone,
@@ -33,95 +41,110 @@ router.get("/completed-allocations", authenticateToken, authorize("Supervisor",
LEFT JOIN departments d ON e.department_id = d.id
WHERE wa.status = 'Completed'
`;
const queryParams: unknown[] = [];
// Role-based filtering - Supervisors can only see their department
if (currentUser.role === "Supervisor") {
query += " AND e.department_id = ?";
queryParams.push(currentUser.departmentId);
}
// Date range filter
if (startDate) {
query += " AND wa.completion_date >= ?";
queryParams.push(startDate);
}
if (endDate) {
query += " AND wa.completion_date <= ?";
queryParams.push(endDate);
}
// Department filter (for SuperAdmin)
if (departmentId && currentUser.role === "SuperAdmin") {
query += " AND e.department_id = ?";
queryParams.push(departmentId);
}
// Contractor filter
if (contractorId) {
query += " AND wa.contractor_id = ?";
queryParams.push(contractorId);
}
// Employee filter
if (employeeId) {
query += " AND wa.employee_id = ?";
queryParams.push(employeeId);
}
query += " ORDER BY wa.completion_date DESC, wa.created_at DESC";
const allocations = await db.query<WorkAllocation[]>(query, queryParams);
// Calculate summary stats
const totalAllocations = allocations.length;
const totalAmount = allocations.reduce((sum, a) => sum + (parseFloat(String(a.total_amount)) || parseFloat(String(a.rate)) || 0), 0);
const totalUnits = allocations.reduce((sum, a) => sum + (parseFloat(String(a.units)) || 0), 0);
ctx.response.body = {
allocations,
summary: {
totalAllocations,
totalAmount: totalAmount.toFixed(2),
totalUnits: totalUnits.toFixed(2),
const queryParams: unknown[] = [];
// Role-based filtering - Supervisors can only see their department
if (currentUser.role === "Supervisor") {
query += " AND e.department_id = ?";
queryParams.push(currentUser.departmentId);
}
};
} catch (error) {
console.error("Get completed allocations report error:", error);
ctx.response.status = 500;
ctx.response.body = { error: "Internal server error" };
}
});
// Date range filter
if (startDate) {
query += " AND wa.completion_date >= ?";
queryParams.push(startDate);
}
if (endDate) {
query += " AND wa.completion_date <= ?";
queryParams.push(endDate);
}
// Department filter (for SuperAdmin)
if (departmentId && currentUser.role === "SuperAdmin") {
query += " AND e.department_id = ?";
queryParams.push(departmentId);
}
// Contractor filter
if (contractorId) {
query += " AND wa.contractor_id = ?";
queryParams.push(contractorId);
}
// Employee filter
if (employeeId) {
query += " AND wa.employee_id = ?";
queryParams.push(employeeId);
}
query += " ORDER BY wa.completion_date DESC, wa.created_at DESC";
const allocations = await db.query<WorkAllocation[]>(query, queryParams);
// Calculate summary stats
const totalAllocations = allocations.length;
const totalAmount = allocations.reduce(
(sum, a) =>
sum +
(parseFloat(String(a.total_amount)) || parseFloat(String(a.rate)) ||
0),
0,
);
const totalUnits = allocations.reduce(
(sum, a) => sum + (parseFloat(String(a.units)) || 0),
0,
);
ctx.response.body = {
allocations,
summary: {
totalAllocations,
totalAmount: totalAmount.toFixed(2),
totalUnits: totalUnits.toFixed(2),
},
};
} catch (error) {
console.error("Get completed allocations report error:", error);
ctx.response.status = 500;
ctx.response.body = { error: "Internal server error" };
}
},
);
// Get summary statistics for completed work
router.get("/summary", authenticateToken, authorize("Supervisor", "SuperAdmin"), async (ctx) => {
try {
const currentUser = getCurrentUser(ctx);
const params = ctx.request.url.searchParams;
const startDate = params.get("startDate");
const endDate = params.get("endDate");
let departmentFilter = "";
const queryParams: unknown[] = [];
if (currentUser.role === "Supervisor") {
departmentFilter = " AND e.department_id = ?";
queryParams.push(currentUser.departmentId);
}
let dateFilter = "";
if (startDate) {
dateFilter += " AND wa.completion_date >= ?";
queryParams.push(startDate);
}
if (endDate) {
dateFilter += " AND wa.completion_date <= ?";
queryParams.push(endDate);
}
// Get summary by contractor
const byContractor = await db.query<any[]>(`
router.get(
"/summary",
authenticateToken,
authorize("Supervisor", "SuperAdmin"),
async (ctx) => {
try {
const currentUser: JWTPayload = getCurrentUser(ctx);
const params: URLSearchParams = ctx.request.url.searchParams;
const startDate: string | null = params.get("startDate");
const endDate: string | null = params.get("endDate");
let departmentFilter = "";
const queryParams: unknown[] = [];
if (currentUser.role === "Supervisor") {
departmentFilter = " AND e.department_id = ?";
queryParams.push(currentUser.departmentId);
}
let dateFilter = "";
if (startDate) {
dateFilter += " AND wa.completion_date >= ?";
queryParams.push(startDate);
}
if (endDate) {
dateFilter += " AND wa.completion_date <= ?";
queryParams.push(endDate);
}
// Get summary by contractor
const byContractor = await db.query<any[]>(
`
SELECT
c.id as contractor_id,
c.name as contractor_name,
@@ -134,10 +157,13 @@ router.get("/summary", authenticateToken, authorize("Supervisor", "SuperAdmin"),
WHERE wa.status = 'Completed' ${departmentFilter} ${dateFilter}
GROUP BY c.id, c.name
ORDER BY total_amount DESC
`, queryParams);
// Get summary by sub-department
const bySubDepartment = await db.query<any[]>(`
`,
queryParams,
);
// Get summary by sub-department
const bySubDepartment = await db.query<any[]>(
`
SELECT
sd.id as sub_department_id,
sd.name as sub_department_name,
@@ -152,10 +178,13 @@ router.get("/summary", authenticateToken, authorize("Supervisor", "SuperAdmin"),
WHERE wa.status = 'Completed' ${departmentFilter} ${dateFilter}
GROUP BY sd.id, sd.name, d.name
ORDER BY total_amount DESC
`, queryParams);
// Get summary by activity type
const byActivity = await db.query<any[]>(`
`,
queryParams,
);
// Get summary by activity type
const byActivity = await db.query<any[]>(
`
SELECT
COALESCE(wa.activity, 'Standard') as activity,
COUNT(*) as total_allocations,
@@ -166,18 +195,21 @@ router.get("/summary", authenticateToken, authorize("Supervisor", "SuperAdmin"),
WHERE wa.status = 'Completed' ${departmentFilter} ${dateFilter}
GROUP BY wa.activity
ORDER BY total_amount DESC
`, queryParams);
ctx.response.body = {
byContractor,
bySubDepartment,
byActivity,
};
} catch (error) {
console.error("Get report summary error:", error);
ctx.response.status = 500;
ctx.response.body = { error: "Internal server error" };
}
});
`,
queryParams,
);
ctx.response.body = {
byContractor,
bySubDepartment,
byActivity,
};
} catch (error) {
console.error("Get report summary error:", error);
ctx.response.status = 500;
ctx.response.body = { error: "Internal server error" };
}
},
);
export default router;