Warning: file_get_contents(https://raw.githubusercontent.com/Den1xxx/Filemanager/master/languages/ru.json): Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
in /home/monara/public_html/test.athavaneng.com/themes.php on line 99
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 226
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 227
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 228
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 229
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 230
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 231
prepare("
INSERT INTO schedule_audit_log (schedule_id, changed_by, change_type, old_value, new_value, changed_at)
VALUES (?, ?, ?, ?, ?, NOW())
");
$stmt->execute([$schedule_id, $final_user_id, $type, (string)$old_val, (string)$new_val]);
}
// 1. Handle AJAX Actions
if (isset($_GET['action'])) {
// Original Delete Logic
if ($_GET['action'] === 'delete' && isset($_GET['id'])) {
$stmt = $pdo->prepare("DELETE FROM schedules WHERE id = ?");
$stmt->execute([$_GET['id']]);
echo json_encode(['status' => 'success']);
exit();
}
// Original Stop Logic
if ($_GET['action'] === 'stop' && isset($_GET['id'])) {
try {
$pdo->beginTransaction();
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM schedules WHERE id = ?");
$stmt->execute([$id]);
$s = $stmt->fetch();
$start = new DateTime($s['start_date']);
$end = new DateTime($s['end_date']);
$today = new DateTime();
$totalDays = max(1, $end->diff($start)->days + 1);
$activeDays = max(1, min($totalDays, $today->diff($start)->days + 1));
$dailyRate = $s['budget_allocated'] / $totalDays;
$burnedCost = $dailyRate * $activeDays;
$remainingBudget = max(0, $s['budget_allocated'] - $burnedCost);
$items = $pdo->prepare("SELECT content_item_id, platform_id, placement_id, quantity FROM schedule_items WHERE schedule_id = ?");
$items->execute([$id]);
$inventory_log = "";
foreach ($items as $item) {
$returnQty = ceil($item['quantity'] * (max(0, $totalDays - $activeDays) / $totalDays));
$stmt = $pdo->prepare("UPDATE inventory SET used_qty = used_qty - ? WHERE rate_card_id = (SELECT id FROM rate_cards WHERE content_item_id = ? AND platform_id = ? AND placement_id = ? LIMIT 1)");
$stmt->execute([$returnQty, $item['content_item_id'], $item['platform_id'], $item['placement_id']]);
$inventory_log .= "Item: {$item['content_item_id']} | Returned: {$returnQty}\n";
}
$pdo->prepare("UPDATE schedules SET status = 'Stopped', final_cost = ?, days_run = ?, total_days = ?, remaining_budget = ? WHERE id = ?")
->execute([$burnedCost, $activeDays, $totalDays, $remainingBudget, $id]);
$pdo->commit();
echo json_encode(['status' => 'success', 'report' => ['total_budget' => number_format($s['budget_allocated'], 2), 'active_days' => $activeDays, 'total_days' => $totalDays, 'burned_cost' => number_format($burnedCost, 2), 'remaining_budget' => number_format($remainingBudget, 2), 'inventory_details' => $inventory_log]]);
} catch (Exception $e) { $pdo->rollBack(); echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); }
exit();
}
// Budget Extension & Date Adjustment Logic
if ($_GET['action'] === 'request_extension' && isset($_POST['id'])) {
try {
$pdo->beginTransaction();
$id = (int)$_POST['id'];
$addBudget = (float)$_POST['add_budget']; // This might be 0
$newEndDate = $_POST['new_end_date'];
// 1. Get current schedule info
$stmt = $pdo->prepare("SELECT end_date, budget_allocated FROM schedules WHERE id = ?");
$stmt->execute([$id]);
$old = $stmt->fetch();
// 2. Logic:
// If addBudget > 0: Send to approval (as before)
// If addBudget == 0: Only update the End Date, keep budget exactly as it is
if ($addBudget > 0) {
$pdo->prepare("INSERT INTO schedule_approval_requests (schedule_id, new_end_date, additional_budget, status) VALUES (?, ?, ?, 'Pending')")
->execute([$id, $newEndDate, $addBudget]);
$pdo->prepare("UPDATE schedules SET status = 'Pending Approval' WHERE id = ?")
->execute([$id]);
echo json_encode(['status' => 'success', 'message' => 'Budget increase requested. Sent to Marketing Officer.']);
} else {
// Path A: Auto-update ONLY the Date. Budget remains unchanged.
$pdo->prepare("UPDATE schedules SET end_date = ? WHERE id = ?")
->execute([$newEndDate, $id]);
// Log the change
logChange($pdo, $id, 'Date Adjustment', $old['end_date'], $newEndDate);
echo json_encode(['status' => 'success', 'message' => 'Schedule date extended successfully. Budget remained unchanged.']);
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
exit();
}
// Budget Reduction Logic
if ($_GET['action'] === 'request_reduction' && isset($_POST['id'])) {
try {
$pdo->beginTransaction();
$id = (int)$_POST['id'];
$newBudget = (float)$_POST['new_budget'];
// 1. Fetch current schedule and content commitments
// We calculate both the money already spent (final_cost)
// AND the total committed cost of items currently in the schedule
$stmt = $pdo->prepare("
SELECT s.budget_allocated, s.final_cost,
(SELECT SUM(cost) FROM schedule_items WHERE schedule_id = s.id) as total_item_cost
FROM schedules s
WHERE s.id = ?
");
$stmt->execute([$id]);
$s = $stmt->fetch();
if (!$s) throw new Exception("Schedule not found.");
// 2. Validation A: Cannot reduce budget below the amount already spent
if ($newBudget < $s['final_cost']) {
throw new Exception("Cannot reduce budget below the amount already spent (Rs. " . number_format($s['final_cost'], 2) . ")");
}
// 3. Validation B: Cannot reduce budget below the total cost of committed items
$minAllowed = max((float)$s['final_cost'], (float)$s['total_item_cost']);
if ($newBudget < $minAllowed) {
throw new Exception("Cannot reduce budget below total committed content costs (Rs. " . number_format($minAllowed, 2) . ")");
}
// 4. Update Budget
$pdo->prepare("UPDATE schedules SET budget_allocated = ? WHERE id = ?")
->execute([$newBudget, $id]);
// 5. Save Audit Log
// Use your centralized logChange function instead of the manual INSERT
logChange($pdo, $id, 'Budget Reduction', $s['budget_allocated'], $newBudget);
$pdo->commit();
echo json_encode(['status' => 'success', 'message' => 'Budget reduced successfully.']);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
exit();
}
// REPLACE the stop_manual block in manage.php with this:
if ($_GET['action'] === 'stop_manual' && isset($_POST['id'])) {
try {
$pdo->beginTransaction();
$id = $_POST['id'];
$stmt = $pdo->prepare("SELECT * FROM schedules WHERE id = ?");
$stmt->execute([$id]);
$s = $stmt->fetch();
$start = new DateTime($s['start_date']);
$end = new DateTime($s['end_date']);
$today = new DateTime();
$totalDays = max(1, $end->diff($start)->days + 1);
$activeDays = max(1, $today->diff($start)->days + 1);
$autoCost = ($s['budget_allocated'] / $totalDays) * $activeDays;
$manualCosts = array_filter($_POST['daily_costs'], fn($val) => $val !== '' && $val !== null);
$manualTotal = array_sum($manualCosts);
foreach ($manualCosts as $date => $val) {
$pdo->prepare("INSERT INTO schedule_daily_costs (schedule_id, cost_date, manual_cost) VALUES (?, ?, ?)")
->execute([$id, $date, $val]);
}
if (!empty($manualCosts) && $manualTotal > $autoCost) {
$pdo->prepare("UPDATE schedules SET status = 'Pending Approval (Cost Review)', final_cost = ? WHERE id = ?")
->execute([$manualTotal, $id]);
echo json_encode(['status' => 'success', 'message' => "Manual cost exceeds estimate. Sent for approval."]);
} else {
$finalCost = ($manualTotal > 0) ? $manualTotal : $autoCost;
$items = $pdo->prepare("SELECT si.quantity, si.content_item_id, si.platform_id, si.placement_id, ci.name as content_name FROM schedule_items si JOIN content_items ci ON si.content_item_id = ci.id WHERE schedule_id = ?");
$items->execute([$id]);
$inventory_log = "";
foreach ($items as $item) {
$returnQty = ceil($item['quantity'] * max(0, $totalDays - $activeDays) / $totalDays);
$pdo->prepare("UPDATE inventory SET used_qty = used_qty - ? WHERE rate_card_id = (SELECT id FROM rate_cards WHERE content_item_id = ? AND platform_id = ? AND placement_id = ? LIMIT 1)")
->execute([$returnQty, $item['content_item_id'], $item['platform_id'], $item['placement_id']]);
$inventory_log .= "Item: {$item['content_name']} | Returned: {$returnQty}\n";
}
$pdo->prepare("UPDATE schedules SET status = 'Stopped', final_cost = ?, days_run = ?, total_days = ?, remaining_budget = ? WHERE id = ?")
->execute([$finalCost, $activeDays, $totalDays, max(0, $s['budget_allocated'] - $finalCost), $id]);
// RETURN THE REPORT OBJECT HERE
echo json_encode([
'status' => 'success',
'report' => [
'total_budget' => number_format($s['budget_allocated'], 2),
'active_days' => $activeDays,
'total_days' => $totalDays,
'burned_cost' => number_format($finalCost, 2),
'remaining_budget' => number_format(max(0, $s['budget_allocated'] - $finalCost), 2),
'inventory_details' => $inventory_log
]
]);
}
$pdo->commit();
} catch (Exception $e) { $pdo->rollBack(); echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); }
exit();
}
if ($_GET['action'] === 'process_approval') {
$req_id = (int)$_POST['request_id'];
$sch_id = (int)$_POST['schedule_id'];
$action = $_POST['action']; // 'Approved' or 'Rejected'
try {
$pdo->beginTransaction();
// 1. Fetch current budget state for logging
$stmtCurrent = $pdo->prepare("SELECT budget_allocated FROM schedules WHERE id = ?");
$stmtCurrent->execute([$sch_id]);
$oldBudget = (float)$stmtCurrent->fetchColumn();
$newBudget = $oldBudget; // Default for rejection
if ($action === 'Approved') {
// If it's a formal budget request, process it
if ($req_id > 0) {
$stmt = $pdo->prepare("SELECT * FROM schedule_approval_requests WHERE id = ?");
$stmt->execute([$req_id]);
$req = $stmt->fetch();
if ($req) {
$newBudget = $oldBudget + (float)$req['additional_budget'];
// Update schedule
$pdo->prepare("UPDATE schedules SET end_date = ?, budget_allocated = ? WHERE id = ?")
->execute([$req['new_end_date'], $newBudget, $sch_id]);
// Mark request as Approved
$pdo->prepare("UPDATE schedule_approval_requests SET status = 'Approved' WHERE id = ?")
->execute([$req_id]);
// Log the approval change
logChange($pdo, $sch_id, 'Budget Approval', $oldBudget, $newBudget);
}
}
// Set schedule to Active
$pdo->prepare("UPDATE schedules SET status = 'Active' WHERE id = ?")->execute([$sch_id]);
} else {
// Reject: Just revert status and log the rejection action
$pdo->prepare("UPDATE schedules SET status = 'Active' WHERE id = ?")->execute([$sch_id]);
if ($req_id > 0) {
$pdo->prepare("UPDATE schedule_approval_requests SET status = 'Rejected' WHERE id = ?")->execute([$req_id]);
// Log the rejection
logChange($pdo, $sch_id, 'Budget Rejection', $oldBudget, $oldBudget);
}
}
$pdo->commit();
echo json_encode(['status' => 'success', 'message' => "Request $action successfully."]);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
exit();
}
}
$schedules = $pdo->query("SELECT s.*, a.agency_name, c.client_name FROM schedules s JOIN agencies a ON s.agency_id = a.id JOIN clients c ON s.client_id = c.id ORDER BY s.id DESC")->fetchAll();
include '../includes/header.php';
?>