AlexWinder's avatar

PayPal Smart Checkout - return_url/cancel_url just closes window with no redirect

I am currently writing an application in Laravel which has the PayPal smart checkout button is making use of the PayPal PHP SDK (https://github.com/paypal/PayPal-PHP-SDK).

So far everything is working fine, however I am having some trouble with the return_url and cancel_url which is in the 'application_context' array. I can set the cancel_url and if I hover my cursor over the "Cancel and return to brand name" link I can see that it is being correctly set the cancel_url I have set, however if I click on this link all that happens is the pop-up window closes and returns to my checkout page. It doesn't actually go to the URL.

I have also set the return_url however I have not yet found if this working at all - however processing my order does work correctly but upon completing the order the PayPal window just closes and returns to the previous page.

Some example of my code which I'm using:

Front-end:

paypal.Buttons({
        createOrder: function() {
            return fetch('{{ route('api.paypal.set-up-transaction') }}', {
                method: 'post',
                headers: {
                    'content-type': 'application/json'
                }
            }).then(function(res) {
                return res.json();
            }).then(function(data) {
                return data.result.id;
            });
        },
        onApprove: function(data, actions) {
            return actions.order.capture().then(function(details) {
                return fetch('{{ route('api.paypal.verify-transaction') }}', {
                    method: 'post',
                    headers: {
                        'content-type': 'application/json'
                    },
                    body: JSON.stringify({
                        orderID: data.orderID
                    })
                });
            });
        }
    }).render('#paypal-button-container');

Back-end (where the logic of route('api.paypal.set-up-transaction') is):

use App\Order;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Response;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Orders\OrdersGetRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use Illuminate\Support\Facades\Cookie;        

        // Get a users order from their cookie
        $order_details = Order::findOrFail(Cookie::get('order_id'));

        $order = new OrdersCreateRequest();
        $order->prefer('return=representation');

        $order->body = [
            'intent' => 'CAPTURE',
            'application_context' => [ 
                'brand_name' => config('app.name'),
                'locale' => 'en-GB',
                'landing_page' => 'BILLING',
                'shipping_preferences' => 'SET_PROVIDED_ADDRESS',
                'user_action' => 'PAY_NOW',
                'return_url' => '<a href="https://example.com/return" target="_blank">https://example.com/return</a>', //  TODO - This should be set   
                'cancel_url' => route('order-payment.create', ['payment' => 'cancelled']), 
            ],
            'purchase_units' => [
                [
                    'reference_id' => 'PUHF', // TODO set these
                    'description' => 'Sporting Goods', // TODO set these
                    'custom_id' => 'CUST-HighFashions', // TODO set these
                    'soft_descriptor' => 'HighFashions', // TODO set these
                    'amount' => [
                        'currency_code' => 'GBP',
                        'value' => strval($order_details->total_price),
                        'breakdown' => [
                            'item_total' => [
                                'currency_code' => 'GBP',
                                'value' => strval($order_details->sub_total_price),
                            ],
                            'shipping' => [
                                'currency_code' => 'GBP',
                                'value' => strval($order_details->shipping_price),
                            ],
                        ],
                    ],
                    'shipping' => [
                        'address' => [
                            'address_line_1' => $order_details->address_line_1,
                            'address_line_2' => $order_details->address_line_2,
                            'admin_area_2' => $order_details->address_city,
                            'admin_area_1' => $order_details->address_county,
                            'postal_code' => $order_details->address_post_code,
                            'country_code' => 'GB',
                        ],
                    ],
                ],
            ],
        ];

        foreach($order_details->items as $item)
        {
            if($item->product_attribute_name && $item->product_attribute_value_name) 
            {
                $description =  $item->product_attribute_name . ': ' . $item->product_attribute_value_name;
            } else {
                $description = $item->product_name;
            }

            // Add details of the items being purchased to the PayPal request
            $order->body['purchase_units'][0]['items'][] = [
                'name' => $item->product_name,
                'description' => $description,
                'sku' => $item->sku_code,
                'unit_amount' => [
                    'currency_code' => 'GBP',
                    'value' => $item->product_price,
                ],
                'quantity' => $item->quantity,
                'category' => 'PHYSICAL_GOODS',
            ];
        };

        $client = self::httpClient();
        $response = $client->execute($order);

        return Response::json($response);

Back-end (where the logic of route('api.paypal.verify-transaction') is):

$client = self::httpClient();

        $response = $client->execute(new OrdersGetRequest($request->orderID));

        /**
         *Enable the following line to print complete response as JSON.
        */
        //print json_encode($response->result);
        print "Verify Transaction Called\n";
        print "Status Code: {$response->statusCode}\n";
        print "Status: {$response->result->status}\n";
        print "Order ID: {$response->result->id}\n";
        print "Intent: {$response->result->intent}\n";
        print "Links:\n";
        foreach($response->result->links as $link)
        {
            print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
        }
        // 4. Save the transaction in your database. Implement logic to save transaction to your database for future reference.
        print "Gross Amount: {$response->result->purchase_units[0]->amount->currency_code} {$response->result->purchase_units[0]->amount->value}\n";

        // Get a users order from their cookie
        $order_details = Order::findOrFail(Cookie::get('order_id'));

        // Set the order details and update the status
        $order_details->statusPaymentReceived();
        $order_details->payment_gateway = 'PayPal';
        $order_details->payment_gateway_reference = $response->result->id;
        $order_details->total_paid_gross = $response->result->purchase_units[0]->amount->value;
        $order_details->save();

All self::httpClient() does is create a connection to PayPal depending on whether it should use Sandbox or Production.

Is there any way to capture the return_url/cancel_url when the PayPal button closes? Or is there any way I can tell PayPal to redirect to my chosen URL?

Any advice would be greatly appreciated, I'm tearing my hair out over this and PayPal's documentation are far from user friendly!

Thanks, Alex

0 likes
0 replies

Please or to participate in this conversation.