paypal / PayPal-PHP-SDK

PHP SDK for PayPal RESTful APIs
https://developer.paypal.com/docs/api/
Other
26 stars 89 forks source link

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

Closed MichaelBelgium closed 4 years ago

MichaelBelgium commented 4 years ago

General information

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?

MichaelBelgium commented 4 years ago

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

prakash-gangadharan commented 4 years ago

@MichaelBelgium, can you add your code snippet here?

MichaelBelgium commented 4 years ago

@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();
//...
MichaelBelgium commented 4 years ago

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

prakash-gangadharan commented 4 years ago

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

MichaelBelgium commented 4 years ago

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

prakash-gangadharan commented 4 years ago

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

MichaelBelgium commented 4 years ago

I believe so, gotta use everywhere number_format 🙄

prakash-gangadharan commented 4 years ago

That sounds cool :thumbsup: