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.
186 lines
6.3 KiB
PHP
186 lines
6.3 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/**
|
|
* Get Order Detail
|
|
* GET: ?OrderID=123
|
|
* POST: { OrderID: 123 }
|
|
*/
|
|
|
|
function getStatusText(int $status): string {
|
|
return match ($status) {
|
|
0 => 'Cart', 1 => 'Submitted', 2 => 'In Progress', 3 => 'Ready',
|
|
4 => 'On the Way', 5 => 'Complete', 6 => 'Cancelled', 7 => 'Deleted',
|
|
default => 'Unknown',
|
|
};
|
|
}
|
|
|
|
function getOrderTypeName(int $orderType): string {
|
|
return match ($orderType) {
|
|
1 => 'Dine-in', 2 => 'Takeaway', 3 => 'Delivery', default => 'Unknown',
|
|
};
|
|
}
|
|
|
|
$response = ['OK' => false];
|
|
|
|
try {
|
|
// Get OrderID from GET or POST
|
|
$orderID = (int) ($_GET['OrderID'] ?? 0);
|
|
if ($orderID === 0) {
|
|
$data = readJsonBody();
|
|
$orderID = (int) ($data['OrderID'] ?? 0);
|
|
}
|
|
|
|
if ($orderID === 0) {
|
|
$response['ERROR'] = 'missing_order_id';
|
|
$response['MESSAGE'] = 'OrderID is required';
|
|
jsonResponse($response);
|
|
}
|
|
|
|
$qOrder = queryOne("
|
|
SELECT
|
|
o.ID, o.UUID, o.BusinessID, o.UserID, o.ServicePointID,
|
|
o.StatusID, o.OrderTypeID, o.Remarks, o.AddedOn, o.LastEditedOn,
|
|
o.SubmittedOn, o.TipAmount,
|
|
u.FirstName, u.LastName, u.ContactNumber, u.EmailAddress,
|
|
sp.Name AS Name, sp.TypeID AS TypeID,
|
|
b.Name AS BizName, b.TaxRate
|
|
FROM Orders o
|
|
LEFT JOIN Users u ON u.ID = o.UserID
|
|
LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID
|
|
LEFT JOIN Businesses b ON b.ID = o.BusinessID
|
|
WHERE o.ID = ?
|
|
", [$orderID]);
|
|
|
|
if (!$qOrder) {
|
|
$response['ERROR'] = 'order_not_found';
|
|
$response['MESSAGE'] = 'Order not found';
|
|
jsonResponse($response);
|
|
}
|
|
|
|
// Get line items
|
|
$qItems = queryTimed("
|
|
SELECT
|
|
oli.ID, oli.ItemID, oli.ParentOrderLineItemID,
|
|
oli.Quantity, oli.Price, oli.Remark,
|
|
i.Name, i.Price AS ItemPrice, i.IsCheckedByDefault
|
|
FROM OrderLineItems oli
|
|
INNER JOIN Items i ON i.ID = oli.ItemID
|
|
WHERE oli.OrderID = ? AND oli.IsDeleted = 0
|
|
ORDER BY oli.ID
|
|
", [$orderID]);
|
|
|
|
// Build hierarchy
|
|
$itemsById = [];
|
|
foreach ($qItems as $row) {
|
|
$itemsById[(int) $row['ID']] = [
|
|
'LineItemID' => (int) $row['ID'],
|
|
'ItemID' => (int) $row['ItemID'],
|
|
'ParentLineItemID' => (int) $row['ParentOrderLineItemID'],
|
|
'Name' => $row['Name'] ?? '',
|
|
'Quantity' => (int) $row['Quantity'],
|
|
'UnitPrice' => (float) $row['Price'],
|
|
'Remarks' => $row['Remark'] ?? '',
|
|
'IsDefault' => ((int) $row['IsCheckedByDefault'] === 1),
|
|
'Modifiers' => [],
|
|
];
|
|
}
|
|
|
|
$lineItems = [];
|
|
foreach ($qItems as $row) {
|
|
$id = (int) $row['ID'];
|
|
$parentID = (int) $row['ParentOrderLineItemID'];
|
|
if ($parentID > 0 && isset($itemsById[$parentID])) {
|
|
$itemsById[$parentID]['Modifiers'][] = &$itemsById[$id];
|
|
} else {
|
|
$lineItems[] = &$itemsById[$id];
|
|
}
|
|
}
|
|
unset($id); // break reference
|
|
|
|
// Calculate subtotal
|
|
$subtotal = 0;
|
|
foreach ($lineItems as $item) {
|
|
$itemTotal = $item['UnitPrice'] * $item['Quantity'];
|
|
foreach ($item['Modifiers'] as $mod) {
|
|
$itemTotal += $mod['UnitPrice'] * $mod['Quantity'];
|
|
}
|
|
$subtotal += $itemTotal;
|
|
}
|
|
|
|
$taxRate = (is_numeric($qOrder['TaxRate']) && (float) $qOrder['TaxRate'] > 0) ? (float) $qOrder['TaxRate'] : 0;
|
|
$tax = $subtotal * $taxRate;
|
|
$tip = is_numeric($qOrder['TipAmount']) ? (float) $qOrder['TipAmount'] : 0;
|
|
$total = $subtotal + $tax + $tip;
|
|
|
|
// Get staff who worked on this order
|
|
$qStaff = queryTimed("
|
|
SELECT DISTINCT u.ID, u.FirstName,
|
|
(SELECT r.AccessToken
|
|
FROM TaskRatings r
|
|
INNER JOIN Tasks t2 ON t2.ID = r.TaskID
|
|
WHERE t2.OrderID = ?
|
|
AND r.ForUserID = u.ID
|
|
AND r.Direction = 'customer_rates_worker'
|
|
AND r.CompletedOn IS NULL
|
|
AND r.ExpiresOn > NOW()
|
|
LIMIT 1) AS RatingToken
|
|
FROM Tasks t
|
|
INNER JOIN Users u ON u.ID = t.ClaimedByUserID
|
|
WHERE t.OrderID = ? AND t.ClaimedByUserID > 0
|
|
", [$orderID, $orderID]);
|
|
|
|
$staff = [];
|
|
foreach ($qStaff as $row) {
|
|
$staff[] = [
|
|
'UserID' => (int) $row['ID'],
|
|
'FirstName' => $row['FirstName'],
|
|
'AvatarUrl' => baseUrl() . '/uploads/users/' . $row['ID'] . '.jpg',
|
|
'RatingToken' => $row['RatingToken'] ?? '',
|
|
];
|
|
}
|
|
|
|
$statusID = (int) $qOrder['StatusID'];
|
|
$orderTypeID = (int) ($qOrder['OrderTypeID'] ?? 0);
|
|
|
|
$response['OK'] = true;
|
|
$response['ORDER'] = [
|
|
'OrderID' => (int) $qOrder['ID'],
|
|
'UUID' => $qOrder['UUID'] ?? '',
|
|
'BusinessID' => (int) $qOrder['BusinessID'],
|
|
'Name' => $qOrder['BizName'] ?? '',
|
|
'Status' => $statusID,
|
|
'StatusText' => getStatusText($statusID),
|
|
'OrderTypeID' => $orderTypeID,
|
|
'OrderTypeName' => getOrderTypeName($orderTypeID),
|
|
'Subtotal' => $subtotal,
|
|
'Tax' => $tax,
|
|
'Tip' => $tip,
|
|
'Total' => $total,
|
|
'Notes' => $qOrder['Remarks'],
|
|
'CreatedOn' => toISO8601($qOrder['AddedOn']),
|
|
'SubmittedOn' => !empty($qOrder['SubmittedOn']) ? toISO8601($qOrder['SubmittedOn']) : '',
|
|
'UpdatedOn' => !empty($qOrder['LastEditedOn']) ? toISO8601($qOrder['LastEditedOn']) : '',
|
|
'Customer' => [
|
|
'UserID' => (int) $qOrder['UserID'],
|
|
'FirstName' => $qOrder['FirstName'],
|
|
'LastName' => $qOrder['LastName'],
|
|
'Phone' => $qOrder['ContactNumber'],
|
|
'Email' => $qOrder['EmailAddress'],
|
|
],
|
|
'ServicePoint' => [
|
|
'ServicePointID' => (int) ($qOrder['ServicePointID'] ?? 0),
|
|
'Name' => $qOrder['Name'] ?? '',
|
|
'TypeID' => (int) ($qOrder['TypeID'] ?? 0),
|
|
],
|
|
'LineItems' => $lineItems,
|
|
'Staff' => $staff,
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$response['ERROR'] = 'server_error';
|
|
$response['MESSAGE'] = $e->getMessage();
|
|
}
|
|
|
|
jsonResponse($response);
|