'Method not allowed'], 405); } $input = json_decode(file_get_contents('php://input'), true); $orderId = $input['order_id'] ?? ''; $sourceId = $input['source_id'] ?? ''; if (empty($orderId)) { jsonResponse(['error' => 'Order ID required'], 400); } $order = db()->fetch( "SELECT * FROM orders WHERE order_id = :id", ['id' => $orderId] ); if (!$order) { jsonResponse(['error' => 'Order not found'], 404); } if ($order['payment_status'] === 'paid') { jsonResponse(['error' => 'Order already paid'], 400); } // Demo mode - Square not configured if (!isSquareConfigured()) { db()->update('orders', [ 'payment_status' => 'paid', 'order_status' => 'confirmed', 'square_payment_id' => 'demo_' . bin2hex(random_bytes(8)), 'payment_method' => 'square', ], 'order_id = :id', ['id' => $orderId] ); jsonResponse([ 'demo_mode' => true, 'message' => 'Payment simulated (Square not configured)', 'redirect' => '/order-confirmation.php?order=' . $orderId ]); } if (empty($sourceId)) { jsonResponse(['error' => 'Card details required'], 400); } try { $result = squareCreatePayment( $sourceId, (float) $order['total'], $orderId, ['note' => 'Order #' . $order['order_number']] ); $payment = $result['payment'] ?? []; $status = $payment['status'] ?? ''; if ($status === 'COMPLETED') { markSquarePaymentResult($payment['id'], $orderId, 'COMPLETED'); jsonResponse([ 'success' => true, 'redirect' => '/order-confirmation.php?order=' . $orderId ]); } // Store the payment id even if not yet completed, so the reconciliation // poll and webhook can find this order by square_payment_id. db()->update('orders', ['square_payment_id' => $payment['id'] ?? null], 'order_id = :id', ['id' => $orderId] ); jsonResponse(['error' => 'Payment was not completed (status: ' . $status . ')'], 400); } catch (Exception $e) { error_log('Square payment error: ' . $e->getMessage()); jsonResponse(['error' => 'Payment failed: ' . $e->getMessage()], 500); }