10

I'm trying to implement the API of PayPal payment with Laravel 5.1. But when I log in to PayPal (sandbox), it uses the address I used in my account, and also it uses the name from PayPal account not the data from my website. That's my problem.

I want to use the data from my website because it doesn't make sense if I enter the shipping address (for example) from my website and not using it. Please see my code below for reference (Or comment down below for some details from me).

class PaypalPaymentController extends BaseController
{

    private $_api_context;

    public function __construct(){
        $paypal_conf = \Config::get('paypal');

        $this->_api_context = new ApiContext(new OAuthTokenCredential(
            $paypal_conf['client_id'],
            $paypal_conf['secret']
        ));

        $this->_api_context->setConfig($paypal_conf['settings']);
    }

    public function payWithPaypal(Request $request){
        $payer = new Payer;
        $payer->setPaymentMethod('paypal');

        $price = 0;

        switch($request->get('amount')) {
            case '10 books':
                $price = 6200;
                break;
            case '20 books':
                $price = 12200;
                break;
            case '50 books':
                $price = 25200;
                break;
            default:
                return redirect()
                        ->route('bookstore.shipping')
                        ->with('danger', 'Please select the right amount of book/s.');
                break;
        }

        $item1 = new Item();
        $item1->setName($request->get('amount'))
                ->setCurrency('PHP')
                ->setQuantity(1)
                ->setPrice($price);

        $item_list = new ItemList();
        $item_list->setItems([$item1]);

        $amount = new Amount();
        $amount->setCurrency('PHP')
                ->setTotal($price);

        $transaction = new Transaction();
        $transaction->setAmount($amount)
                    ->setItemList($item_list)
                    ->setDescription('Books transaction');

        $redirect_urls = new RedirectUrls();
        $redirect_urls->setReturnUrl(route('bookstore.payment-status'))
                        ->setCancelUrl(route('bookstore.payment-status'));

        $payment = new Payment();
        $payment->setIntent('Sale')
                ->setPayer($payer)
                ->setRedirectUrls($redirect_urls)
                ->setTransactions([$transaction]);

         $patchReplace = new Patch();
         $patchReplace->setOp('add')
                    ->setPath('/transactions/0/item_list/shipping_address')
                    ->setValue(json_decode('{
                        "line1": "345 Lark Ave",
                        "city": "Montreal",
                        "state": "QC",
                        "postal_code": "H1A4K2",
                        "country_code": "CA"
                    }'));

         $patchRequest = (new PatchRequest())->setPatches([$patchReplace]);


        try{

            $payment->create($this->_api_context);
            $payment->update($patchRequest, $this->_api_context);

        } catch(\Palpal\Exception\PPConnectionException $e){

            if(\Config::get('app.debug')){
                return redirect()
                        ->route('bookstore.shipping')
                        ->with('danger', 'Connection Timeout.');
            }

            return redirect()
                    ->route('bookstore.shipping')
                    ->with('danger', 'Some error occured, sorry for the inconvenience.');
        }

        foreach($payment->getLinks() as $link){
            if($link->getRel() == 'approval_url'){
                $redirect_url = $link->getHref();
                break;
            }
        }

        Session::put('paypal_payment_id', $payment->getId());

        if(isset($redirect_url)){
            return Redirect::away($redirect_url);
        }

        return redirect()
                ->route('bookstore.shipping')
                ->with('danger', 'Unknown error occured.');
    }

    public function getPaymentStatus(){
        $payment_id = Session::get('paypal_payment_id');
        Session::forget('paypal_payment_id');

        if(empty(Input::get('PayerID')) || empty(Input::get('token'))){
            return redirect()
                    ->route('bookstore.shipping')
                    ->with('danger', 'Payment failed.');
        }

        $payment = Payment::get($payment_id, $this->_api_context);
        $execution = new PaymentExecution();
        $execution->setPayerId(Input::get('PayerID'));

        $result = $payment->execute($execution, $this->_api_context);

        if($result->getState() == 'approved'){
            // Send Email
            $email_data = [
                'number_of_books' => $payment->transactions[0]->item_list->items[0]->name,
                'shipping' => [
                    'street' => $payment->payer->payer_info->shipping_address->line1,
                    'city' => $payment->payer->payer_info->shipping_address->city,
                    'state' => $payment->payer->payer_info->shipping_address->state,
                    'country' => $payment->payer->payer_info->shipping_address->country_code,
                ]
            ];

            // Send email function here ...

            return redirect()
                    ->route('bookstore.shipping')
                    ->with('success', 'Transaction payment success!');
        }

        return redirect()
                ->route('bookstore.shipping')
                ->with('danger', 'Payment failed.');
    }

}

I also reviewed this link but it seems like it cannot answer my problem. Also, what if the country has a province? How can we add that?

Update 1

