payfrit-api/api/menu/menus.php
John Mizerek 1f81d98c52 Initial PHP API migration from CFML
Complete port of all 163 API endpoints from Lucee/CFML to PHP 8.3.
Shared helpers in api/helpers.php (DB, auth, request/response, security).
PDO prepared statements throughout. Same JSON response shapes as CFML.
2026-03-14 14:26:59 -07:00

181 lines
7.2 KiB
PHP

<?php
require_once __DIR__ . '/../helpers.php';
runAuth();
/**
* Menu CRUD API
*
* Actions: list, get, save, delete, reorder, setDefault
* POST body: { "BusinessID": 37, "action": "list", ... }
*/
$data = readJsonBody();
$businessID = (int) ($data['BusinessID'] ?? 0);
if ($businessID === 0) {
apiAbort(['OK' => false, 'ERROR' => 'missing_business_id', 'MESSAGE' => 'BusinessID is required']);
}
$action = strtolower($data['action'] ?? 'list');
try {
switch ($action) {
case 'list':
$qMenus = queryTimed("
SELECT ID, Name, Description, DaysActive, StartTime, EndTime, SortOrder, IsActive
FROM Menus
WHERE BusinessID = ? AND IsActive = 1
ORDER BY SortOrder, Name
", [$businessID]);
$menus = [];
foreach ($qMenus as $m) {
$catCount = queryOne("
SELECT COUNT(*) as cnt FROM Categories
WHERE BusinessID = ? AND MenuID = ?
", [$businessID, $m['ID']]);
$menus[] = [
'MenuID' => (int) $m['ID'],
'Name' => $m['Name'],
'Description' => $m['Description'] ?? '',
'DaysActive' => (int) $m['DaysActive'],
'StartTime' => !empty($m['StartTime']) ? (new DateTime($m['StartTime']))->format('H:i') : '',
'EndTime' => !empty($m['EndTime']) ? (new DateTime($m['EndTime']))->format('H:i') : '',
'SortOrder' => (int) $m['SortOrder'],
'CategoryCount' => (int) $catCount['cnt'],
];
}
jsonResponse(['OK' => true, 'MENUS' => $menus, 'COUNT' => count($menus)]);
case 'get':
$menuID = (int) ($data['MenuID'] ?? 0);
if ($menuID === 0) {
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_id', 'MESSAGE' => 'MenuID is required']);
}
$menu = queryOne("SELECT * FROM Menus WHERE ID = ? AND BusinessID = ?", [$menuID, $businessID]);
if (!$menu) {
apiAbort(['OK' => false, 'ERROR' => 'menu_not_found', 'MESSAGE' => 'Menu not found']);
}
jsonResponse(['OK' => true, 'MENU' => [
'MenuID' => (int) $menu['ID'],
'Name' => $menu['Name'],
'Description' => $menu['Description'] ?? '',
'DaysActive' => (int) $menu['DaysActive'],
'StartTime' => !empty($menu['StartTime']) ? (new DateTime($menu['StartTime']))->format('H:i') : '',
'EndTime' => !empty($menu['EndTime']) ? (new DateTime($menu['EndTime']))->format('H:i') : '',
'SortOrder' => (int) $menu['SortOrder'],
'IsActive' => (int) $menu['IsActive'],
]]);
case 'save':
$menuID = (int) ($data['MenuID'] ?? 0);
$menuName = trim($data['Name'] ?? '');
$menuDescription = trim($data['Description'] ?? '');
$menuDaysActive = (int) ($data['DaysActive'] ?? 127);
$menuStartTime = !empty($data['StartTime']) ? trim($data['StartTime']) : null;
$menuEndTime = !empty($data['EndTime']) ? trim($data['EndTime']) : null;
$menuSortOrder = (int) ($data['SortOrder'] ?? 0);
if ($menuName === '') {
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_name', 'MESSAGE' => 'Menu name is required']);
}
if ($menuID > 0) {
queryTimed("
UPDATE Menus SET
Name = ?, Description = ?, DaysActive = ?,
StartTime = ?, EndTime = ?, SortOrder = ?
WHERE ID = ? AND BusinessID = ?
", [$menuName, $menuDescription, $menuDaysActive, $menuStartTime, $menuEndTime, $menuSortOrder, $menuID, $businessID]);
jsonResponse(['OK' => true, 'MenuID' => $menuID, 'ACTION' => 'updated']);
} else {
queryTimed("
INSERT INTO Menus (
BusinessID, Name, Description,
DaysActive, StartTime, EndTime,
SortOrder, IsActive, AddedOn
) VALUES (?, ?, ?, ?, ?, ?, ?, 1, NOW())
", [$businessID, $menuName, $menuDescription, $menuDaysActive, $menuStartTime, $menuEndTime, $menuSortOrder]);
$newID = (int) lastInsertId();
jsonResponse(['OK' => true, 'MenuID' => $newID, 'ACTION' => 'created']);
}
case 'delete':
$menuID = (int) ($data['MenuID'] ?? 0);
if ($menuID === 0) {
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_id', 'MESSAGE' => 'MenuID is required']);
}
$catCheck = queryOne("
SELECT COUNT(*) as cnt FROM Categories
WHERE MenuID = ? AND BusinessID = ?
", [$menuID, $businessID]);
if ((int) $catCheck['cnt'] > 0) {
queryTimed("
UPDATE Categories SET MenuID = 0
WHERE MenuID = ? AND BusinessID = ?
", [$menuID, $businessID]);
}
queryTimed("
UPDATE Menus SET IsActive = 0
WHERE ID = ? AND BusinessID = ?
", [$menuID, $businessID]);
jsonResponse([
'OK' => true,
'MenuID' => $menuID,
'ACTION' => 'deleted',
'CategoriesUnassigned' => (int) $catCheck['cnt'],
]);
case 'reorder':
$menuOrder = $data['MenuOrder'] ?? [];
if (!is_array($menuOrder) || count($menuOrder) === 0) {
apiAbort(['OK' => false, 'ERROR' => 'missing_menu_order', 'MESSAGE' => 'MenuOrder array is required']);
}
foreach ($menuOrder as $i => $id) {
queryTimed("
UPDATE Menus SET SortOrder = ?
WHERE ID = ? AND BusinessID = ?
", [$i, (int) $id, $businessID]);
}
jsonResponse(['OK' => true, 'ACTION' => 'reordered']);
case 'setdefault':
$menuID = (int) ($data['MenuID'] ?? 0);
if ($menuID > 0) {
$check = queryOne("
SELECT ID FROM Menus WHERE ID = ? AND BusinessID = ? AND IsActive = 1
", [$menuID, $businessID]);
if (!$check) {
apiAbort(['OK' => false, 'ERROR' => 'invalid_menu', 'MESSAGE' => 'Menu not found or not active']);
}
}
queryTimed("
UPDATE Businesses SET DefaultMenuID = ?
WHERE ID = ?
", [$menuID === 0 ? null : $menuID, $businessID]);
jsonResponse(['OK' => true, 'ACTION' => 'defaultSet', 'DefaultMenuID' => $menuID]);
default:
apiAbort(['OK' => false, 'ERROR' => 'invalid_action', 'MESSAGE' => 'Unknown action: ' . $action]);
}
} catch (Exception $e) {
jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage(), 'DETAIL' => '']);
}