Forums / Setup & design / SOS: Paypal - checkAmount failed - Solved

SOS: Paypal - checkAmount failed - Solved

Author Message

Mingxing Chen

Tuesday 03 July 2007 12:10:56 am

Hi guys,

Please help me :( I have not found how to solve my problem in this forum.

IThe version is 3.91. When I order something and use paypal to pay for them. Sometimes it failed and got this information:

checkAmount failed: Order amount (21.85) and received amount (21.85) do not match.

*21.85 is the price.

This is the function in <i>/kernel/shop/classes/ezpaymentcallbackchecker.php</i>

    function checkAmount( $amount )
    {
        $orderAmount = $this->order->attribute( 'total_inc_vat' );
        if ( $orderAmount == $amount )
        {
            return true;
        }

        $this->logger->writeTimedString( "Order amount ($orderAmount) and received amount ($amount) do not match.", 'checkAmount failed' );
        return false;
    }

But 21.85==21.85!!!
Yes, the type of $orderAmount is float(double), and $amount is string, this seems not the problem in PHP. Even I changed the datatype of $amount to float, I failed as well.

But when I bought other things with different prices, I successed!
It really confuses me, any one can help me?

Help~~~

Cheers.

Shinetech is the leader in next generation global application outsourcing. Shinetech combines world class technical skills, recognized expertise in advanced development methodologies and industry experience to deliver results for global enterprises. Shinetech utilizes distributed Agile methods for rapid and precise systems development.
------------------------------------------------------------------------------------------
Blog: http://www.mingxing.me
Email: chenmx@shinetechchina.com

Pascal Specht

Tuesday 03 July 2007 11:51:24 pm

Hi Mingxing,

I suppose this is a rounding or type safety problem:
Did you try to check the following:
round both floats to 2 digits precision, like in
$order_amount = round($order_amount,2);
before the comparison (and use === as the operator)
or, after rounding, convert to strings and do a string comparison using the appropriate operator.

Hope this helps,

Pascal

Mingxing Chen

Wednesday 04 July 2007 9:03:58 pm

Hi Pascal,

Thanks for your reply.

Yes, we have found the same problem - comparision of two float(double) numbers.
It's really bad to use '==' to compare them, why eZ Publish makes this simple mistake?!
Or, am I wrong? :(

I used this code to check the Amount(price):

$amount = doubleval($amount);
$orderAmount = doubleval($orderAmount);
if ( abs($orderAmount - $amount )<=1e-6 )
{
    return true;
}

It's not good enough, because there would be inaccuracy.

After reading your message and suggestions from my colleague, I tried this way:

$orderAmount = sprintf("%01.2f", $orderAmount);
if(strcmp($orderAmount, $amount)==0)
{
    return true;
}

What do you think about them? I am looking forward to a better solution from you. ;D

Cheers.

Mingxing

Shinetech is the leader in next generation global application outsourcing. Shinetech combines world class technical skills, recognized expertise in advanced development methodologies and industry experience to deliver results for global enterprises. Shinetech utilizes distributed Agile methods for rapid and precise systems development.
------------------------------------------------------------------------------------------
Blog: http://www.mingxing.me
Email: chenmx@shinetechchina.com

Bruce Morrison

Wednesday 04 July 2007 10:34:38 pm

Hi Mingxing

Firstly I'd report this as a bug @ http://issues.ez.no

The php manual http://au.php.net/float says "never compare floating point numbers for equality"

From my reading it appears your final solution (use of sprintf) is the right way of doing things.

Cheers
Bruce

My Blog: http://www.stuffandcontent.com/
Follow me on twitter: http://twitter.com/brucemorrison
Consolidated eZ Publish Feed : http://friendfeed.com/rooms/ez-publish

Pascal Specht

Wednesday 04 July 2007 11:23:57 pm

Hi Mingxing,

OK, the good news is that you know how to solve your problem... Somehow, I'd like to add, in case this may be useful:

comparing two floats by a threshold via the absolute difference is the correct way to compare floats outside of e-commerce. In CAD/CAM or graphical programs, you should definitively use this so called epsilon compare method, where the correct value of epsilon (1e-6) is a very difficult empirical task, and there's no universal value.

The correct way to do it in e-commerce in my opinion is to first apply a round method of your own (I wouldn't rely on the internal sprintf round, because I don't know how it works). Apply the correct banker's rounding. In most cases, the round function does this correctly for your currency. After that, do a convert to a string, and use a smart and documented way for the separation signs, the presence or not of the currency symbol before or after the amount, the number of digits etc. Only then, application exchange via XML or CURL or whatever can be reliable. Also, my way of proceeding is to apply rounding at the latest moment possible in the computation chain. If you apply several sums and VAT or other taxes, the round operation should happen at the latest moment in the chain, to avoid cumulating rounding errors.

Have a nice day,
Pascal