Stripe API PHP partial refund doesnt work

96 views Asked by At

I try do partial refund in stripe php but all time do full refund instead.

My code:

public static function createRefund($id,$refundAmount){
        $refundAmount = $refundAmount *  100;
        $refund = \Stripe\Refund::create([
            'payment_intent' => $id,
            'amount' => $refundAmount,
        ]);

        if ($refund->status === 'succeeded') {
            return true;
        } else {
           return  false;
        }
    }

I get success and in logs see that refund was created : text

But I always get full amount refund. For example, there was payment intent with 3 CHF. I try refund 0.5 and get in my card 3 CHF (but see message that 0.5CHF ...)

What problem can be? There can be settings to block partial refunds? Or maybe problem with card? Because seems code is correct. Thanks!

1

There are 1 answers

0
hakre On

In your question you write that you want to refund 0.5 CHF.

Given the $refundAmount parameter is 0.5 and the following code:

        $refundAmount = $refundAmount *  100;
        $refund = \Stripe\Refund::create([
            'payment_intent' => $id,
            'amount' => $refundAmount,
        ]);

We can see that $refundAmount is multiplied by 100:

        $refundAmount = $refundAmount *  100;

As $refundAmount is 0.5, this is a floating point calculation

0.5 * 100

which results in PHP always in a floating point number:

> 0.5 * 100
= 50.0

(note the .0).

You then assign this floating point number to the API message:

        $refund = \Stripe\Refund::create([
            'payment_intent' => $id,
            'amount' => $refundAmount,
        ]);

However the field 'amount' expects an integer value (ref).

Perhaps 50.0 is read as 500? Perhaps 'amount' is dropped? Perhaps the default is taken (the default is full refund)? Better provide the correct number.

In PHP to convert a floating point number to an integer, you can either cast it, or, as a floating point calculation has been done that is always with precision error, round(), and then cast it:

$refundAmount = (int)round($refundAmount *  100);

Better yet it would be though, to not enter into this territory at all and to provide an integer value in the first place and don't do any calculation inside the function:

public static function createRefund(?string $id, int $refundAmount): bool
{
  
    $refund = \Stripe\Refund::create([
        'payment_intent' => $id,
        'amount' => $refundAmount,
    ]);

    return $refund->status === 'succeeded';
}

You then just call that method with the appropriate value and next time you run into an "API" issue, you may have already better clarity what your actual values are.

...::createRefund($paymentIntent, (int)round($refundChf * 100))

If it helps, there is also an existing Q&A about partial and full refunds on site: