mirror of
https://github.com/Solo-Web-Works/BillTrak.git
synced 2026-01-29 06:20:34 +00:00
✨feature: Update database schema to separate payees from payments
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
Temp/
|
||||
node_modules/
|
||||
*-bak*
|
||||
bills.db
|
||||
|
||||
Binary file not shown.
@@ -18,15 +18,27 @@ try {
|
||||
switch($action) {
|
||||
case 'add':
|
||||
$data = [
|
||||
'date' => (new DateTime($_POST['date']))->format('Y-m-d'), // Normalize to YYYY-MM-DD
|
||||
'billName' => $_POST['billName'],
|
||||
'amount' => (float)$_POST['amount'],
|
||||
'date' => (new DateTime($_POST['date']))->format('Y-m-d'),
|
||||
'payeeId' => $_POST['payeeId'], // Payee ID instead of name
|
||||
'amount' => (float)$_POST['amount'],
|
||||
'paymentId' => $_POST['paymentId'],
|
||||
'year' => (int)explode('-', $_POST['date'])[0],
|
||||
'comment' => $_POST['comment']
|
||||
'comment' => $_POST['comment'] ?? '',
|
||||
'year' => (int)explode('-', $_POST['date'])[0]
|
||||
];
|
||||
|
||||
$result = Bill::add($data);
|
||||
$stmt = DB::connect()->prepare("
|
||||
INSERT INTO bills (billDate, payeeId, amount, paymentId, comment, year)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$result = $stmt->execute([
|
||||
$data['date'],
|
||||
$data['payeeId'],
|
||||
$data['amount'],
|
||||
$data['paymentId'],
|
||||
$data['comment'],
|
||||
$data['year']
|
||||
]);
|
||||
|
||||
echo json_encode(['success' => $result]);
|
||||
break;
|
||||
|
||||
@@ -75,17 +87,6 @@ try {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'getPayees':
|
||||
$stmt = DB::connect()->query("SELECT DISTINCT billName FROM bills ORDER BY billName ASC");
|
||||
echo json_encode($stmt->fetchAll(PDO::FETCH_COLUMN));
|
||||
break;
|
||||
|
||||
case 'addPayee':
|
||||
$stmt = DB::connect()->prepare("INSERT INTO bills (billName) VALUES (?)");
|
||||
$result = $stmt->execute([$_POST['billName']]);
|
||||
echo json_encode(['success' => $result]);
|
||||
break;
|
||||
|
||||
case 'getAll':
|
||||
echo json_encode(Bill::getAll()->fetchAll(PDO::FETCH_ASSOC));
|
||||
break;
|
||||
@@ -97,30 +98,56 @@ try {
|
||||
echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
|
||||
break;
|
||||
|
||||
case 'getTotals':
|
||||
case 'getTotals':
|
||||
echo json_encode(Bill::getYearlyTotals()->fetchAll(PDO::FETCH_ASSOC));
|
||||
break;
|
||||
|
||||
case 'getByYear':
|
||||
$year = $_GET['year'] ?? date('Y');
|
||||
$sort = $_GET['sort'] ?? 'date_asc'; // Default sorting
|
||||
$sort = $_GET['sort'] ?? 'date_desc';
|
||||
|
||||
$sortOptions = [
|
||||
'date_asc' => 'billDate ASC',
|
||||
'date_desc' => 'billDate DESC',
|
||||
'payee' => 'billName ASC, billDate ASC',
|
||||
'date_asc' => 'bills.billDate ASC',
|
||||
'date_desc' => 'bills.billDate DESC',
|
||||
'payee' => 'payees.name ASC, bills.billDate ASC'
|
||||
];
|
||||
|
||||
$orderBy = $sortOptions[$sort] ?? $sortOptions['date_asc'];
|
||||
|
||||
$stmt = DB::connect()->prepare("SELECT * FROM bills WHERE year = ? ORDER BY $orderBy");
|
||||
$stmt = DB::connect()->prepare("
|
||||
SELECT bills.*, payees.name AS payeeName
|
||||
FROM bills
|
||||
JOIN payees ON bills.payeeId = payees.id
|
||||
WHERE bills.year = ?
|
||||
ORDER BY $orderBy
|
||||
");
|
||||
$stmt->execute([$year]);
|
||||
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
break;
|
||||
|
||||
case 'addPayee':
|
||||
$stmt = DB::connect()->prepare("INSERT INTO payees (name) VALUES (?)");
|
||||
$result = $stmt->execute([$_POST['payeeName']]);
|
||||
echo json_encode(['success' => $result]);
|
||||
break;
|
||||
|
||||
case 'getPayees':
|
||||
try {
|
||||
$stmt = DB::connect()->query("SELECT id, name FROM payees ORDER BY name ASC");
|
||||
$payees = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo json_encode($payees);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'getYears':
|
||||
$stmt = DB::connect()->query("SELECT DISTINCT year FROM bills ORDER BY year DESC");
|
||||
echo json_encode($stmt->fetchAll(PDO::FETCH_COLUMN));
|
||||
try {
|
||||
$stmt = DB::connect()->query("SELECT DISTINCT year FROM bills ORDER BY year DESC");
|
||||
$years = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
echo json_encode($years);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -3,15 +3,22 @@ class DB {
|
||||
public static function connect() {
|
||||
$db = new PDO('sqlite:'.__DIR__.'/../data/bills.db');
|
||||
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS payees (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)");
|
||||
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS bills (
|
||||
id INTEGER PRIMARY KEY,
|
||||
billDate TEXT NOT NULL,
|
||||
billName TEXT NOT NULL,
|
||||
amount REAL NOT NULL,
|
||||
paymentId TEXT,
|
||||
year INTEGER NOT NULL,
|
||||
comment TEXT
|
||||
)");
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
billDate TEXT NOT NULL,
|
||||
payeeId INTEGER NOT NULL,
|
||||
amount REAL NOT NULL,
|
||||
paymentId TEXT,
|
||||
comment TEXT,
|
||||
year INTEGER NOT NULL,
|
||||
FOREIGN KEY (payeeId) REFERENCES payees(id) ON DELETE CASCADE
|
||||
)");
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<form id="addPayeeForm" class="border p-4 rounded shadow bg-gray-100">
|
||||
<h2 class="text-2xl font-bold mb-4">Add New Payee</h2>
|
||||
|
||||
<input type="text" id="newPayeeName" name="billName" class="bg-white border rounded p-2 w-5/6" placeholder="New Payee Name">
|
||||
<input type="text" id="newPayeeName" name="payeeName" class="bg-white border rounded p-2 w-5/6" placeholder="New Payee Name">
|
||||
|
||||
<button type="submit" class="mt-4 bg-blue-500 text-white px-4 py-2 rounded">Add Payee</button>
|
||||
</form>
|
||||
|
||||
16
js/app.js
16
js/app.js
@@ -31,21 +31,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const response = await fetch('/includes/api.php?action=getPayees');
|
||||
const payees = await response.json();
|
||||
|
||||
const payeeSelect = document.getElementById('editFormBillName');
|
||||
const payeeSelect = document.getElementById('billName');
|
||||
payeeSelect.innerHTML = ''; // Clear existing options
|
||||
|
||||
// Add default "Select Payee" option
|
||||
const defaultOption = document.createElement('option');
|
||||
defaultOption.value = '';
|
||||
defaultOption.textContent = 'Select Payee';
|
||||
defaultOption.disabled = true;
|
||||
payeeSelect.appendChild(defaultOption);
|
||||
|
||||
// Populate payees
|
||||
payees.forEach(payee => {
|
||||
const option = document.createElement('option');
|
||||
option.value = payee;
|
||||
option.textContent = payee;
|
||||
option.value = payee.id; // Use payee ID as the value
|
||||
option.textContent = payee.name; // Display payee name
|
||||
payeeSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
@@ -77,7 +69,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
billItem.innerHTML = `
|
||||
<p><strong>Date:</strong> ${formattedDate}</p>
|
||||
<p><strong>Bill Name:</strong> ${bill.billName}</p>
|
||||
<p><strong>Bill Name:</strong> ${bill.payeeName}</p>
|
||||
<p><strong>Amount:</strong> $${bill.amount.toFixed(2)}</p>
|
||||
<p><strong>Payment ID:</strong> ${bill.paymentId || 'N/A'}</p>
|
||||
<p><strong>Comment:</strong> ${bill.comment || 'N/A'}</p>
|
||||
|
||||
Reference in New Issue
Block a user