restaurant_id); if (!$gateway->enabled) return null; $exchange = floatval(str_replace(',', '.', $gateway->currency_exchange)); if (!$exchange || $exchange == 0) { $exchange = 1.0; } return [ 'id' => 'upayments', 'title' => $gateway->title, 'description' => $gateway->description, 'currency' => $gateway->currency, 'exchange' => $exchange, 'can_capture_card' => \Alexr\Payments\GatewayUpayments::$hasCaptureCards ]; } public function upayments_create() { $restaurant_id = intval($_REQUEST['restaurantId']); $booking_id = intval($_REQUEST['booking_id']); $nonce = $_REQUEST['nonce']; // Desde la view booking no se necesita el nonce if ($nonce != 'not_needed') { if ( ! $this->verify_nonce($restaurant_id) && ! $this->verify_nonce('stripe-'.$restaurant_id) ) { wp_send_json_error(['error' => __eva('Invalid nonce. Try to refresh the page.')]); } } if (!defined('ALEXR_PRO_VERSION')) { wp_send_json_error(['error' => __eva('Need the PRO plugin enabled.')]); } $gateway = new \Alexr\Payments\GatewayUpayments($restaurant_id); $amount = floatval($_REQUEST['amount']); $amount = intval( 100.0 * $amount); $currency = sanitize_text_field($_REQUEST['currency']); // Convert amount based on exchange rate $exchange = floatval(str_replace(',', '.', $gateway->currency_exchange)); if (!$exchange || $exchange == 0) { $exchange = 1.0; } $upayments_amount = $amount * $exchange; //ray('upayments_create upayments_amount: ' . $upayments_amount); $booking = \Alexr\Models\Booking::find($booking_id); if (!$booking) { wp_send_json_error(['error' => __eva('Invalid booking')]); } try { // Create charge to get payment link $charge = $gateway->createCharge($booking, $upayments_amount, $gateway->currency); $data = [ 'charge' => $charge, 'type' => 'direct_payment' ]; $payment = $gateway->create_payment($booking_id, $upayments_amount, $data, \Alexr\Enums\PaymentStatus::PENDING); // Get payment URL from response // UPayments returns different field names depending on the response $payment_url = $charge['data']['link'] ?? $charge['data']['url'] ?? $charge['data']['paymentURL'] ?? $charge['data']['payment_url'] ?? null; if (!$payment_url) { throw new \Exception('Payment URL not found in UPayments response'); } wp_send_json_success([ 'payment_url' => $payment_url, 'payment_id' => $payment->id, 'order_id' => $charge['order']['id'] ?? null, 'reference_id' => $charge['reference']['id'] ?? null ]); } catch (\Exception $e) { wp_send_json_error(['error' => $e->getMessage()]); } } public function upayments_webhook() { $raw_input = file_get_contents('php://input'); $payload = json_decode($raw_input, true); if (!$payload) { http_response_code(400); exit('Invalid payload'); } error_log('UPayments webhook received: ' . print_r($payload, true)); // Get order_id or reference_id from payload $order_id = $payload['order_id'] ?? $payload['requested_order_id'] ?? ''; $reference_id = $payload['ref'] ?? $payload['reference_id'] ?? ''; $payment_id = $payload['payment_id'] ?? ''; // Try to find payment by order_id, reference_id or payment_id $payment = null; if ($order_id) { $payment = \Alexr\Models\Payment::where('payment_type', 'upayments') ->where('upayments_order_id', $order_id) ->first(); } if (!$payment && $reference_id) { $payment = \Alexr\Models\Payment::where('payment_type', 'upayments') ->where('upayments_reference_id', $reference_id) ->first(); } if (!$payment && $payment_id) { $payment = \Alexr\Models\Payment::where('payment_type', 'upayments') ->where('upayments_payment_id', $payment_id) ->first(); } if (!$payment) { error_log('UPayments webhook: Payment not found'); http_response_code(404); exit('Payment not found'); } $booking = \Alexr\Models\Booking::find($payment->booking_id); if (!$booking) { http_response_code(404); exit('Booking not found'); } $gateway = new \Alexr\Payments\GatewayUpayments($booking->restaurant_id); if (!$gateway->validateWebhook($payload)) { http_response_code(401); exit('Invalid signature'); } // Update payment status based on webhook event $result = strtoupper($payload['result'] ?? ''); switch ($result) { case 'CAPTURED': case 'SUCCESS': case 'PAID': if ($payment->status !== \Alexr\Enums\PaymentStatus::SUCCEEDED) { $payment->status = \Alexr\Enums\PaymentStatus::SUCCEEDED; $payment->upayments_status = $result; $payment->upayments_payment_id = $payment_id; $booking->status = $booking->paymentStatus; $booking->save(); $booking->sendBookingEmail(); $booking->sendSmsNotification(); $booking->sendWhatsappNotification(); } break; case 'FAILED': case 'FAILURE': $payment->status = \Alexr\Enums\PaymentStatus::FAILED; $payment->upayments_status = $result; break; case 'CANCELLED': case 'CANCELED': case 'EXPIRED': $payment->status = \Alexr\Enums\PaymentStatus::CANCELLED; $payment->upayments_status = $result; break; } $payment->settings = array_merge($payment->settings ?? [], ['webhook' => $payload]); $payment->save(); http_response_code(200); exit('OK'); } public function upayments_fetch() { $uuid = sanitize_text_field($_REQUEST['uuid']); $booking = \Alexr\Models\Booking::where('uuid', $uuid)->first(); if (!$booking) { wp_send_json_error(['error' => __eva('Invalid booking.')]); } $data = $this->getUPaymentsPaymentArgs($booking); $data['amount'] = intval($booking->amount) / 100.0; wp_send_json_success(['payment' => $data]); } }