⚡ Hooks de transportistas y envio

Actualizado: 2024-12-01

Los hooks de transportistas permiten intervenir en el calculo de tarifas, mostrar contenido extra en el checkout y reaccionar a cambios de estado del envio. Son esenciales para modulos de transportista personalizados.

#Hooks principales de carrier

HookTipoCuando se ejecuta
actionCarrierProcessactionAl seleccionar transportista en checkout
actionCarrierUpdateactionAl editar un transportista en el BO
displayCarrierExtraContentdisplayDebajo de cada transportista en checkout
displayBeforeCarrierdisplayAntes de la lista de transportistas
displayAfterCarrierdisplayDespues de la lista de transportistas
actionValidateOrderactionAl confirmar el pedido (incluye datos de envio)
actionOrderStatusPostUpdateactionDespues de cambiar el estado del pedido
actionObjectOrderCarrierUpdateAfteractionAl actualizar datos del carrier en un pedido

#getOrderShippingCost()

Calculo dinamico de coste de envio
php
<?php

// ── Metodo principal de CarrierModule ──
// Se llama automaticamente para calcular el precio de envio

class MyCarrier extends CarrierModule
{
    /**
     * Calcula el coste de envio para el carrito actual.
     *
     * @param Cart $cart    El carrito del cliente
     * @param float $shipping_cost  Coste base configurado en rangos
     * @return float|false  Precio final de envio, o false si no disponible
     */
    public function getOrderShippingCost($cart, $shipping_cost)
    {
        // $shipping_cost ya contiene el precio del rango configurado en el BO
        // Puedes modificarlo o reemplazarlo completamente

        // ── Ejemplo 1: Tarifa plana ──
        return 4.95;

        // ── Ejemplo 2: Modificar la tarifa base ──
        // Recargo del 10% en temporada alta
        $month = (int) date('m');
        if ($month === 12 || $month === 1) {
            return $shipping_cost * 1.10;
        }
        return $shipping_cost;

        // ── Ejemplo 3: Calculo por API externa ──
        $address  = new Address($cart->id_address_delivery);
        $weight   = $cart->getTotalWeight();
        $postcode = $address->postcode;

        $apiCost = $this->callExternalShippingAPI($weight, $postcode);
        if ($apiCost === false) {
            return false; // No disponible → no mostrar este transportista
        }
        return $apiCost;

        // ── Ejemplo 4: Envio gratis si carrito > X€ ──
        $total = $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING);
        if ($total >= 50.00) {
            return 0.00; // Gratis
        }
        return $shipping_cost;
    }

    /**
     * Coste externo (sin rango base del BO).
     */
    public function getOrderShippingCostExternal($cart)
    {
        return $this->getOrderShippingCost($cart, 0);
    }
}

#getOrderShippingCostExternal()

Coste de envio sin rangos del BO
php
<?php

// ── Se llama cuando NO hay rangos configurados en el BO ──
// Es decir, el modulo calcula TODO el precio por su cuenta
// (tipico de integraciones con APIs de transportistas)

public function getOrderShippingCostExternal($cart)
{
    // Obtener datos necesarios
    $address = new Address($cart->id_address_delivery);
    $country = new Country($address->id_country);
    $weight  = $cart->getTotalWeight();
    $total   = $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING);

    // Dimensiones (si las guardas en el producto)
    $products = $cart->getProducts();
    $maxLength = 0;
    foreach ($products as $p) {
        $maxLength = max($maxLength, (float) $p['depth']);
    }

    // Llamar API del transportista
    try {
        $response = $this->apiClient->getRate([
            'origin'      => Configuration::get('MY_CARRIER_ORIGIN_ZIP'),
            'destination'  => $address->postcode,
            'country'      => $country->iso_code,
            'weight'       => $weight,
            'total_amount' => $total,
        ]);

        if (isset($response['price'])) {
            return (float) $response['price'];
        }
    } catch (\Exception $e) {
        PrestaShopLogger::addLog('MyCarrier API error: ' . $e->getMessage(), 3);
    }

    return false; // No disponible
}

#displayCarrierExtraContent

Mostrar contenido extra en el checkout
php
<?php

// ── Muestra HTML debajo del nombre del transportista en el checkout ──
// Util para: seleccionar punto de recogida, mostrar info extra, etc.

public function hookDisplayCarrierExtraContent(array $params): string
{
    $carrier = $params['carrier']; // Datos del transportista

    // Solo mostrar para nuestro transportista
    if ((int) $carrier['id'] !== (int) $this->getCarrierId()) {
        return '';
    }

    // Ejemplo: selector de punto de recogida
    $this->context->smarty->assign([
        'pickup_points' => $this->getPickupPoints(
            $this->context->cart->id_address_delivery
        ),
        'selected_point' => $this->context->cart->getDeliveryOption(),
    ]);

    return $this->display(__FILE__, 'views/templates/hook/carrier-extra.tpl');
}

// ── Template carrier-extra.tpl ──
// <div class="my-carrier-pickup">
//   <p>Selecciona un punto de recogida:</p>
//   <select name="my_carrier_pickup_id">
//     {foreach $pickup_points as $point}
//       <option value="{$point.id}">{$point.name} - {$point.address}</option>
//     {/foreach}
//   </select>
// </div>

#Hooks de estado de envio

Reaccionar a cambios de estado del pedido
php
<?php

// ── Cuando el pedido cambia a "Enviado" ──
public function hookActionOrderStatusPostUpdate(array $params): void
{
    $newStatus = $params['newOrderStatus'];
    $orderId   = (int) $params['id_order'];

    // Estado 4 = Enviado (por defecto)
    if ((int) $newStatus->id !== Configuration::get('PS_OS_SHIPPING')) {
        return;
    }

    $order = new Order($orderId);
    $carrier = new Carrier($order->id_carrier);

    // Si es nuestro transportista, notificar a la API
    if ($carrier->external_module_name === $this->name) {
        $tracking = $order->getWsShippingNumber();
        $this->notifyShipment($order, $tracking);
    }
}

// ── Cuando se actualiza el numero de tracking ──
public function hookActionObjectOrderCarrierUpdateAfter(array $params): void
{
    $orderCarrier = $params['object'];
    $tracking     = $orderCarrier->tracking_number;

    if (!empty($tracking)) {
        // Enviar tracking al cliente, actualizar API externa, etc.
        $order = new Order($orderCarrier->id_order);
        $this->sendTrackingEmail($order, $tracking);
    }
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.