Efectivamente, @sergio94 ha dado en el clavo. La lógica de OrderConfirmationController::init() es bastante estricta. Busca los parámetros id_order, id_module y key en la URL ($_GET). Si id_order falta, o si la clave de seguridad (key) no es válida para el id_customer y el id_cart del contexto, el método init() te redirigirá. Tu override, al llamar a parent::init() primero, permite que esa redirección ocurra antes de que puedas inyectar el id_order necesario para los pedidos gratuitos.
Para solucionar esto, necesitas asegurarte de que $_GET contenga los valores correctos para tu pedido gratuito antes de que se ejecute parent::init(). Así, el controlador creerá que ha sido llamado correctamente y no redirigirá. Aquí te muestro una forma de hacerlo:
// overrides/controllers/front/OrderConfirmationController.php
class OrderConfirmationControllerCore extends OrderConfirmationController
{
public function init()
{
// Solo intervenimos si id_order no está ya en la URL y tenemos un carrito y cliente válidos
if (!Tools::getValue('id_order') && $this->context->cart->id && $this->context->customer->id) {
$id_order = Order::getIdByCartId((int)$this->context->cart->id);
if ($id_order) {
$order = new Order($id_order);
Este código asegura que, si un pedido gratuito validado existe para el carrito actual y el cliente, los parámetros necesarios se establecen en $_GET antes de que el controlador principal realice sus comprobaciones de redirección. Ten en cuenta que los overrides pueden ser delicados en actualizaciones futuras. Para una solución más robusta y mantenible en un entorno de producción, especialmente si manejas muchos pedidos gratuitos y quieres una página de confirmación personalizada, te recomiendo considerar una herramienta de página de confirmación dedicada. Estos módulos están diseñados para integrarse sin overrides y manejar estas situaciones de forma más limpia.