483 lines
23 KiB
PHP
483 lines
23 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../db/config.php';
|
|
header('Content-Type: application/json');
|
|
|
|
$action = $_GET['action'] ?? '';
|
|
$pdo = db();
|
|
|
|
try {
|
|
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
|
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
switch ($action) {
|
|
case 'get_stock':
|
|
// List all drugs with total stock quantity
|
|
$sql = "SELECT d.id, d.name_en, d.name_ar, d.min_stock_level, d.reorder_level, d.unit,
|
|
COALESCE(SUM(b.quantity), 0) as total_stock
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
GROUP BY d.id
|
|
ORDER BY d.name_en ASC";
|
|
$stmt = $pdo->query($sql);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'get_low_stock':
|
|
// Count total for pagination
|
|
$countSql = "SELECT COUNT(*) FROM (
|
|
SELECT d.id
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
GROUP BY d.id
|
|
HAVING COALESCE(SUM(b.quantity), 0) <= MAX(d.reorder_level)
|
|
) as total";
|
|
$total = $pdo->query($countSql)->fetchColumn();
|
|
|
|
// List drugs where total stock is <= reorder_level
|
|
$sql = "SELECT d.id, d.name_en, d.name_ar, d.min_stock_level, d.reorder_level, d.unit,
|
|
COALESCE(SUM(b.quantity), 0) as total_stock
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
GROUP BY d.id
|
|
HAVING total_stock <= MAX(d.reorder_level)
|
|
ORDER BY total_stock ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
]);
|
|
break;
|
|
|
|
case 'get_expired':
|
|
// Count total
|
|
$countSql = "SELECT COUNT(*)
|
|
FROM pharmacy_batches b
|
|
JOIN drugs d ON b.drug_id = d.id
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.expiry_date < CURDATE() AND b.quantity > 0";
|
|
$total = $pdo->query($countSql)->fetchColumn();
|
|
|
|
// List batches that have expired and still have quantity
|
|
$sql = "SELECT b.id, b.batch_number, b.expiry_date, b.quantity,
|
|
d.name_en as drug_name, d.name_ar as drug_name_ar,
|
|
s.name_en as supplier_name
|
|
FROM pharmacy_batches b
|
|
JOIN drugs d ON b.drug_id = d.id
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.expiry_date < CURDATE() AND b.quantity > 0
|
|
ORDER BY b.expiry_date ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
]);
|
|
break;
|
|
|
|
case 'get_near_expiry':
|
|
$days = $_GET['days'] ?? 90;
|
|
|
|
// Count total
|
|
$countSql = "SELECT COUNT(*)
|
|
FROM pharmacy_batches b
|
|
JOIN drugs d ON b.drug_id = d.id
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.expiry_date >= CURDATE()
|
|
AND b.expiry_date <= DATE_ADD(CURDATE(), INTERVAL ? DAY)
|
|
AND b.quantity > 0";
|
|
$countStmt = $pdo->prepare($countSql);
|
|
$countStmt->execute([$days]);
|
|
$total = $countStmt->fetchColumn();
|
|
|
|
// List batches expiring in the next X days
|
|
$sql = "SELECT b.id, b.batch_number, b.expiry_date, b.quantity,
|
|
d.name_en as drug_name, d.name_ar as drug_name_ar,
|
|
s.name_en as supplier_name,
|
|
DATEDIFF(b.expiry_date, CURDATE()) as days_remaining
|
|
FROM pharmacy_batches b
|
|
JOIN drugs d ON b.drug_id = d.id
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.expiry_date >= CURDATE()
|
|
AND b.expiry_date <= DATE_ADD(CURDATE(), INTERVAL :days DAY)
|
|
AND b.quantity > 0
|
|
ORDER BY b.expiry_date ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':days', $days, PDO::PARAM_INT);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
]);
|
|
break;
|
|
|
|
case 'get_batches':
|
|
$drug_id = $_GET['drug_id'] ?? 0;
|
|
if (!$drug_id) throw new Exception("Drug ID required");
|
|
|
|
$sql = "SELECT b.*, s.name_en as supplier_name
|
|
FROM pharmacy_batches b
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.drug_id = ? AND b.quantity > 0
|
|
ORDER BY b.expiry_date ASC";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$drug_id]);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'add_stock':
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') throw new Exception("Invalid method");
|
|
|
|
$drug_id = $_POST['drug_id'] ?? 0;
|
|
$batch_number = $_POST['batch_number'] ?? '';
|
|
$expiry_date = $_POST['expiry_date'] ?? '';
|
|
$quantity = $_POST['quantity'] ?? 0;
|
|
$cost_price = $_POST['cost_price'] ?? 0;
|
|
$sale_price = $_POST['sale_price'] ?? 0;
|
|
$supplier_id = !empty($_POST['supplier_id']) ? $_POST['supplier_id'] : null;
|
|
|
|
if (!$drug_id || !$batch_number || !$expiry_date || !$quantity) {
|
|
throw new Exception("Missing required fields");
|
|
}
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO pharmacy_batches
|
|
(drug_id, batch_number, expiry_date, quantity, cost_price, sale_price, supplier_id, received_date)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, CURDATE())");
|
|
$stmt->execute([$drug_id, $batch_number, $expiry_date, $quantity, $cost_price, $sale_price, $supplier_id]);
|
|
|
|
echo json_encode(['success' => true, 'message' => 'Stock added successfully']);
|
|
break;
|
|
|
|
case 'search_drugs':
|
|
$q = $_GET['q'] ?? '';
|
|
$sql = "SELECT d.id, d.name_en, d.name_ar, d.sku, d.price as default_price,
|
|
(SELECT sale_price FROM pharmacy_batches pb WHERE pb.drug_id = d.id AND pb.quantity > 0 AND pb.expiry_date >= CURDATE() ORDER BY pb.expiry_date ASC LIMIT 1) as batch_price,
|
|
COALESCE(SUM(b.quantity), 0) as stock
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
WHERE (d.name_en LIKE ? OR d.name_ar LIKE ? OR d.sku LIKE ?)
|
|
GROUP BY d.id
|
|
LIMIT 20";
|
|
$stmt = $pdo->prepare($sql);
|
|
$term = "%$q%";
|
|
$stmt->execute([$term, $term, $term]);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'create_sale':
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') throw new Exception("Invalid method");
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
|
|
if (empty($input['items'])) throw new Exception("No items in sale");
|
|
|
|
// Check Settings
|
|
$allow_negative = false;
|
|
try {
|
|
$settingStmt = $pdo->prepare("SELECT setting_value FROM settings WHERE setting_key = 'allow_negative_stock'");
|
|
$settingStmt->execute();
|
|
$allow_negative = (bool)$settingStmt->fetchColumn();
|
|
} catch (Exception $e) { /* ignore */ }
|
|
|
|
$pdo->beginTransaction();
|
|
|
|
try {
|
|
// Create Sale Record
|
|
$stmt = $pdo->prepare("INSERT INTO pharmacy_sales (patient_id, visit_id, total_amount, payment_method, status) VALUES (?, ?, ?, ?, 'completed')");
|
|
$stmt->execute([
|
|
$input['patient_id'] ?? null,
|
|
$input['visit_id'] ?? null,
|
|
$input['total_amount'] ?? 0,
|
|
$input['payment_method'] ?? 'cash'
|
|
]);
|
|
$sale_id = $pdo->lastInsertId();
|
|
|
|
// Process Items
|
|
foreach ($input['items'] as $item) {
|
|
$drug_id = $item['drug_id'];
|
|
$qty_needed = $item['quantity'];
|
|
$unit_price = $item['price']; // Or fetch from batch? Use provided price for now.
|
|
|
|
// Fetch available batches (FIFO)
|
|
$batch_stmt = $pdo->prepare("SELECT id, quantity FROM pharmacy_batches WHERE drug_id = ? AND quantity > 0 ORDER BY expiry_date ASC FOR UPDATE");
|
|
$batch_stmt->execute([$drug_id]);
|
|
$batches = $batch_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$qty_remaining = $qty_needed;
|
|
|
|
foreach ($batches as $batch) {
|
|
if ($qty_remaining <= 0) break;
|
|
|
|
$take = min($batch['quantity'], $qty_remaining);
|
|
|
|
// Deduct from batch
|
|
$update = $pdo->prepare("UPDATE pharmacy_batches SET quantity = quantity - ? WHERE id = ?");
|
|
$update->execute([$take, $batch['id']]);
|
|
|
|
// Add to sale items
|
|
$item_stmt = $pdo->prepare("INSERT INTO pharmacy_sale_items (sale_id, drug_id, batch_id, quantity, unit_price, total_price) VALUES (?, ?, ?, ?, ?, ?)");
|
|
$item_stmt->execute([$sale_id, $drug_id, $batch['id'], $take, $unit_price, $take * $unit_price]);
|
|
|
|
$qty_remaining -= $take;
|
|
}
|
|
|
|
if ($qty_remaining > 0) {
|
|
if ($allow_negative) {
|
|
// Record sale for remaining quantity without batch
|
|
$item_stmt = $pdo->prepare("INSERT INTO pharmacy_sale_items (sale_id, drug_id, batch_id, quantity, unit_price, total_price) VALUES (?, ?, ?, ?, ?, ?)");
|
|
$item_stmt->execute([$sale_id, $drug_id, null, $qty_remaining, $unit_price, $qty_remaining * $unit_price]);
|
|
} else {
|
|
throw new Exception("Insufficient stock for drug ID: $drug_id");
|
|
}
|
|
}
|
|
}
|
|
|
|
$pdo->commit();
|
|
echo json_encode(['success' => true, 'sale_id' => $sale_id]);
|
|
|
|
} catch (Exception $e) {
|
|
$pdo->rollBack();
|
|
throw $e;
|
|
}
|
|
break;
|
|
|
|
case 'get_sales':
|
|
// List recent sales
|
|
$sql = "SELECT s.*, p.name as patient_name
|
|
FROM pharmacy_sales s
|
|
LEFT JOIN patients p ON s.patient_id = p.id
|
|
ORDER BY s.created_at DESC LIMIT 50";
|
|
$stmt = $pdo->query($sql);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'get_sale_details':
|
|
$sale_id = $_GET['sale_id'] ?? 0;
|
|
if (!$sale_id) throw new Exception("Sale ID required");
|
|
|
|
$stmt = $pdo->prepare("SELECT s.*, p.name as patient_name FROM pharmacy_sales s LEFT JOIN patients p ON s.patient_id = p.id WHERE s.id = ?");
|
|
$stmt->execute([$sale_id]);
|
|
$sale = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$sale) throw new Exception("Sale not found");
|
|
|
|
$items_stmt = $pdo->prepare("SELECT i.*, d.name_en as drug_name
|
|
FROM pharmacy_sale_items i
|
|
JOIN drugs d ON i.drug_id = d.id
|
|
WHERE i.sale_id = ?");
|
|
$items_stmt->execute([$sale_id]);
|
|
$sale['items'] = $items_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode($sale);
|
|
break;
|
|
|
|
case 'get_report':
|
|
$type = $_GET['type'] ?? 'inventory_valuation';
|
|
$startDate = $_GET['start_date'] ?? date('Y-m-01');
|
|
$endDate = $_GET['end_date'] ?? date('Y-m-d');
|
|
|
|
if ($type === 'inventory_valuation') {
|
|
// Count distinct drugs in stock for pagination
|
|
$countSql = "SELECT COUNT(DISTINCT d.id)
|
|
FROM drugs d
|
|
JOIN pharmacy_batches b ON d.id = b.drug_id
|
|
WHERE b.quantity > 0";
|
|
$total = $pdo->query($countSql)->fetchColumn();
|
|
|
|
$sql = "SELECT d.name_en as drug_name, d.name_ar as drug_name_ar,
|
|
g.name_en as category_name,
|
|
SUM(b.quantity) as stock_quantity,
|
|
SUM(b.quantity * b.cost_price) / SUM(b.quantity) as avg_cost,
|
|
SUM(b.quantity * b.sale_price) / SUM(b.quantity) as selling_price,
|
|
SUM(b.quantity * b.cost_price) as total_cost_value,
|
|
SUM(b.quantity * b.sale_price) as total_sales_value
|
|
FROM drugs d
|
|
JOIN pharmacy_batches b ON d.id = b.drug_id
|
|
LEFT JOIN drugs_groups g ON d.group_id = g.id
|
|
WHERE b.quantity > 0
|
|
GROUP BY d.id
|
|
ORDER BY d.name_en ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
// Calculate Grand Totals (entire stock)
|
|
$grandTotalSql = "SELECT SUM(b.quantity * b.cost_price) as total_cost,
|
|
SUM(b.quantity * b.sale_price) as total_sales
|
|
FROM pharmacy_batches b
|
|
WHERE b.quantity > 0";
|
|
$grandTotals = $pdo->query($grandTotalSql)->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit,
|
|
'grand_total_cost' => $grandTotals['total_cost'] ?? 0,
|
|
'grand_total_sales' => $grandTotals['total_sales'] ?? 0
|
|
]);
|
|
|
|
} elseif ($type === 'sales') {
|
|
// Count
|
|
$countSql = "SELECT COUNT(*) FROM pharmacy_sales WHERE created_at BETWEEN ? AND ? + INTERVAL 1 DAY";
|
|
$countStmt = $pdo->prepare($countSql);
|
|
$countStmt->execute([$startDate, $endDate]);
|
|
$total = $countStmt->fetchColumn();
|
|
|
|
$sql = "SELECT s.id, s.created_at, s.total_amount, s.payment_method,
|
|
p.name as patient_name,
|
|
(SELECT COUNT(*) FROM pharmacy_sale_items i WHERE i.sale_id = s.id) as item_count
|
|
FROM pharmacy_sales s
|
|
LEFT JOIN patients p ON s.patient_id = p.id
|
|
WHERE s.created_at BETWEEN :start AND :end + INTERVAL 1 DAY
|
|
ORDER BY s.created_at DESC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$grandTotalSql = "SELECT SUM(total_amount) as total FROM pharmacy_sales WHERE created_at BETWEEN ? AND ? + INTERVAL 1 DAY";
|
|
$grandTotalStmt = $pdo->prepare($grandTotalSql);
|
|
$grandTotalStmt->execute([$startDate, $endDate]);
|
|
$grandTotal = $grandTotalStmt->fetchColumn();
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':start', $startDate);
|
|
$stmt->bindValue(':end', $endDate);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit,
|
|
'grand_total_sales' => $grandTotal ?? 0
|
|
]);
|
|
|
|
} elseif ($type === 'expiry') {
|
|
$countSql = "SELECT COUNT(*) FROM pharmacy_batches WHERE expiry_date BETWEEN ? AND ? AND quantity > 0";
|
|
$countStmt = $pdo->prepare($countSql);
|
|
$countStmt->execute([$startDate, $endDate]);
|
|
$total = $countStmt->fetchColumn();
|
|
|
|
$sql = "SELECT b.id, b.batch_number, b.expiry_date, b.quantity,
|
|
d.name_en as drug_name, d.name_ar as drug_name_ar,
|
|
s.name_en as supplier_name,
|
|
DATEDIFF(b.expiry_date, CURDATE()) as days_remaining
|
|
FROM pharmacy_batches b
|
|
JOIN drugs d ON b.drug_id = d.id
|
|
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
|
WHERE b.expiry_date BETWEEN :start AND :end AND b.quantity > 0
|
|
ORDER BY b.expiry_date ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':start', $startDate);
|
|
$stmt->bindValue(':end', $endDate);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
]);
|
|
|
|
} elseif ($type === 'purchase_report') {
|
|
$countSql = "SELECT COUNT(*) FROM pharmacy_lpos WHERE lpo_date BETWEEN ? AND ?";
|
|
$countStmt = $pdo->prepare($countSql);
|
|
$countStmt->execute([$startDate, $endDate]);
|
|
$total = $countStmt->fetchColumn();
|
|
|
|
$sql = "SELECT l.id, l.lpo_date, l.status, l.total_amount, s.name_en as supplier_name, s.name_ar as supplier_name_ar
|
|
FROM pharmacy_lpos l
|
|
LEFT JOIN suppliers s ON l.supplier_id = s.id
|
|
WHERE l.lpo_date BETWEEN :start AND :end
|
|
ORDER BY l.lpo_date DESC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$grandTotalSql = "SELECT SUM(total_amount) as total FROM pharmacy_lpos WHERE lpo_date BETWEEN ? AND ?";
|
|
$grandTotalStmt = $pdo->prepare($grandTotalSql);
|
|
$grandTotalStmt->execute([$startDate, $endDate]);
|
|
$grandTotal = $grandTotalStmt->fetchColumn();
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':start', $startDate);
|
|
$stmt->bindValue(':end', $endDate);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit,
|
|
'grand_total_purchases' => $grandTotal ?? 0
|
|
]);
|
|
} elseif ($type === 'low_stock') {
|
|
// Reuse get_low_stock logic
|
|
$countSql = "SELECT COUNT(*) FROM (
|
|
SELECT d.id
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
GROUP BY d.id
|
|
HAVING COALESCE(SUM(b.quantity), 0) <= MAX(d.reorder_level)
|
|
) as total";
|
|
$total = $pdo->query($countSql)->fetchColumn();
|
|
|
|
$sql = "SELECT d.id, d.name_en, d.name_ar, d.min_stock_level, d.reorder_level, d.unit,
|
|
COALESCE(SUM(b.quantity), 0) as total_stock
|
|
FROM drugs d
|
|
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
|
|
GROUP BY d.id
|
|
HAVING total_stock <= MAX(d.reorder_level)
|
|
ORDER BY total_stock ASC
|
|
LIMIT :limit OFFSET :offset";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC),
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new Exception("Invalid action");
|
|
}
|
|
} catch (Exception $e) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => $e->getMessage()]);
|
|
} |