diff --git a/assets/js/billing.js b/assets/js/billing.js new file mode 100644 index 0000000..282d32e --- /dev/null +++ b/assets/js/billing.js @@ -0,0 +1,30 @@ +function initBillingPage(projectId) { + document.querySelectorAll('.billing-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_billing.php', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Maybe show a small success indicator + } else { + alert('Error saving billing amount: ' + data.error); + } + }) + .catch(error => { + console.error('Error:', error); + alert('An unexpected error occurred.'); + }); + }); + }); +} diff --git a/billing.php b/billing.php new file mode 100644 index 0000000..e404f20 --- /dev/null +++ b/billing.php @@ -0,0 +1,114 @@ +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 billing 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 billingMonthly WHERE projectId = :projectId AND month = :month"); + $stmt->execute([':projectId' => $projectId, ':month' => $monthStr]); + $count = $stmt->fetchColumn(); + + if ($count == 0) { + $insertStmt = $pdo->prepare("INSERT INTO billingMonthly (projectId, month, amount) VALUES (:projectId, :month, 0)"); + $insertStmt->execute([':projectId' => $projectId, ':month' => $monthStr]); + } + + $currentMonth->modify('+1 month'); + } + + // Fetch billing data + $stmt = $pdo->prepare("SELECT * FROM billingMonthly WHERE projectId = :projectId ORDER BY month"); + $stmt->execute([':projectId' => $projectId]); + $billingData = $stmt->fetchAll(PDO::FETCH_ASSOC); + +} catch (PDOException $e) { + $db_error = "Database error: " . $e->getMessage(); +} + +?> + + + + + + Billing - <?php echo htmlspecialchars($project['name']); ?> + + + + +
+
+ + + +
+ + +
+
+ + + + + ' . $currentMonth->format('M Y') . ''; + $currentMonth->modify('+1 month'); + } + ?> + + + + + + '; + } + ?> + + +
Billing
Billing
+
+
+
+
+ + + + + + diff --git a/db/migrations/006_create_billing_monthly_table.sql b/db/migrations/006_create_billing_monthly_table.sql new file mode 100644 index 0000000..1f8748a --- /dev/null +++ b/db/migrations/006_create_billing_monthly_table.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `billingMonthly` ( + `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/export_billing.php b/export_billing.php new file mode 100644 index 0000000..733e481 --- /dev/null +++ b/export_billing.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 billingMonthly WHERE projectId = :projectId ORDER BY month"); + $stmt->execute([':projectId' => $projectId]); + $billingData = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $filename = "billing_" . strtolower(str_replace(' ', '_', $projectName)) . ".csv"; + + header('Content-Type: text/csv'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + + $output = fopen('php://output', 'w'); + + // Header row + $header = ['Billing']; + foreach ($billingData as $row) { + $header[] = date("M Y", strtotime($row['month'])); + } + fputcsv($output, $header); + + // Data row + $data = ['Billing']; + foreach ($billingData 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 a09fab4..a64c2b4 100644 --- a/project_details.php +++ b/project_details.php @@ -137,6 +137,7 @@ if (!$project) { diff --git a/save_billing.php b/save_billing.php new file mode 100644 index 0000000..4481695 --- /dev/null +++ b/save_billing.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 billingMonthly 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);