paypal/PayPal-PHP-SDK

Paypal Item prices are correct on localhost, not live/staging server

Closed this issue ยท 9 comments

General information

  • SDK/Library version: 1.14.0
  • Environment: sandbox
  • PayPal-Debug-ID values: 87137f1a3b0
  • Language, language version, and OS: PHP 7.2 Debian stretch

Issue description

Initial issue was this error on my server:

[13-10-2019 12:00:31] PayPal\Core\PayPalHttpConnection : ERROR: Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/payments/payment. {"name":"VALIDATION_ERROR","details":[{"field":"transactions[0].amount","issue":"Transaction amount details (subtotal, tax, shipping) must add up to specified amount total"},{"field":"transactions[0]","issue":"Item amount must add up to specified amount subtotal (or total if amount details not specified)"}],"message":"Invalid request - see details","information_link":"https://developer.paypal.com/docs/api/payments//#errors","debug_id":"87137f1a3b0"}

While adding the same items to the transaction on localhost it does work. AFter debugging i found out this:

Items localhost:

[2019-10-13 12:11:04] local.INFO: array (
  0 => 
  PayPal\Api\Item::__set_state(array(
     '_propMap' => 
    array (
      'name' => 'Sandwich',
      'currency' => 'EUR',
      'quantity' => 3,
      'price' => '0.50',<== correct
    ),
  )),
  1 => 
  PayPal\Api\Item::__set_state(array(
     '_propMap' => 
    array (
      'name' => 'Witte pistolet',
      'currency' => 'EUR',
      'quantity' => 5,
      'price' => '0.40', <== correct
    ),
  )),
  2 => 
  PayPal\Api\Item::__set_state(array(
     '_propMap' => 
    array (
      'name' => 'Zacht bruin',
      'currency' => 'EUR',
      'quantity' => 10,
      'price' => '0.45',<== correct
    ),
  )),
)  

Items on staging server:

[2019-10-13 12:05:02] staging.INFO: array (
  0 =>
  PayPal\Api\Item::__set_state(array(
     '_propMap' =>
    array (
      'name' => 'Sandwich',
      'currency' => 'EUR',
      'quantity' => 3,
      'price' => '1', <== rounded
    ),
  )),
  1 =>
  PayPal\Api\Item::__set_state(array(
     '_propMap' =>
    array (
      'name' => 'Zacht bruin',
      'currency' => 'EUR',
      'quantity' => 10,
      'price' => '0' ,<== rounded
    ),
  )),
  2 =>
  PayPal\Api\Item::__set_state(array(
     '_propMap' =>
    array (
      'name' => 'Witte pistolet',
      'currency' => 'EUR',
      'quantity' => 5,
      'price' => '0', <== rounded
    ),
  )),
)

The code is exactly the same (ofcourse) but on the staging/live server the item prices get rounded?
Items are getting loaded from the session cart which, when debugged, returns:

[2019-10-13 12:05:02] staging.INFO: {"rowId":"1ca30d70ab09187def0f79120f1607ee","id":43,"name":"Sandwich","qty":3,"price":0.5,"options":[],"tax":"0.00","subtotal":"1.50"}
[2019-10-13 12:05:02] staging.INFO: {"rowId":"8c9a90e4053cd74dcb83515e745419ae","id":42,"name":"Zacht bruin","qty":10,"price":0.45,"options":[],"tax":"0.00","subtotal":"4.50"}
[2019-10-13 12:05:02] staging.INFO: {"rowId":"0200fdfc7ee6c5b96ab26c639259d987","id":44,"name":"Witte pistolet","qty":5,"price":0.4,"options":[],"tax":"0.00","subtotal":"2.00"}

Which is exactly the same like on localhost.
What can be the issue here?

Might be related to #1265 - I'm using laravel too

@MichaelBelgium, can you add your code snippet here?

@prakash-gangadharan

        $total = (float)Cart::total(2, '.');

        foreach (Cart::content() as $cartProduct)
        {
            $item = new Item();
            $item->setName($cartProduct->name)
                ->setCurrency('EUR')
                ->setQuantity($cartProduct->qty)
                ->setPrice($cartProduct->price);

            array_push($items, $item);

            Log::info($cartProduct);
        }

        Log::info($items);
        
        $payer = new Payer();
        $payer->setPaymentMethod('paypal');
        
        $item_list = new ItemList();
        $item_list->setItems($items);

        $details = new Details();
        $details
            ->setSubtotal($subTotal)
            ->setHandlingFee(Cart::getCost(\Gloudemans\Shoppingcart\Cart::COST_TRANSACTION, 2, '.'));//paypal fee

        Log::info('handling fee: ' . Cart::getCost(\Gloudemans\Shoppingcart\Cart::COST_TRANSACTION, 2, '.'));

        $amount = new Amount();
        $amount->setCurrency('EUR')
            ->setDetails($details)
            ->setTotal($total);

        Log::info('Total: '.$total);        

        $transaction = new Transaction();
        $transaction->setAmount($amount)
            ->setInvoiceNumber($hash)
            ->setItemList($item_list)
            ->setDescription('Bestelling '.$hash);

        $redirect_urls = new RedirectUrls();
        $redirect_urls->setReturnUrl(route('paypal.status'))
            ->setCancelUrl(route('cart.index', ['cancel' => $hash]));

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

        try {
            $payment->create($this->paypalApi);

        } catch (Exception $ex) {
            return redirect()->route('cart.index')->with('error', $ex->getMessage());
        }

        $redirect_url = $payment->getApprovalLink();
//...

I found the issue. $cartProduct->price returned "0.5" localhost and on the server "0,5" (with comma). I believe this is the cause then. And i can blame locale settings

@MichaelBelgium ,so the round off issue resolved now in stage?

It's not rounding it (or well partially), it's just the parsing of floats (by the locale) that screws up everything. Like "0,5" gets passed to setPrice and in the function it set $decimals to 0 as it can't find a dot. So everything after the comma gets cut, hence why it looks like it rounded off

@MichaelBelgium, I believe you resolved the issue now, aren't you?

I believe so, gotta use everywhere number_format ๐Ÿ™„

That sounds cool ๐Ÿ‘