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.
172 lines
5.6 KiB
PHP
172 lines
5.6 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/**
|
|
* Customer initiates a chat with staff
|
|
* POST: { BusinessID, ServicePointID?, OrderID?, UserID?, Message?, ForceNew? }
|
|
*/
|
|
|
|
$data = readJsonBody();
|
|
$businessID = (int) ($data['BusinessID'] ?? 0);
|
|
$servicePointID = (int) ($data['ServicePointID'] ?? 0);
|
|
$orderID = (int) ($data['OrderID'] ?? 0);
|
|
$initialMessage = trim($data['Message'] ?? '');
|
|
$userID = (int) ($data['UserID'] ?? 0);
|
|
|
|
if ($businessID <= 0) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_params', 'MESSAGE' => 'BusinessID is required']);
|
|
}
|
|
|
|
try {
|
|
// If servicePointID not provided but orderID is, look it up
|
|
if ($servicePointID <= 0 && $orderID > 0) {
|
|
$qOrderSP = queryOne("SELECT ServicePointID FROM Orders WHERE ID = ?", [$orderID]);
|
|
if ($qOrderSP && (int) $qOrderSP['ServicePointID'] > 0) {
|
|
$servicePointID = (int) $qOrderSP['ServicePointID'];
|
|
}
|
|
}
|
|
|
|
// Look up "Chat" task type for this business
|
|
$ttQuery = queryOne("
|
|
SELECT ID FROM tt_TaskTypes
|
|
WHERE BusinessID = ? AND Name LIKE '%Chat%'
|
|
LIMIT 1
|
|
", [$businessID]);
|
|
$chatTaskTypeID = $ttQuery ? (int) $ttQuery['ID'] : 0;
|
|
|
|
// Check for existing open chat
|
|
$forceNew = !empty($data['ForceNew']) && $data['ForceNew'] === true;
|
|
|
|
if (!$forceNew) {
|
|
$existingChat = queryOne("
|
|
SELECT t.ID, t.CreatedOn,
|
|
(SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.ID) as LastMessageTime
|
|
FROM Tasks t
|
|
LEFT JOIN ChatMessages cm2 ON cm2.TaskID = t.ID AND cm2.SenderUserID = ?
|
|
WHERE t.BusinessID = ?
|
|
AND (t.TaskTypeID = ? OR t.Title LIKE 'Chat%')
|
|
AND t.CompletedOn IS NULL
|
|
AND (
|
|
(t.OrderID = ? AND ? > 0)
|
|
OR (t.SourceType = 'servicepoint' AND t.SourceID = ? AND ? > 0)
|
|
OR (t.SourceType = 'user' AND t.SourceID = ? AND ? > 0)
|
|
OR (cm2.SenderUserID = ? AND ? > 0)
|
|
)
|
|
ORDER BY t.CreatedOn DESC
|
|
LIMIT 1
|
|
", [
|
|
$userID, $businessID, $chatTaskTypeID,
|
|
$orderID, $orderID,
|
|
$servicePointID, $servicePointID,
|
|
$userID, $userID,
|
|
$userID, $userID,
|
|
]);
|
|
|
|
if ($existingChat) {
|
|
$lastActivity = $existingChat['LastMessageTime'];
|
|
if (empty($lastActivity)) {
|
|
$lastActivity = $existingChat['CreatedOn'];
|
|
}
|
|
$chatAge = (int) ((time() - strtotime($lastActivity)) / 60);
|
|
|
|
if ($chatAge > 30) {
|
|
// Auto-close stale chat
|
|
queryTimed("UPDATE Tasks SET CompletedOn = NOW() WHERE ID = ?", [$existingChat['ID']]);
|
|
} else {
|
|
jsonResponse([
|
|
'OK' => true,
|
|
'TaskID' => (int) $existingChat['ID'],
|
|
'MESSAGE' => 'Rejoined existing chat',
|
|
'EXISTING' => true,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get service point info
|
|
$tableName = '';
|
|
if ($servicePointID > 0) {
|
|
$spQuery = queryOne("SELECT Name FROM ServicePoints WHERE ID = ?", [$servicePointID]);
|
|
$tableName = $spQuery ? $spQuery['Name'] : "Table #$servicePointID";
|
|
}
|
|
|
|
// Get user name
|
|
$userName = '';
|
|
if ($userID > 0) {
|
|
$userQuery = queryOne("SELECT FirstName FROM Users WHERE ID = ?", [$userID]);
|
|
if ($userQuery && !empty(trim($userQuery['FirstName']))) {
|
|
$userName = $userQuery['FirstName'];
|
|
}
|
|
}
|
|
|
|
// Create task title
|
|
if ($servicePointID > 0) {
|
|
$taskTitle = !empty($userName)
|
|
? "Chat - $userName ($tableName)"
|
|
: "Chat - $tableName";
|
|
} else {
|
|
$taskTitle = !empty($userName)
|
|
? "Chat - $userName (Remote)"
|
|
: "Remote Chat";
|
|
}
|
|
|
|
$taskDetails = !empty($initialMessage) ? $initialMessage : 'Customer initiated chat';
|
|
|
|
// Look up or create a "Chat" category
|
|
$catQuery = queryOne("
|
|
SELECT ID FROM TaskCategories
|
|
WHERE BusinessID = ? AND Name = 'Chat'
|
|
LIMIT 1
|
|
", [$businessID]);
|
|
|
|
if (!$catQuery) {
|
|
queryTimed("
|
|
INSERT INTO TaskCategories (BusinessID, Name, Color)
|
|
VALUES (?, 'Chat', '#2196F3')
|
|
", [$businessID]);
|
|
$categoryID = (int) lastInsertId();
|
|
} else {
|
|
$categoryID = (int) $catQuery['ID'];
|
|
}
|
|
|
|
// Determine source type and ID
|
|
$sourceType = $servicePointID > 0 ? 'servicepoint' : 'user';
|
|
$sourceID = $servicePointID > 0 ? $servicePointID : $userID;
|
|
|
|
// Insert task
|
|
queryTimed("
|
|
INSERT INTO Tasks (
|
|
BusinessID, CategoryID, OrderID, TaskTypeID,
|
|
Title, Details, ClaimedByUserID, SourceType, SourceID, CreatedOn
|
|
) VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, NOW())
|
|
", [
|
|
$businessID,
|
|
$categoryID,
|
|
$orderID > 0 ? $orderID : null,
|
|
$chatTaskTypeID > 0 ? $chatTaskTypeID : null,
|
|
$taskTitle,
|
|
$taskDetails,
|
|
$sourceType,
|
|
$sourceID,
|
|
]);
|
|
|
|
$taskID = (int) lastInsertId();
|
|
|
|
// If there's an initial message, save it
|
|
if (!empty($initialMessage) && $userID > 0) {
|
|
queryTimed("
|
|
INSERT INTO ChatMessages (TaskID, SenderUserID, SenderType, MessageBody)
|
|
VALUES (?, ?, 'customer', ?)
|
|
", [$taskID, $userID, $initialMessage]);
|
|
}
|
|
|
|
jsonResponse([
|
|
'OK' => true,
|
|
'TaskID' => $taskID,
|
|
'MESSAGE' => 'Chat started',
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage()]);
|
|
}
|