Hello. I am experiencing a weird problem with shipping calculations.
I have a checkout page, where the shipping method and cost is calculated (by calling a ‘set-shipping’ route with fetch) based on the selected shipping country. Upon visiting this checkout page, a default shipping product is added for the default country.
I am adding this default shipping product with this code:
// controllers/checkout.php
...
$cart = merx()->cart();
// I first remove all shipping products, because selecting another country adds a shipping product on top of the default one.
removeAllShippingMethods($cart);
$cart->add([
'id' => $defaultShippingMethod->id(),
'type' => 'shipping',
'price' => cartSumAboveFreeShipping($defaultShippingMethod) ? 0 : (float) $defaultShippingMethod->price()->value()
]);
...
Everything works so far. The problem presents itself when the payment is performed. No matter which shipping method is selected, the default shipping product is always passed to the payment method (Stripe). Curiously, the correct shipping method (the one selected by the user) is registered on the order page created by Merx.
Ι updated this post many times (10 so far!) to not flood the topic. Sorry!
I found out that by adding the shipping product via fetch, the product seems to be added on the page, but is not passed to payment. Only if I refresh the checkout page this product is actually added.
My shipping route:
[
'pattern' => 'shop-api/set-shipping',
'method' => 'POST',
'action' => function() {
try {
$data = kirby()->request()->data();
$method = kirby()->page($data['method']);
$method_data = [
'name' => $method->title()->value(),
'from' => $method->from()->value(),
'to' => $method->to()->value(),
'price' => cartSumAboveFreeShipping($method) ? 0 : formatCurrency($method->price()->value())
];
$cart = merx()->cart();
removeAllShipping($cart);
$cart->add([
'id' => $method->id(),
'type' => 'shipping',
'price' => cartSumAboveFreeShipping($method) ? 0 : (float) $method->price()->value()
]);
return [
'status' => 200,
'method' => $method_data,
'itemsBuildTime' => allItemsBuildTime(),
'cart' => [
'subtotal' => formatCurrency($cart->filterBy('type', 'product')->getSum()),
'total' => formatCurrency($cart->getSum()),
]
];
} catch (Kirby\Exception\Exception $ex) {
return $ex->toArray();
}
},
],
Ο, I solved it. I was always using the same StripePaymentIntent that I set in the checkout controller. It needed to be created after all the peoduct changes.

I have an issue with Stripe. During Stripe’s redirect to the success page, Stripe shows a button “Return to Merchant” If the user doesn’t wait for the automatic redirect and clicks the button (understandable), the user is redirected to the cart/checkout with an error saying the payment couldn’t be finished. The user is still charged, but Stripe doesn’t register it as a charge and will refund it in 1 or 2 days (they say). How can I make sure this “Return to Merchant” button is not visible or doesn’t result in an error? I really hope I can solve this issue fast. If it is any help, I can give access to the code on GitHub.




