diff --git a/assets/js/expenses.js b/assets/js/expenses.js
new file mode 100644
index 0000000..9954047
--- /dev/null
+++ b/assets/js/expenses.js
@@ -0,0 +1,30 @@
+function initExpensesPage(projectId) {
+ document.querySelectorAll('.expenses-amount').forEach(input => {
+ input.addEventListener('blur', function() {
+ const month = this.dataset.month;
+ const amount = this.value;
+
+ const formData = new FormData();
+ formData.append('projectId', projectId);
+ formData.append('month', month);
+ formData.append('amount', amount);
+
+ fetch('save_expenses.php', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ // Maybe show a small success indicator
+ } else {
+ alert('Error saving expenses amount: ' + data.error);
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ alert('An unexpected error occurred.');
+ });
+ });
+ });
+}
diff --git a/db/migrations/008_create_expenses_monthly_table.sql b/db/migrations/008_create_expenses_monthly_table.sql
new file mode 100644
index 0000000..743a0f2
--- /dev/null
+++ b/db/migrations/008_create_expenses_monthly_table.sql
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS `expensesMonthly` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `projectId` INT NOT NULL,
+ `month` DATE NOT NULL,
+ `amount` DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
+ FOREIGN KEY (`projectId`) REFERENCES `projects`(`id`) ON DELETE CASCADE,
+ UNIQUE KEY `project_month` (`projectId`, `month`)
+);
diff --git a/expenses.php b/expenses.php
new file mode 100644
index 0000000..9f67fad
--- /dev/null
+++ b/expenses.php
@@ -0,0 +1,121 @@
+exec($sql);
+ }
+
+ $stmt = $pdo->prepare("SELECT * FROM projects WHERE id = :id");
+ $stmt->execute([':id' => $projectId]);
+ $project = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$project) {
+ header("Location: projects.php");
+ exit();
+ }
+
+ // Initialize expenses records if they don't exist
+ $startDate = new DateTime($project['startDate']);
+ $endDate = new DateTime($project['endDate']);
+ $currentMonth = clone $startDate;
+
+ while ($currentMonth <= $endDate) {
+ $monthStr = $currentMonth->format('Y-m-01');
+ $stmt = $pdo->prepare("SELECT COUNT(*) FROM expensesMonthly WHERE projectId = :projectId AND month = :month");
+ $stmt->execute([':projectId' => $projectId, ':month' => $monthStr]);
+ $count = $stmt->fetchColumn();
+
+ if ($count == 0) {
+ $insertStmt = $pdo->prepare("INSERT INTO expensesMonthly (projectId, month, amount) VALUES (:projectId, :month, 0)");
+ $insertStmt->execute([':projectId' => $projectId, ':month' => $monthStr]);
+ }
+
+ $currentMonth->modify('+1 month');
+ }
+
+ // Fetch expenses data
+ $stmt = $pdo->prepare("SELECT * FROM expensesMonthly WHERE projectId = :projectId ORDER BY month");
+ $stmt->execute([':projectId' => $projectId]);
+ $expensesData = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+} catch (PDOException $e) {
+ $db_error = "Database error: " . $e->getMessage();
+}
+
+?>
+
+
+
+
+
+ Expenses -
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/export_expenses.php b/export_expenses.php
new file mode 100644
index 0000000..a1b46af
--- /dev/null
+++ b/export_expenses.php
@@ -0,0 +1,46 @@
+prepare("SELECT name FROM projects WHERE id = :id");
+ $stmt->execute([':id' => $projectId]);
+ $project = $stmt->fetch(PDO::FETCH_ASSOC);
+ $projectName = $project ? $project['name'] : 'project';
+
+ $stmt = $pdo->prepare("SELECT month, amount FROM expensesMonthly WHERE projectId = :projectId ORDER BY month");
+ $stmt->execute([':projectId' => $projectId]);
+ $expensesData = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ $filename = "expenses_" . strtolower(str_replace(' ', '_', $projectName)) . ".csv";
+
+ header('Content-Type: text/csv');
+ header('Content-Disposition: attachment; filename="' . $filename . '"');
+
+ $output = fopen('php://output', 'w');
+
+ // Header row
+ $header = ['Expenses'];
+ foreach ($expensesData as $row) {
+ $header[] = date("M Y", strtotime($row['month']));
+ }
+ fputcsv($output, $header);
+
+ // Data row
+ $data = ['Expenses'];
+ foreach ($expensesData as $row) {
+ $data[] = $row['amount'];
+ }
+ fputcsv($output, $data);
+
+ fclose($output);
+ exit();
+
+} catch (PDOException $e) {
+ die("Database error: " . $e->getMessage());
+}
diff --git a/project_details.php b/project_details.php
index f36259c..e599aa6 100644
--- a/project_details.php
+++ b/project_details.php
@@ -98,9 +98,15 @@ if ($project_id) {
$billing_stmt->execute([':pid' => $project_id]);
$monthly_billing = $billing_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
+ // Base Monthly Expenses
+ $expenses_stmt = $pdo->prepare("SELECT month, amount FROM expensesMonthly WHERE projectId = :pid");
+ $expenses_stmt->execute([':pid' => $project_id]);
+ $monthly_expenses = $expenses_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
+
// 2. Calculate cumulative values month by month
$cumulative_billing = 0;
$cumulative_cost = 0;
+ $cumulative_expenses = 0;
$previous_month_wip = 0;
foreach ($months as $month) {
@@ -108,11 +114,12 @@ if ($project_id) {
$cost = $monthly_costs[$month] ?? 0;
$base_monthly_wip = $monthly_wip[$month] ?? 0;
$billing = $monthly_billing[$month] ?? 0;
- $expenses = 0; // Placeholder for expenses
+ $expenses = $monthly_expenses[$month] ?? 0;
// Cumulative calculations
$cumulative_billing += $billing;
$cumulative_cost += $cost;
+ $cumulative_expenses += $expenses;
// WIP Calculation (new formula)
// current month WIP = previous month WIP + Month Expenses + base_monthly_wip - month Billing
@@ -122,7 +129,7 @@ if ($project_id) {
$financial_data['Billings'][$month] = $cumulative_billing;
$financial_data['Cost'][$month] = $cumulative_cost;
$financial_data['Opening Balance'][$month] = 0; // Placeholder
- $financial_data['Expenses'][$month] = $expenses;
+ $financial_data['Expenses'][$month] = $cumulative_expenses;
// Calculated metrics (NSR and Margin)
$nsr = $financial_data['WIP'][$month] + $financial_data['Billings'][$month] - $financial_data['Opening Balance'][$month] - $financial_data['Expenses'][$month];
@@ -177,6 +184,7 @@ if (!$project) {
Project:
diff --git a/save_expenses.php b/save_expenses.php
new file mode 100644
index 0000000..84abab6
--- /dev/null
+++ b/save_expenses.php
@@ -0,0 +1,36 @@
+ false, 'error' => 'Invalid request'];
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $projectId = $_POST['projectId'] ?? null;
+ $month = $_POST['month'] ?? null;
+ $amount = $_POST['amount'] ?? null;
+
+ if ($projectId && $month && $amount !== null) {
+ try {
+ $pdo = db();
+ $stmt = $pdo->prepare("UPDATE expensesMonthly SET amount = :amount WHERE projectId = :projectId AND month = :month");
+ $stmt->execute([
+ ':amount' => $amount,
+ ':projectId' => $projectId,
+ ':month' => $month
+ ]);
+
+ if ($stmt->rowCount() > 0) {
+ $response['success'] = true;
+ unset($response['error']);
+ } else {
+ $response['error'] = 'No record found to update.';
+ }
+ } catch (PDOException $e) {
+ $response['error'] = 'Database error: ' . $e->getMessage();
+ }
+ } else {
+ $response['error'] = 'Missing required fields.';
+ }
+}
+
+echo json_encode($response);