Primer version funcional
This commit is contained in:
75
models/ActivityLog.php
Executable file
75
models/ActivityLog.php
Executable file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
class ActivityLog {
|
||||
public static function all($limit = 100) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT al.*, u.username, u.first_name, u.last_name
|
||||
FROM activity_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.id
|
||||
ORDER BY al.created_at DESC
|
||||
LIMIT ?",
|
||||
[$limit]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getByUser($userId, $limit = 50) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT al.*, u.username, u.first_name, u.last_name
|
||||
FROM activity_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.id
|
||||
WHERE al.user_id = ?
|
||||
ORDER BY al.created_at DESC
|
||||
LIMIT ?",
|
||||
[$userId, $limit]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getByAction($action, $limit = 50) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT al.*, u.username
|
||||
FROM activity_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.id
|
||||
WHERE al.action = ?
|
||||
ORDER BY al.created_at DESC
|
||||
LIMIT ?",
|
||||
[$action, $limit]
|
||||
);
|
||||
}
|
||||
|
||||
public static function create($userId, $action, $details = '') {
|
||||
$db = Database::getInstance();
|
||||
$db->execute(
|
||||
"INSERT INTO activity_logs (user_id, action, details, ip_address) VALUES (?, ?, ?, ?)",
|
||||
[
|
||||
$userId,
|
||||
$action,
|
||||
$details,
|
||||
$_SERVER['REMOTE_ADDR'] ?? null
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public static function deleteAll() {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute("DELETE FROM activity_logs");
|
||||
}
|
||||
|
||||
public static function deleteByUser($userId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute("DELETE FROM activity_logs WHERE user_id = ?", [$userId]);
|
||||
}
|
||||
|
||||
public static function getDistinctUsers() {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT DISTINCT u.id, u.username, u.first_name, u.last_name
|
||||
FROM activity_logs al
|
||||
LEFT JOIN users u ON al.user_id = u.id
|
||||
WHERE u.id IS NOT NULL
|
||||
ORDER BY u.username"
|
||||
);
|
||||
}
|
||||
}
|
||||
207
models/CollectionConcept.php
Executable file
207
models/CollectionConcept.php
Executable file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
class CollectionConcept {
|
||||
public static function all($activeOnly = false) {
|
||||
$db = Database::getInstance();
|
||||
$sql = "SELECT c.*, u.username as created_by_name
|
||||
FROM finance_collection_concepts c
|
||||
LEFT JOIN users u ON c.created_by = u.id";
|
||||
|
||||
if ($activeOnly) {
|
||||
$sql .= " WHERE c.is_active = 1";
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY c.created_at DESC";
|
||||
|
||||
return $db->fetchAll($sql);
|
||||
}
|
||||
|
||||
public static function findById($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM finance_collection_concepts WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function create($data, $userId) {
|
||||
$db = Database::getInstance();
|
||||
$db->execute(
|
||||
"INSERT INTO finance_collection_concepts
|
||||
(name, description, total_amount, amount_per_house, concept_date, due_date, category, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
[
|
||||
$data['name'],
|
||||
$data['description'] ?? null,
|
||||
$data['total_amount'] ?? null,
|
||||
$data['amount_per_house'],
|
||||
$data['concept_date'],
|
||||
$data['due_date'] ?? null,
|
||||
$data['category'] ?? null,
|
||||
$userId
|
||||
]
|
||||
);
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
|
||||
public static function update($id, $data) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute(
|
||||
"UPDATE finance_collection_concepts
|
||||
SET name = ?, description = ?, total_amount = ?, amount_per_house = ?, concept_date = ?, due_date = ?, category = ?
|
||||
WHERE id = ?",
|
||||
[
|
||||
$data['name'],
|
||||
$data['description'] ?? null,
|
||||
$data['total_amount'] ?? null,
|
||||
$data['amount_per_house'],
|
||||
$data['concept_date'],
|
||||
$data['due_date'] ?? null,
|
||||
$data['category'] ?? null,
|
||||
$id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public static function save($data, $userId) {
|
||||
if (isset($data['id']) && !empty($data['id'])) {
|
||||
return self::update($data['id'], $data);
|
||||
} else {
|
||||
return self::create($data, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute(
|
||||
"DELETE FROM finance_collection_concepts WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getPaymentsByConcept($conceptId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT cp.*, h.number as house_number, h.owner_name
|
||||
FROM finance_collection_payments cp
|
||||
JOIN houses h ON cp.house_id = h.id
|
||||
WHERE cp.concept_id = ?
|
||||
ORDER BY CAST(h.number AS UNSIGNED)",
|
||||
[$conceptId]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getTotalCollected($conceptId) {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM finance_collection_payments
|
||||
WHERE concept_id = ?",
|
||||
[$conceptId]
|
||||
);
|
||||
return $result['total'] ?? 0;
|
||||
}
|
||||
|
||||
public static function getCollectionStatus($conceptId) {
|
||||
$concept = self::findById($conceptId);
|
||||
$totalHouses = House::countActive();
|
||||
$totalExpected = $concept['amount_per_house'] * $totalHouses;
|
||||
$totalCollected = self::getTotalCollected($conceptId);
|
||||
$totalExpenses = Expense::getTotalByConcept($conceptId);
|
||||
|
||||
return [
|
||||
'total_houses' => $totalHouses,
|
||||
'total_expected' => $totalExpected,
|
||||
'total_collected' => $totalCollected,
|
||||
'total_expenses' => $totalExpenses,
|
||||
'balance' => $totalCollected - $totalExpenses,
|
||||
'percentage' => $totalExpected > 0 ? round(($totalCollected / $totalExpected) * 100, 2) : 0,
|
||||
'pending' => max(0, $totalExpected - $totalCollected)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class CollectionPayment {
|
||||
public static function getForConcept($conceptId) {
|
||||
$db = Database::getInstance();
|
||||
$payments = $db->fetchAll(
|
||||
"SELECT cp.*, h.number as house_number, h.owner_name
|
||||
FROM finance_collection_payments cp
|
||||
JOIN houses h ON cp.house_id = h.id
|
||||
WHERE cp.concept_id = ?
|
||||
ORDER BY CAST(h.number AS UNSIGNED)",
|
||||
[$conceptId]
|
||||
);
|
||||
|
||||
$result = [];
|
||||
foreach ($payments as $p) {
|
||||
$result[$p['house_id']] = $p;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function update($conceptId, $houseId, $amount, $userId, $notes = null, $paymentDate = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$existing = $db->fetchOne(
|
||||
"SELECT id FROM finance_collection_payments WHERE concept_id = ? AND house_id = ?",
|
||||
[$conceptId, $houseId]
|
||||
);
|
||||
|
||||
$currentDateTime = date('Y-m-d H:i:s');
|
||||
$paymentDate = $paymentDate ? $paymentDate : $currentDateTime;
|
||||
|
||||
if ($existing) {
|
||||
$db->execute(
|
||||
"UPDATE finance_collection_payments
|
||||
SET amount = ?, payment_date = ?, notes = ?, created_by = ?
|
||||
WHERE id = ?",
|
||||
[$amount, $paymentDate, $notes, $userId, $existing['id']]
|
||||
);
|
||||
} else {
|
||||
$db->execute(
|
||||
"INSERT INTO finance_collection_payments
|
||||
(concept_id, house_id, amount, payment_date, notes, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[$conceptId, $houseId, $amount, $paymentDate, $notes, $userId]
|
||||
);
|
||||
}
|
||||
|
||||
return ['success' => true, 'deleted' => false];
|
||||
}
|
||||
|
||||
public static function getByHouse($houseId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT cp.*, c.name as concept_name
|
||||
FROM finance_collection_payments cp
|
||||
JOIN finance_collection_concepts c ON cp.concept_id = c.id
|
||||
WHERE cp.house_id = ?
|
||||
ORDER BY cp.created_at DESC",
|
||||
[$houseId]
|
||||
);
|
||||
}
|
||||
|
||||
public static function initializePayments($conceptId, $userId) {
|
||||
require_once __DIR__ . '/House.php'; // Incluir House model
|
||||
$houses = House::allActive(); // Obtener solo casas activas
|
||||
|
||||
$db = Database::getInstance();
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
// Eliminar pagos existentes para este concepto antes de inicializar
|
||||
$db->execute("DELETE FROM finance_collection_payments WHERE concept_id = ?", [$conceptId]);
|
||||
|
||||
foreach ($houses as $house) {
|
||||
self::update($conceptId, $house['id'], 0, $userId, 'Pago inicializado', date('Y-m-d H:i:s'));
|
||||
}
|
||||
$db->commit();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
error_log("Error al inicializar pagos de concepto: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
198
models/Expense.php
Executable file
198
models/Expense.php
Executable file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
class Expense {
|
||||
public static function all($startDate = null, $endDate = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "SELECT e.*, u.username as created_by_name
|
||||
FROM expenses e
|
||||
LEFT JOIN users u ON e.created_by = u.id";
|
||||
|
||||
$params = [];
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$sql .= " WHERE expense_date BETWEEN ? AND ?";
|
||||
$params[] = $startDate;
|
||||
$params[] = $endDate;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY expense_date DESC";
|
||||
|
||||
return $db->fetchAll($sql, $params);
|
||||
}
|
||||
|
||||
public static function findById($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM expenses WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function create($data, $userId) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$db->execute(
|
||||
"INSERT INTO expenses (description, amount, expense_date, category, receipt_path, notes, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
[
|
||||
$data['description'],
|
||||
$data['amount'],
|
||||
$data['expense_date'],
|
||||
$data['category'] ?? null,
|
||||
$data['receipt_path'] ?? null,
|
||||
$data['notes'] ?? null,
|
||||
$userId
|
||||
]
|
||||
);
|
||||
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
|
||||
public static function update($id, $data) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$db->execute(
|
||||
"UPDATE expenses SET description = ?, amount = ?, expense_date = ?, category = ?, receipt_path = ?, notes = ? WHERE id = ?",
|
||||
[
|
||||
$data['description'],
|
||||
$data['amount'],
|
||||
$data['expense_date'],
|
||||
$data['category'] ?? null,
|
||||
$data['receipt_path'] ?? null,
|
||||
$data['notes'] ?? null,
|
||||
$id
|
||||
]
|
||||
);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public static function save($data, $userId, $receiptFile = null, $allocations = []) {
|
||||
$db = Database::getInstance();
|
||||
$isUpdate = isset($data['id']) && !empty($data['id']);
|
||||
$expenseId = $data['id'] ?? null;
|
||||
|
||||
// Handle receipt upload
|
||||
$receipt_path = $data['receipt_path'] ?? null; // Keep existing path if not new file
|
||||
if ($receiptFile && $receiptFile['error'] === UPLOAD_ERR_OK) {
|
||||
$uploadDir = __DIR__ . '/../uploads/expenses/';
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0777, true);
|
||||
}
|
||||
$filename = uniqid('receipt_') . '_' . basename($receiptFile['name']);
|
||||
$targetPath = $uploadDir . $filename;
|
||||
if (move_uploaded_file($receiptFile['tmp_name'], $targetPath)) {
|
||||
$receipt_path = '/uploads/expenses/' . $filename;
|
||||
} else {
|
||||
// Handle upload error, maybe return false or throw exception
|
||||
error_log("Failed to move uploaded file: " . $receiptFile['tmp_name'] . " to " . $targetPath);
|
||||
return false;
|
||||
}
|
||||
} elseif ($isUpdate && empty($data['existing_receipt'])) {
|
||||
// If it's an update and no new file, and existing_receipt is empty, clear the path
|
||||
$receipt_path = null;
|
||||
}
|
||||
|
||||
$data['receipt_path'] = $receipt_path;
|
||||
|
||||
if ($isUpdate) {
|
||||
self::update($expenseId, $data);
|
||||
} else {
|
||||
$expenseId = self::create($data, $userId);
|
||||
}
|
||||
|
||||
// Save allocations
|
||||
if ($expenseId && !empty($allocations)) {
|
||||
self::saveAllocations($expenseId, $allocations);
|
||||
} else if ($expenseId && $isUpdate) {
|
||||
// If update and no allocations, clear existing ones
|
||||
$db->execute("DELETE FROM expense_concept_allocations WHERE expense_id = ?", [$expenseId]);
|
||||
}
|
||||
|
||||
return $expenseId;
|
||||
}
|
||||
|
||||
public static function saveAllocations($expenseId, $allocations) {
|
||||
$db = Database::getInstance();
|
||||
// Delete existing allocations for this expense
|
||||
$db->execute("DELETE FROM expense_concept_allocations WHERE expense_id = ?", [$expenseId]);
|
||||
|
||||
foreach ($allocations as $allocation) {
|
||||
$db->execute(
|
||||
"INSERT INTO expense_concept_allocations (expense_id, concept_id, amount)
|
||||
VALUES (?, ?, ?)",
|
||||
[$expenseId, $allocation['concept_id'], $allocation['amount']]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function delete($id) {
|
||||
$db = Database::getInstance();
|
||||
// Optionally delete associated receipt file
|
||||
$expense = self::findById($id);
|
||||
if ($expense && $expense['receipt_path']) {
|
||||
$filePath = __DIR__ . '/..' . $expense['receipt_path'];
|
||||
if (file_exists($filePath)) {
|
||||
unlink($filePath);
|
||||
}
|
||||
}
|
||||
// Delete allocations first
|
||||
$db->execute("DELETE FROM expense_concept_allocations WHERE expense_id = ?", [$id]);
|
||||
return $db->execute(
|
||||
"DELETE FROM expenses WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getTotalByDateRange($startDate, $endDate) {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM expenses
|
||||
WHERE expense_date BETWEEN ? AND ?",
|
||||
[$startDate, $endDate]
|
||||
);
|
||||
return $result['total'] ?? 0;
|
||||
}
|
||||
|
||||
public static function getTotalByCategory($category, $startDate = null, $endDate = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM expenses
|
||||
WHERE category = ?";
|
||||
$params = [$category];
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$sql .= " AND expense_date BETWEEN ? AND ?";
|
||||
$params[] = $startDate;
|
||||
$params[] = $endDate;
|
||||
}
|
||||
|
||||
$result = $db->fetchOne($sql, $params);
|
||||
return $result['total'] ?? 0;
|
||||
}
|
||||
|
||||
public static function getConcepts($expenseId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT ec.*, c.name as concept_name
|
||||
FROM expense_concept_allocations ec
|
||||
JOIN finance_collection_concepts c ON ec.concept_id = c.id
|
||||
WHERE ec.expense_id = ?",
|
||||
[$expenseId]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getTotalByConcept($conceptId) {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM expense_concept_allocations
|
||||
WHERE concept_id = ?",
|
||||
[$conceptId]
|
||||
);
|
||||
return $result['total'] ?? 0;
|
||||
}
|
||||
}
|
||||
93
models/House.php
Executable file
93
models/House.php
Executable file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
class House {
|
||||
public static function all() {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM houses ORDER BY CAST(number AS UNSIGNED)"
|
||||
);
|
||||
}
|
||||
|
||||
public static function findById($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM houses WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function findByNumber($number) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM houses WHERE number = ?",
|
||||
[$number]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getActive() {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM houses WHERE status = 'activa' ORDER BY CAST(number AS UNSIGNED)"
|
||||
);
|
||||
}
|
||||
|
||||
public static function getAccessible() {
|
||||
$db = Database::getInstance();
|
||||
$accessibleIds = Auth::getAccessibleHouseIds();
|
||||
|
||||
if (empty($accessibleIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$placeholders = str_repeat('?,', count($accessibleIds) - 1) . '?';
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM houses WHERE id IN ($placeholders) ORDER BY CAST(number AS UNSIGNED)",
|
||||
$accessibleIds
|
||||
);
|
||||
}
|
||||
|
||||
public static function update($id, $data) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute(
|
||||
"UPDATE houses SET status = ?, consumption_only = ?, owner_name = ?, owner_email = ?, owner_phone = ? WHERE id = ?",
|
||||
[
|
||||
$data['status'],
|
||||
$data['consumption_only'] ?? 0,
|
||||
$data['owner_name'] ?? null,
|
||||
$data['owner_email'] ?? null,
|
||||
$data['owner_phone'] ?? null,
|
||||
$id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public static function countActive() {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COUNT(*) as count FROM houses WHERE status = 'activa'",
|
||||
[]
|
||||
);
|
||||
return $result['count'] ?? 0;
|
||||
}
|
||||
|
||||
public static function countAll() {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COUNT(*) as count FROM houses",
|
||||
[]
|
||||
);
|
||||
return $result['count'] ?? 0;
|
||||
}
|
||||
|
||||
public static function search($query) {
|
||||
$db = Database::getInstance();
|
||||
$term = "%$query%";
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM houses
|
||||
WHERE number LIKE ? OR owner_name LIKE ?
|
||||
ORDER BY CAST(number AS UNSIGNED)
|
||||
LIMIT 10",
|
||||
[$term, $term]
|
||||
);
|
||||
}
|
||||
}
|
||||
88
models/MonthlyBill.php
Executable file
88
models/MonthlyBill.php
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
class MonthlyBill {
|
||||
public static function getYear($year) {
|
||||
$db = Database::getInstance();
|
||||
$months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
|
||||
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
|
||||
|
||||
$result = [];
|
||||
foreach ($months as $month) {
|
||||
$bill = $db->fetchOne(
|
||||
"SELECT * FROM monthly_bills WHERE year = ? AND month = ?",
|
||||
[$year, $month]
|
||||
);
|
||||
$result[$month] = $bill;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function save($data) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$activeHouses = House::countActive();
|
||||
|
||||
if (isset($data['amount_per_house']) && !empty($data['amount_per_house'])) {
|
||||
$amountPerHouse = $data['amount_per_house'];
|
||||
} else {
|
||||
$amountPerHouse = round($data['total_amount'] / $activeHouses, 2);
|
||||
}
|
||||
|
||||
$existing = $db->fetchOne(
|
||||
"SELECT id FROM monthly_bills WHERE year = ? AND month = ?",
|
||||
[$data['year'], $data['month']]
|
||||
);
|
||||
|
||||
if ($existing) {
|
||||
$db->execute(
|
||||
"UPDATE monthly_bills SET total_amount = ?, amount_per_house = ?, due_date = ? WHERE id = ?",
|
||||
[
|
||||
$data['total_amount'],
|
||||
$amountPerHouse,
|
||||
$data['due_date'] ?? null,
|
||||
$existing['id']
|
||||
]
|
||||
);
|
||||
return $existing['id'];
|
||||
} else {
|
||||
$db->execute(
|
||||
"INSERT INTO monthly_bills (year, month, total_amount, amount_per_house, due_date)
|
||||
VALUES (?, ?, ?, ?, ?)",
|
||||
[
|
||||
$data['year'],
|
||||
$data['month'],
|
||||
$data['total_amount'],
|
||||
$amountPerHouse,
|
||||
$data['due_date'] ?? null
|
||||
]
|
||||
);
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
}
|
||||
|
||||
public static function updatePayments($year, $month) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$bill = $db->fetchOne(
|
||||
"SELECT * FROM monthly_bills WHERE year = ? AND month = ?",
|
||||
[$year, $month]
|
||||
);
|
||||
|
||||
if (!$bill) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$houses = House::getActive();
|
||||
|
||||
foreach ($houses as $house) {
|
||||
$monto_esperado = $bill['amount_per_house'];
|
||||
|
||||
if ($house['consumption_only'] && $year >= 2025) {
|
||||
$monto_esperado = max(0, $monto_esperado - 100.00);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
110
models/Payment.php
Executable file
110
models/Payment.php
Executable file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
class Payment {
|
||||
public static function getMatrix($year) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$houses = $db->fetchAll(
|
||||
"SELECT h.id, h.number, h.status, h.consumption_only, h.owner_name
|
||||
FROM houses h
|
||||
ORDER BY CAST(h.number AS UNSIGNED)"
|
||||
);
|
||||
|
||||
$months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
|
||||
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
|
||||
|
||||
$payments = [];
|
||||
foreach ($months as $month) {
|
||||
$monthPayments = $db->fetchAll(
|
||||
"SELECT house_id, amount, payment_date
|
||||
FROM payments
|
||||
WHERE year = ? AND month = ?",
|
||||
[$year, $month]
|
||||
);
|
||||
$payments[$month] = [];
|
||||
foreach ($monthPayments as $p) {
|
||||
$payments[$month][$p['house_id']] = $p;
|
||||
}
|
||||
}
|
||||
|
||||
return ['houses' => $houses, 'payments' => $payments, 'months' => $months];
|
||||
}
|
||||
|
||||
public static function getExpectedAmount($house, $year, $month) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$bill = $db->fetchOne(
|
||||
"SELECT * FROM monthly_bills WHERE year = ? AND month = ?",
|
||||
[$year, $month]
|
||||
);
|
||||
|
||||
if (!$bill) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$monto_base = $bill['amount_per_house'];
|
||||
|
||||
if ($house['consumption_only'] && $year >= 2025) {
|
||||
$monto_base = max(0, $monto_base - 100.00);
|
||||
}
|
||||
|
||||
return round($monto_base, 2);
|
||||
}
|
||||
|
||||
public static function update($houseId, $year, $month, $amount, $userId, $notes = null, $paymentMethod = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$existing = $db->fetchOne(
|
||||
"SELECT id FROM payments WHERE house_id = ? AND year = ? AND month = ?",
|
||||
[$houseId, $year, $month]
|
||||
);
|
||||
|
||||
if ($amount == 0 && $existing) {
|
||||
$db->execute(
|
||||
"DELETE FROM payments WHERE id = ?",
|
||||
[$existing['id']]
|
||||
);
|
||||
return ['success' => true, 'deleted' => true];
|
||||
}
|
||||
|
||||
if ($existing) {
|
||||
$db->execute(
|
||||
"UPDATE payments SET amount = ?, payment_date = NOW(), notes = ?, payment_method = ?, created_by = ? WHERE id = ?",
|
||||
[$amount, $notes, $paymentMethod, $userId, $existing['id']]
|
||||
);
|
||||
} else {
|
||||
$db->execute(
|
||||
"INSERT INTO payments (house_id, year, month, amount, payment_date, notes, payment_method, created_by)
|
||||
VALUES (?, ?, ?, ?, NOW(), ?, ?, ?)",
|
||||
[$houseId, $year, $month, $amount, $notes, $paymentMethod, $userId]
|
||||
);
|
||||
}
|
||||
|
||||
return ['success' => true, 'deleted' => false];
|
||||
}
|
||||
|
||||
public static function getByHouse($houseId, $year = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
if ($year) {
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM payments WHERE house_id = ? AND year = ? ORDER BY FIELD(month, 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre')",
|
||||
[$houseId, $year]
|
||||
);
|
||||
}
|
||||
|
||||
return $db->fetchAll(
|
||||
"SELECT * FROM payments WHERE house_id = ? ORDER BY year DESC, FIELD(month, 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre') DESC",
|
||||
[$houseId]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getTotalByYear($year) {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total FROM payments WHERE year = ?",
|
||||
[$year]
|
||||
);
|
||||
return $result['total'] ?? 0;
|
||||
}
|
||||
}
|
||||
399
models/Report.php
Executable file
399
models/Report.php
Executable file
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
|
||||
class Report {
|
||||
public static function getGeneralBalance($startDate = null, $endDate = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$whereClause = '';
|
||||
$params = [];
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$whereClause = " WHERE YEAR(cp.payment_date) BETWEEN ? AND ?";
|
||||
$params = [$startDate, $endDate];
|
||||
}
|
||||
|
||||
$accessibleHouseIds = Auth::getAccessibleHouseIds();
|
||||
|
||||
if (!empty($accessibleHouseIds) && !Auth::isAdmin()) {
|
||||
$placeholders = str_repeat('?,', count($accessibleHouseIds) - 1) . '?';
|
||||
|
||||
if ($whereClause) {
|
||||
$whereClause .= " AND cp.house_id IN ($placeholders)";
|
||||
} else {
|
||||
$whereClause = " WHERE cp.house_id IN ($placeholders)";
|
||||
}
|
||||
|
||||
$params = array_merge($params, $accessibleHouseIds);
|
||||
}
|
||||
|
||||
$totalConceptPayments = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(cp.amount), 0) as total
|
||||
FROM finance_collection_payments cp
|
||||
LEFT JOIN finance_collection_concepts c ON cp.concept_id = c.id
|
||||
$whereClause",
|
||||
$params
|
||||
);
|
||||
$totalConceptPayments = $totalConceptPayments['total'] ?? 0;
|
||||
|
||||
$totalExpenses = 0;
|
||||
$balance = $totalConceptPayments;
|
||||
|
||||
if (Auth::isAdmin() || Auth::isCapturist()) {
|
||||
$expenseParams = [];
|
||||
$expenseWhere = '';
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$expenseWhere = " WHERE YEAR(expense_date) BETWEEN ? AND ?";
|
||||
$expenseParams = [$startDate, $endDate];
|
||||
}
|
||||
|
||||
$totalExpenses = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM expenses $expenseWhere",
|
||||
$expenseParams
|
||||
);
|
||||
$totalExpenses = $totalExpenses['total'] ?? 0;
|
||||
|
||||
$balance = $totalConceptPayments - $totalExpenses;
|
||||
}
|
||||
|
||||
return [
|
||||
'total_incomes' => $totalConceptPayments,
|
||||
'water_incomes' => 0,
|
||||
'concept_incomes' => $totalConceptPayments,
|
||||
'total_expenses' => $totalExpenses,
|
||||
'balance' => $balance
|
||||
];
|
||||
}
|
||||
|
||||
public static function getHouseStatement($houseId, $year = null) {
|
||||
$db = Database::getInstance();
|
||||
$house = House::findById($houseId);
|
||||
|
||||
$whereClause = $year ? " AND year = ?" : "";
|
||||
$params = $year ? [$houseId, $year] : [$houseId];
|
||||
|
||||
$waterPayments = $db->fetchAll(
|
||||
"SELECT 'Agua' as type, month, amount, payment_date, notes
|
||||
FROM payments
|
||||
WHERE house_id = ? $whereClause
|
||||
ORDER BY year DESC, FIELD(month, 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre') DESC",
|
||||
$params
|
||||
);
|
||||
|
||||
$conceptPayments = $db->fetchAll(
|
||||
"SELECT 'Concepto' as type, c.name as description, cp.amount, cp.payment_date, cp.notes
|
||||
FROM finance_collection_payments cp
|
||||
JOIN finance_collection_concepts c ON cp.concept_id = c.id
|
||||
WHERE cp.house_id = ?" .
|
||||
($year ? " AND YEAR(cp.payment_date) = ?" : "") . "
|
||||
ORDER BY cp.payment_date DESC",
|
||||
$year ? [$houseId, $year] : [$houseId]
|
||||
);
|
||||
|
||||
return [
|
||||
'house' => $house,
|
||||
'water_payments' => $waterPayments,
|
||||
'concept_payments' => $conceptPayments
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPaymentsByYear($year) {
|
||||
$db = Database::getInstance();
|
||||
$months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
|
||||
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
|
||||
|
||||
$data = [];
|
||||
foreach ($months as $month) {
|
||||
$result = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total, COUNT(*) as count
|
||||
FROM payments
|
||||
WHERE year = ? AND month = ?",
|
||||
[$year, $month]
|
||||
);
|
||||
$data[$month] = [
|
||||
'total' => $result['total'] ?? 0,
|
||||
'count' => $result['count'] ?? 0
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getExpensesByCategory($startDate = null, $endDate = null) {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "SELECT category, COALESCE(SUM(amount), 0) as total
|
||||
FROM expenses";
|
||||
|
||||
$params = [];
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$sql .= " WHERE YEAR(expense_date) BETWEEN ? AND ?";
|
||||
$params = [$startDate, $endDate];
|
||||
}
|
||||
|
||||
$sql .= " GROUP BY category ORDER BY total DESC";
|
||||
|
||||
return $db->fetchAll($sql, $params);
|
||||
}
|
||||
|
||||
public static function getCollectionReport($conceptId) {
|
||||
$concept = CollectionConcept::findById($conceptId);
|
||||
$status = CollectionConcept::getCollectionStatus($conceptId);
|
||||
$payments = CollectionConcept::getPaymentsByConcept($conceptId);
|
||||
|
||||
return [
|
||||
'concept' => $concept,
|
||||
'status' => $status,
|
||||
'payments' => $payments
|
||||
];
|
||||
}
|
||||
|
||||
public static function getDashboardStats($year = null, $accessibleHouseIds = []) {
|
||||
$year = $year ?? date('Y');
|
||||
$db = Database::getInstance();
|
||||
|
||||
if (!empty($accessibleHouseIds) && !Auth::isAdmin()) {
|
||||
$placeholders = str_repeat('?,', count($accessibleHouseIds) - 1) . '?';
|
||||
|
||||
$totalHouses = count($accessibleHouseIds);
|
||||
|
||||
$activeHousesResult = $db->fetchOne(
|
||||
"SELECT COUNT(*) as count
|
||||
FROM houses
|
||||
WHERE id IN ($placeholders) AND status = 'activa'",
|
||||
$accessibleHouseIds
|
||||
);
|
||||
$activeHouses = $activeHousesResult['count'] ?? 0;
|
||||
|
||||
$conceptPayments = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(cp.amount), 0) as total
|
||||
FROM finance_collection_payments cp
|
||||
WHERE YEAR(cp.payment_date) = ? AND cp.house_id IN ($placeholders)",
|
||||
array_merge([$year], $accessibleHouseIds)
|
||||
);
|
||||
$conceptPayments = $conceptPayments['total'] ?? 0;
|
||||
|
||||
$totalExpenses = 0;
|
||||
$balance = $conceptPayments;
|
||||
} else {
|
||||
$totalHouses = House::countAll();
|
||||
$activeHouses = House::countActive();
|
||||
|
||||
$conceptPayments = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(cp.amount), 0) as total
|
||||
FROM finance_collection_payments cp
|
||||
WHERE YEAR(cp.payment_date) = ?",
|
||||
[$year]
|
||||
);
|
||||
$conceptPayments = $conceptPayments['total'] ?? 0;
|
||||
|
||||
$totalExpenses = $db->fetchOne(
|
||||
"SELECT COALESCE(SUM(amount), 0) as total
|
||||
FROM expenses
|
||||
WHERE YEAR(expense_date) = ?",
|
||||
[$year]
|
||||
);
|
||||
$totalExpenses = $totalExpenses['total'] ?? 0;
|
||||
|
||||
$balance = $conceptPayments - $totalExpenses;
|
||||
}
|
||||
|
||||
$totalConcepts = $db->fetchOne(
|
||||
"SELECT COUNT(*) as count
|
||||
FROM finance_collection_concepts
|
||||
WHERE is_active = 1"
|
||||
);
|
||||
$totalConcepts = $totalConcepts['count'] ?? 0;
|
||||
|
||||
return [
|
||||
'total_houses' => $totalHouses,
|
||||
'active_houses' => $activeHouses,
|
||||
'total_payments' => $conceptPayments,
|
||||
'total_expenses' => $totalExpenses,
|
||||
'balance' => $balance,
|
||||
'active_concepts' => $totalConcepts,
|
||||
'year' => $year
|
||||
];
|
||||
}
|
||||
|
||||
public static function getWaterDebtors($filters = []) {
|
||||
$db = Database::getInstance();
|
||||
$allMonths = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
|
||||
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
|
||||
|
||||
$year = $filters['year'] ?? null;
|
||||
$months = $filters['months'] ?? $allMonths;
|
||||
$houseId = $filters['house_id'] ?? null;
|
||||
$accessibleHouseIds = $filters['accessible_house_ids'] ?? [];
|
||||
|
||||
$whereHouse = '';
|
||||
$houseParams = [];
|
||||
|
||||
if ($houseId) {
|
||||
$whereHouse = "AND h.id = ?";
|
||||
$houseParams = [$houseId];
|
||||
}
|
||||
|
||||
$sql = "SELECT h.id, h.number, h.owner_name, h.status, h.consumption_only
|
||||
FROM houses h
|
||||
WHERE h.status = 'activa' $whereHouse";
|
||||
|
||||
if (!empty($accessibleHouseIds) && !Auth::isAdmin()) {
|
||||
$placeholders = str_repeat('?,', count($accessibleHouseIds) - 1) . '?';
|
||||
$sql .= " AND h.id IN ($placeholders)";
|
||||
$houseParams = array_merge($houseParams, $accessibleHouseIds);
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY CAST(h.number AS UNSIGNED)";
|
||||
|
||||
$houses = $db->fetchAll($sql, $houseParams);
|
||||
|
||||
if ($year) {
|
||||
$yearsToCheck = [$year];
|
||||
} else {
|
||||
$years = $db->fetchAll("SELECT DISTINCT year FROM payments ORDER BY year");
|
||||
$yearsToCheck = array_column($years, 'year');
|
||||
}
|
||||
|
||||
$debtors = [];
|
||||
$grandTotalExpected = 0;
|
||||
$grandTotalPaid = 0;
|
||||
|
||||
foreach ($houses as $house) {
|
||||
$totalExpected = 0;
|
||||
$totalPaid = 0;
|
||||
$monthDetails = [];
|
||||
|
||||
foreach ($yearsToCheck as $yr) {
|
||||
foreach ($months as $month) {
|
||||
$expected = Payment::getExpectedAmount($house, $yr, $month);
|
||||
$payment = $db->fetchOne(
|
||||
"SELECT amount FROM payments WHERE house_id = ? AND year = ? AND month = ?",
|
||||
[$house['id'], $yr, $month]
|
||||
);
|
||||
$paid = $payment['amount'] ?? 0;
|
||||
$due = $expected - $paid;
|
||||
|
||||
$totalExpected += $expected;
|
||||
$totalPaid += $paid;
|
||||
|
||||
if ($due > 0) {
|
||||
$monthDetails[] = [
|
||||
'year' => $yr,
|
||||
'month' => $month,
|
||||
'expected' => $expected,
|
||||
'paid' => $paid,
|
||||
'due' => $due
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$houseTotalDue = $totalExpected - $totalPaid;
|
||||
|
||||
if ($houseTotalDue > 0) {
|
||||
$debtors[] = [
|
||||
'house_id' => $house['id'],
|
||||
'house_number' => $house['number'],
|
||||
'owner_name' => $house['owner_name'],
|
||||
'months_due' => $monthDetails,
|
||||
'total_due' => $houseTotalDue
|
||||
];
|
||||
}
|
||||
|
||||
$grandTotalExpected += $totalExpected;
|
||||
$grandTotalPaid += $totalPaid;
|
||||
}
|
||||
|
||||
$grandTotalDue = $grandTotalExpected - $grandTotalPaid;
|
||||
|
||||
return [
|
||||
'debtors' => $debtors,
|
||||
'total_due' => $grandTotalDue,
|
||||
'total_expected' => $grandTotalExpected,
|
||||
'total_paid' => $grandTotalPaid,
|
||||
'filters' => $filters
|
||||
];
|
||||
}
|
||||
|
||||
public static function getConceptDebtors($accessibleHouseIds = []) {
|
||||
$db = Database::getInstance();
|
||||
$concepts = $db->fetchAll(
|
||||
"SELECT c.id, c.name, c.amount_per_house
|
||||
FROM finance_collection_concepts c
|
||||
WHERE c.is_active = 1
|
||||
ORDER BY c.created_at DESC"
|
||||
);
|
||||
|
||||
$debtors = [];
|
||||
$grandTotal = 0;
|
||||
|
||||
foreach ($concepts as $concept) {
|
||||
$sql = "SELECT h.id, h.number, h.owner_name, h.status
|
||||
FROM houses h
|
||||
WHERE h.status = 'activa'";
|
||||
|
||||
$params = [];
|
||||
|
||||
if (!empty($accessibleHouseIds) && !Auth::isAdmin()) {
|
||||
$placeholders = str_repeat('?,', count($accessibleHouseIds) - 1) . '?';
|
||||
$sql .= " AND h.id IN ($placeholders)";
|
||||
$params = $accessibleHouseIds;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY CAST(h.number AS UNSIGNED)";
|
||||
|
||||
$houses = $db->fetchAll($sql, $params);
|
||||
|
||||
$houseDebtors = [];
|
||||
$totalCollected = 0;
|
||||
$totalExpected = $concept['amount_per_house'] * count($houses);
|
||||
|
||||
foreach ($houses as $house) {
|
||||
$payment = $db->fetchOne(
|
||||
"SELECT amount FROM finance_collection_payments
|
||||
WHERE concept_id = ? AND house_id = ?",
|
||||
[$concept['id'], $house['id']]
|
||||
);
|
||||
$paid = $payment['amount'] ?? 0;
|
||||
|
||||
if ($paid < $concept['amount_per_house']) {
|
||||
$due = $concept['amount_per_house'] - $paid;
|
||||
if ($due > 0) {
|
||||
$houseDebtors[] = [
|
||||
'house_id' => $house['id'],
|
||||
'house_number' => $house['number'],
|
||||
'owner_name' => $house['owner_name'],
|
||||
'expected' => $concept['amount_per_house'],
|
||||
'paid' => $paid,
|
||||
'due' => $due
|
||||
];
|
||||
}
|
||||
}
|
||||
$totalCollected += $paid;
|
||||
}
|
||||
|
||||
$conceptTotalDue = $totalExpected - $totalCollected;
|
||||
|
||||
if ($conceptTotalDue > 0) {
|
||||
$debtors[] = [
|
||||
'concept_id' => $concept['id'],
|
||||
'concept_name' => $concept['name'],
|
||||
'amount_per_house' => $concept['amount_per_house'],
|
||||
'total_expected' => $totalExpected,
|
||||
'total_collected' => $totalCollected,
|
||||
'total_due' => $conceptTotalDue,
|
||||
'house_debtors' => $houseDebtors
|
||||
];
|
||||
$grandTotal += $conceptTotalDue;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'debtors' => $debtors,
|
||||
'total_due' => $grandTotal
|
||||
];
|
||||
}
|
||||
}
|
||||
113
models/User.php
Executable file
113
models/User.php
Executable file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
class User {
|
||||
public static function findByUsername($username) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM users WHERE username = ? AND is_active = 1",
|
||||
[$username]
|
||||
);
|
||||
}
|
||||
|
||||
public static function findById($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchOne(
|
||||
"SELECT * FROM users WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function all() {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT id, username, email, first_name, last_name, role, is_active, last_login, created_at
|
||||
FROM users ORDER BY id"
|
||||
);
|
||||
}
|
||||
|
||||
public static function create($data) {
|
||||
$db = Database::getInstance();
|
||||
$db->execute(
|
||||
"INSERT INTO users (username, email, password, first_name, last_name, role)
|
||||
VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[
|
||||
$data['username'],
|
||||
$data['email'],
|
||||
password_hash($data['password'], PASSWORD_DEFAULT),
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
$data['role']
|
||||
]
|
||||
);
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
|
||||
public static function update($id, $data) {
|
||||
$db = Database::getInstance();
|
||||
$sql = "UPDATE users SET username = ?, email = ?, first_name = ?, last_name = ?, role = ?";
|
||||
$params = [
|
||||
$data['username'],
|
||||
$data['email'],
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
$data['role']
|
||||
];
|
||||
|
||||
if (!empty($data['password'])) {
|
||||
$sql .= ", password = ?";
|
||||
$params[] = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
$sql .= " WHERE id = ?";
|
||||
$params[] = $id;
|
||||
|
||||
// Database::execute() puede devolver el número de filas afectadas o un booleano.
|
||||
// Si devuelve 0 (ninguna fila afectada) PHP lo interpreta como false.
|
||||
// Queremos que sea true si la consulta se ejecuta sin errores.
|
||||
$stmt = $db->execute($sql, $params);
|
||||
return $stmt !== false; // Devuelve true si la ejecución fue exitosa, false si hubo un error.
|
||||
}
|
||||
|
||||
public static function delete($id) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute(
|
||||
"UPDATE users SET is_active = 0 WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
}
|
||||
|
||||
public static function updateProfile($id, $data) {
|
||||
$db = Database::getInstance();
|
||||
$stmt = $db->execute(
|
||||
"UPDATE users SET email = ?, first_name = ?, last_name = ? WHERE id = ?",
|
||||
[
|
||||
$data['email'],
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
$id
|
||||
]
|
||||
);
|
||||
return $stmt !== false; // Devuelve true si la ejecución fue exitosa, false si hubo un error.
|
||||
}
|
||||
|
||||
public static function changePassword($id, $newPassword) {
|
||||
$db = Database::getInstance();
|
||||
$stmt = $db->execute(
|
||||
"UPDATE users SET password = ? WHERE id = ?",
|
||||
[
|
||||
password_hash($newPassword, PASSWORD_DEFAULT),
|
||||
$id
|
||||
]
|
||||
);
|
||||
return $stmt !== false; // Devuelve true si la ejecución fue exitosa, false si hubo un error.
|
||||
}
|
||||
|
||||
public static function verifyPassword($id, $password) {
|
||||
$db = Database::getInstance();
|
||||
$user = $db->fetchOne(
|
||||
"SELECT password FROM users WHERE id = ?",
|
||||
[$id]
|
||||
);
|
||||
return $user && password_verify($password, $user['password']);
|
||||
}
|
||||
}
|
||||
42
models/UserPermission.php
Executable file
42
models/UserPermission.php
Executable file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class UserPermission {
|
||||
public static function getUserHouses($userId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->fetchAll(
|
||||
"SELECT h.* FROM houses h
|
||||
INNER JOIN user_house_permissions uhp ON h.id = uhp.house_id
|
||||
WHERE uhp.user_id = ? ORDER BY CAST(h.number AS UNSIGNED)",
|
||||
[$userId]
|
||||
);
|
||||
}
|
||||
|
||||
public static function getUserHouseIds($userId) {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchAll(
|
||||
"SELECT house_id FROM user_house_permissions WHERE user_id = ?",
|
||||
[$userId]
|
||||
);
|
||||
return array_column($result, 'house_id');
|
||||
}
|
||||
|
||||
public static function assignHousesToUser($userId, $houseIds) {
|
||||
$db = Database::getInstance();
|
||||
$db->execute("DELETE FROM user_house_permissions WHERE user_id = ?", [$userId]);
|
||||
|
||||
foreach ($houseIds as $houseId) {
|
||||
$db->execute(
|
||||
"INSERT INTO user_house_permissions (user_id, house_id) VALUES (?, ?)",
|
||||
[$userId, $houseId]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function removeUserFromHouse($userId, $houseId) {
|
||||
$db = Database::getInstance();
|
||||
return $db->execute(
|
||||
"DELETE FROM user_house_permissions WHERE user_id = ? AND house_id = ?",
|
||||
[$userId, $houseId]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user