187 lines
7.7 KiB
PHP
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();
|
|
}
|