prepare( "SELECT id FROM food_courier_assignments WHERE order_id=? AND courier_id=? AND status='offered' ORDER BY offered_at DESC LIMIT 1" ); $assignSt->execute([$orderId, $food_courier_id]); $assignment = $assignSt->fetch(); if (!$assignment) jsonError('No pending offer for this order', 404); if ($response === 'reject') { $food_con->prepare("UPDATE food_courier_assignments SET status='rejected', responded_at=NOW() WHERE id=?") ->execute([$assignment['id']]); // أعد المحاولة على مرشّح آخر — يعيد استخدام نفس منطق ready.php $orderSt = $food_con->prepare("SELECT merchant_id FROM food_orders WHERE id=? AND status='ready'"); $orderSt->execute([$orderId]); if ($order = $orderSt->fetch()) { $merchantSt = $food_con->prepare("SELECT latitude, longitude FROM food_merchants WHERE id=?"); $merchantSt->execute([$order['merchant_id']]); if ($merchant = $merchantSt->fetch()) { $candidates = foodFindNearbyCouriers((float)$merchant['latitude'], (float)$merchant['longitude']); $priorSt = $food_con->prepare("SELECT courier_id FROM food_courier_assignments WHERE order_id=?"); $priorSt->execute([$orderId]); $prior = array_column($priorSt->fetchAll(), 'courier_id'); foreach ($candidates as $candidateId) { if (in_array($candidateId, $prior, true)) continue; foodOfferOrderToCourier($orderId, $candidateId); break; } } } jsonSuccess(['order_id' => $orderId, 'response' => 'rejected']); } // accept — القفل الذرّي يمنع سباق القبول لو انتهت مهلة سابقة وعُرض على اثنين معاً if (!foodLockOrderForCourier($orderId, $food_courier_id)) { $owner = foodOrderLockOwner($orderId); if ($owner !== $food_courier_id) { jsonError('Order was already claimed by another courier', 409); } } // الطلب لم يُسند لأي سائق بعد عند هذه النقطة — لا فحص ملكية هنا، فقط فحص الحالة أدناه $orderSt = $food_con->prepare("SELECT status FROM food_orders WHERE id=? LIMIT 1"); $orderSt->execute([$orderId]); $orderRow = $orderSt->fetch(); if (!$orderRow || $orderRow['status'] !== 'ready') { jsonError('Order is no longer available for assignment', 409); } $food_con->beginTransaction(); try { $food_con->prepare("UPDATE food_orders SET courier_id=? WHERE id=?")->execute([$food_courier_id, $orderId]); $food_con->prepare("UPDATE food_courier_assignments SET status='accepted', responded_at=NOW() WHERE id=?") ->execute([$assignment['id']]); $food_con->commit(); } catch (Throwable $e) { $food_con->rollBack(); appLog('[FOOD][COURIER][offer_respond] ' . $e->getMessage(), 'ERROR'); jsonError('Failed to accept offer', 500); } food_transition_status($orderId, 'courier_assigned', 'courier', $food_courier_id); jsonSuccess(['order_id' => $orderId, 'response' => 'accepted']);