  1. Added new Patch() class.
  2. Edited Code in Try Catch.

Note: The accepted answer will also receive the bounty plus the up.

Update 2 with Tutorial

  1. For PHP/Laravel (I'm currently using v5.1), install this package paypal/rest-api-sdk-php

  2. Create Sandbox account in PayPal. Choose Buy with Paypal.

  3. Continue until you see options, choose Shop the world.

  4. Login to developer.paypal.com.

  5. Click Accounts. Click Create Account.

  6. Choose what country you want. Choose Personal (Buyer Account) in Account Type.

  7. Add email address, avoid to use -. Use _ instead.

  8. Enter how much PayPal Balance you want.

  9. Click Create Account.

Make it live?

https://github.com/paypal/PayPal-PHP-SDK/wiki/Going-Live

1
  • I assume you're not suppressing errors and have all the correct classes loaded? Maybe you could just double check those two points, 'cause your code seems to be -- almost -- a copy of the example code.
    – Niellles
    Commented Jul 10, 2018 at 20:40

4 Answers 4

1
+250

After you have created the payment, try updating the address as shown in this example.

$paymentId = $createdPayment->getId();

$patch = new \PayPal\Api\Patch();
$patch->setOp('add')
    ->setPath('/transactions/0/item_list/shipping_address')
    ->setValue([
        "recipient_name" => "Gruneberg, Anna",
        "line1" => "52 N Main St",
        "city" => "San Jose",
        "state" => "CA",
        "postal_code" => "95112",
        "country_code" => "US"
    ]);

$patchRequest = new \PayPal\Api\PatchRequest();
$patchRequest->setPatches([$patch]);
$result = $createdPayment->update($patchRequest, $apiContext);

I also reviewed this link but it seems like it cannot answer my problem. Also, what if the country has a province? How can we add that?

Use the state codes listed here.

23
  • Updated with ID Commented Jul 6, 2018 at 4:20
  • Does the payment object you are using have an ID? Commented Jul 6, 2018 at 5:18
  • When I try to dd the getId() method, it returns null. Do you know why? Commented Jul 6, 2018 at 6:08
  • Can you post your full code? The ID of the payment should not be null if you are calling it after the $payment->create($this->_api_context); call. Commented Jul 6, 2018 at 14:53
  • 1
    You're right. It is now not null. I should just put it after the $payment->create($this->_api_context);. However, I'm still facing the same problem. Commented Jul 9, 2018 at 3:28
0

I have not used the PayPal API in a long while, but just skimming over the docs shows that the payer_info shipping address field is deprecated (https://developer.paypal.com/docs/api/orders/v1/#definition-payer_info) and suggests to use the shipping address in the purchase_unit instead.

According to the Docs, this should be set in the CartBase class with the setItemList() function (http://paypal.github.io/PayPal-PHP-SDK/docs/class-PayPal.Api.CartBase.html).

Edit:

So, for the package you are using, you'll need to add the PayPal\Api\ShippingAddress object to your $item_list variable:

$shipping = new PayPal\Api\ShippingAddress();
$shipping->setLine1('123 1st St.')
    ->setCity('Some City')
    ->setState('CA')
    ->setPostalCode("95123")
    ->setCountryCode("US")
    ->setPhone("555-555-5555")
    ->setRecipientName("John Doe");

$item_list = new ItemList();
$item_list->setItems([$item1])
    ->setShippingAddress($shipping);

ItemList class ref: http://paypal.github.io/PayPal-PHP-SDK/docs/source-class-PayPal.Api.ItemList.html#74-85

1
-1

I think this is the relevant documentation you are looking for.

For people who already have PayPal accounts and whom you already prompted for a shipping address before they choose to pay with PayPal, you can use the entered address instead of the address the person has stored with PayPal.

Instead of using the address saved in their account,

The payer is shown the passed-in address but cannot edit it. No address is shown if the address is invalid, such as missing required fields like country, or if the address is not included at all.


Edit: Try something like this in place of what you have.

$address = new ShippingAddress();
$address->setCity('Toronto');
$address->setState('ON');
$address->setCountryCode('CA');
$address->setLine1('123 Fake Street');
$address->setPostalCode('M1M1M1');

$payerInfo = new PayerInfo();
$payerInfo->setShippingAddress($address);

$payer = new Payer();
$payer->setPaymentMethod('paypal');
6
  • This would be great. But can you include an example? Coz I edited the name attributes in the form. This is the API I used: paypal.github.io/PayPal-PHP-SDK/sample/doc/payments/… Commented Jul 6, 2018 at 0:27
  • Also, what if the country has a province? How can we add that? Commented Jul 6, 2018 at 0:52
  • I tried it just now, but still not updating after logging in my sandbox account. Please see this screenshot: ibb.co/fHCgCJ Commented Jul 6, 2018 at 3:02
  • Isn't that what you want, the address prefilled? Commented Jul 6, 2018 at 3:18
  • That is the address in my sandbox account, not the address I used from my website. I want it to be the address I entered from my website. Commented Jul 6, 2018 at 3:19
-1

I haven't worked with PayPal very much, but I'm taking this from the official documentation, so I'm confident it will work for you. Overriding addresses stored with PayPal. For a list of available variables you can use in the checkout page, see Auto-fill PayPal checkout page variables.

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
    <!-- Enable override of buyers's address stored with PayPal . -->
    <input type="hidden" name="address_override" value="1">
    <!-- Set variables that override the address stored with PayPal. -->
    <input type="hidden" name="first_name" value="John">
    <input type="hidden" name="last_name" value="Doe">
    <input type="hidden" name="address1" value="345 Lark Ave">
    <input type="hidden" name="city" value="Montreal">

    <input type="hidden" name="state" value="QC">

    <input type="hidden" name="zip" value="H1A4K2">
    <input type="hidden" name="country" value="CA">
    <input type="image" name="submit"
       src="https://www.paypalobjects.com/en_US/i/btn/btn_buynow_LG.gif"
       alt="PayPal - The safer, easier way to pay online">
</form>

Or, from inside your script...

$address = new ShippingAddress();
$address->setCity('Montreal');
$address->setState('QC');
$address->setCountryCode('CA');
$address->setLine1('345 Lark Ave');
$address->setPostalCode('H1A4K2');

$payerInfo = new PayerInfo();
$payerInfo->setShippingAddress($address);

Here's the list of available province codes. You would use these two-letter strings for the "state" variable, just like you would a U.S. state. PayPal State and Province codes

Province name | Province code

Alberta | AB

British Columbia | BC

Manitoba | MB

New Brunswick | NB

Newfoundland and Labrador | NL

Northwest Territories | NT

Nova Scotia | NS

Nunavut | NU

Ontario | ON

Prince Edward Island | PE

Quebec | QC

Saskatchewan | SK

Yukon | YT

I hope this helps you.

5
  • Is the type of inputs necessarily to be hidden? Commented Jul 6, 2018 at 3:05
  • I tried it just now, but still not updating after logging in my sandbox account. Please see this screenshot: ibb.co/fHCgCJ Commented Jul 6, 2018 at 3:13
  • That's how those <inputs> appeared on the PayPal documentation. It has to be hidden, so no actual input fields appear where they are on the page. The type="hidden" is used to send static $_POST data. Have you tried clearing your cookies and your cache? Your app might be loading an old cookie Commented Jul 6, 2018 at 6:59
  • I'll try this. But how about this piece of code? ibb.co/bD856d . Should I still need this? Commented Jul 6, 2018 at 7:44
  • It seems like you could use either the HTML inputs, or the PHP script in your screenshot. If one of them doesn't work for you, you could always try the other. I'm unsure which would prevail if you used both. Commented Jul 6, 2018 at 17:54

Not the answer you're looking for? Browse other questions tagged or ask your own question.