36293-vm/forecasting_actions.php
2025-11-25 21:46:02 +00:00

187 lines
7.7 KiB
PHP

<?php
require_once __DIR__ . '/db/config.php';
$action = $_POST['action'] ?? null;
$projectId = $_POST['projectId'] ?? null;
if (!$action || !$projectId) {
redirect_with_error('forecasting.php', $projectId, 'Invalid request.');
}
function redirect_with_error($page, $projectId, $message) {
$version = $_POST['version'] ?? null;
$query = http_build_query(array_filter([
'projectId' => $projectId,
'version' => $version,
'error' => $message
]));
header("Location: {$page}?{$query}");
exit();
}
function redirect_with_success($page, $projectId, $message) {
$version = $_POST['version'] ?? null;
$query = http_build_query(array_filter([
'projectId' => $projectId,
'version' => $version,
'success' => $message
]));
header("Location: {$page}?{$query}");
exit();
}
function get_months($startDate, $endDate) {
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$interval = new DateInterval('P1M');
$period = new DatePeriod($start, $interval, $end->modify('+1 month'));
$months = [];
foreach ($period as $dt) {
$months[] = $dt->format('Y-m-01');
}
return $months;
}
try {
$pdo = db();
switch ($action) {
case 'new_version':
// Find the latest version number
$stmt = $pdo->prepare("SELECT MAX(versionNumber) as max_version FROM forecasting WHERE projectId = :projectId");
$stmt->execute([':projectId' => $projectId]);
$latest_version_num = $stmt->fetchColumn();
$new_version_num = $latest_version_num + 1;
// Get the ID of the latest version to clone from
$stmt = $pdo->prepare("SELECT id FROM forecasting WHERE projectId = :projectId AND versionNumber = :versionNumber");
$stmt->execute([':projectId' => $projectId, ':versionNumber' => $latest_version_num]);
$latest_version_id = $stmt->fetchColumn();
$pdo->beginTransaction();
// Create the new forecasting version
$stmt = $pdo->prepare("INSERT INTO forecasting (projectId, versionNumber, createdAt) VALUES (:projectId, :versionNumber, NOW())");
$stmt->execute([':projectId' => $projectId, ':versionNumber' => $new_version_num]);
$new_version_id = $pdo->lastInsertId();
// Clone allocations from the latest version if it exists
if ($latest_version_id) {
$clone_sql = "INSERT INTO forecastAllocation (forecastingId, rosterId, resourceName, level, month, allocatedDays)
SELECT :new_version_id, rosterId, resourceName, level, month, allocatedDays
FROM forecastAllocation WHERE forecastingId = :latest_version_id";
$stmt = $pdo->prepare($clone_sql);
$stmt->execute([':new_version_id' => $new_version_id, ':latest_version_id' => $latest_version_id]);
}
$pdo->commit();
redirect_with_success('forecasting.php', $projectId, 'New version created successfully.', ['version' => $new_version_num]);
break;
case 'add_resource':
$forecastingId = $_POST['forecastingId'] ?? null;
$rosterId = $_POST['rosterId'] ?? null;
if (!$forecastingId || !$rosterId) {
redirect_with_error('forecasting.php', $projectId, 'Missing data for adding resource.');
}
// Fetch project and roster details
$stmt = $pdo->prepare("SELECT startDate, endDate FROM projects WHERE id = :projectId");
$stmt->execute([':projectId' => $projectId]);
$project = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $pdo->prepare("SELECT fullNameEn, `level` FROM roster WHERE id = :rosterId");
$stmt->execute([':rosterId' => $rosterId]);
$roster = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$project || !$roster) {
redirect_with_error('forecasting.php', $projectId, 'Project or resource not found.');
}
$months = get_months($project['startDate'], $project['endDate']);
$insert_sql = "INSERT INTO forecastAllocation (forecastingId, rosterId, resourceName, level, month, allocatedDays) VALUES (:forecastingId, :rosterId, :resourceName, :level, :month, 0)";
$stmt = $pdo->prepare($insert_sql);
$pdo->beginTransaction();
foreach ($months as $month) {
$stmt->execute([
':forecastingId' => $forecastingId,
':rosterId' => $rosterId,
':resourceName' => $roster['fullNameEn'],
':level' => $roster['level'],
':month' => $month
]);
}
$pdo->commit();
redirect_with_success('forecasting.php', $projectId, 'Resource added to forecast.');
break;
case 'remove_resource':
$forecastingId = $_POST['forecastingId'] ?? null;
$rosterId = $_POST['rosterId'] ?? null;
if (!$forecastingId || !$rosterId) {
redirect_with_error('forecasting.php', $projectId, 'Missing data for removing resource.');
}
$sql = "DELETE FROM forecastAllocation WHERE forecastingId = :forecastingId AND rosterId = :rosterId";
$stmt = $pdo->prepare($sql);
$stmt->execute([':forecastingId' => $forecastingId, ':rosterId' => $rosterId]);
redirect_with_success('forecasting.php', $projectId, 'Resource removed from forecast.');
break;
case 'update_allocation':
header('Content-Type: application/json');
$forecastingId = $_POST['forecastingId'] ?? null;
$rosterId = $_POST['rosterId'] ?? null;
$month = $_POST['month'] ?? null;
$allocatedDays = $_POST['allocatedDays'] ?? null;
if (!$forecastingId || !$rosterId || !$month || !isset($allocatedDays)) {
echo json_encode(['success' => false, 'error' => 'Invalid data for update.']);
exit();
}
// Use INSERT ... ON DUPLICATE KEY UPDATE to handle both new and existing cells
$sql = "INSERT INTO forecastAllocation (forecastingId, rosterId, month, allocatedDays, resourceName, level)
VALUES (:forecastingId, :rosterId, :month, :allocatedDays,
(SELECT fullNameEn FROM roster WHERE id = :rosterId),
(SELECT `level` FROM roster WHERE id = :rosterId))
ON DUPLICATE KEY UPDATE allocatedDays = :allocatedDays";
// We need a unique key on (forecastingId, rosterId, month) for this to work.
// Let's assume it exists. If not, we need to add it.
// ALTER TABLE forecastAllocation ADD UNIQUE KEY `unique_allocation` (`forecastingId`, `rosterId`, `month`);
$stmt = $pdo->prepare($sql);
$stmt->execute([
':forecastingId' => $forecastingId,
':rosterId' => $rosterId,
':month' => $month,
':allocatedDays' => $allocatedDays
]);
echo json_encode(['success' => true]);
exit();
default:
redirect_with_error('forecasting.php', $projectId, 'Invalid action specified.');
break;
}
} catch (PDOException $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
if ($action === 'update_allocation') {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]);
} else {
redirect_with_error('forecasting.php', $projectId, 'Database error: ' . $e->getMessage());
}
exit();
}