📍 Puntos de recogida y click & collect

Actualizado: 2024-12-01

Los puntos de recogida (tienda fisica, lockers, oficinas de correos) son cada vez mas populares. PrestaShop permite implementarlos como transportistas especiales con seleccion de punto en el checkout.

#Click & collect nativo

Configurar recogida en tienda
text
DESDE EL BO
1. Transporte → Transportistas → Añadir
2. Nombre: "Recogida en tienda"
3. Tiempo de transito: "Disponible en 24h"
4. Velocidad: 0 (grado de velocidad)
5. Precio: 0.00 (gratis)
6. Rangos: por precio o peso, ambos a 0
7. Zonas: solo la zona de tu tienda
8. Grupo: todos los grupos de clientes
9. Guardar

LIMITACIONES DEL METODO NATIVO
- No muestra mapa de puntos
- No permite seleccionar punto concreto
- Solo 1 direccion de recogida (la tienda)
- Para multiples puntos → modulo personalizado

#Hook displayCarrierExtraContent

Mostrar selector de punto de recogida
php
<?php

// ── Este hook se muestra debajo del transportista en el checkout ──
public function hookDisplayCarrierExtraContent(array $params): string
{
    $carrier = $params['carrier'];
    
    // Solo mostrar para nuestro transportista de puntos de recogida
    if ((int) $carrier['id'] !== (int) Configuration::get('MYMODULE_PICKUP_CARRIER_ID')) {
        return '';
    }

    // Obtener direccion del cliente para buscar puntos cercanos
    $cart = Context::getContext()->cart;
    $address = new Address($cart->id_address_delivery);
    
    // Buscar puntos de recogida cercanos
    $points = $this->getPickupPoints($address->postcode, $address->city);

    $this->context->smarty->assign([
        'pickup_points'   => $points,
        'selected_point'  => $this->getSelectedPoint($cart->id),
        'google_maps_key' => Configuration::get('MYMODULE_GMAPS_KEY'),
    ]);

    return $this->fetch('module:mymodule/views/templates/hook/pickup-selector.tpl');
}

// ── Template pickup-selector.tpl ──
// Muestra lista de puntos + mapa interactivo
// Al seleccionar un punto, hace AJAX para guardar la seleccion

#Integrar API de puntos de recogida

Consultar API externa de puntos
php
<?php

// ── Ejemplo generico: API de puntos de recogida ──
private function getPickupPoints(string $postcode, string $city): array
{
    $cacheKey = 'pickup_' . md5($postcode . $city);
    
    // Cache 1 hora (los puntos no cambian frecuentemente)
    $cached = Cache::retrieve($cacheKey);
    if ($cached) {
        return json_decode($cached, true);
    }

    // Llamar a la API del transportista
    $response = Tools::file_get_contents(
        'https://api.transportista.com/v1/pickup-points?'
        . http_build_query([
            'postcode' => $postcode,
            'city'     => $city,
            'country'  => 'ES',
            'limit'    => 10,
        ]),
        false,
        stream_context_create([
            'http' => [
                'header' => 'Authorization: Bearer ' . Configuration::get('MYMODULE_API_KEY'),
                'timeout' => 5,
            ]
        ])
    );

    $data = json_decode($response, true);
    $points = [];

    foreach ($data['points'] ?? [] as $p) {
        $points[] = [
            'id'       => $p['id'],
            'name'     => $p['name'],
            'address'  => $p['address'],
            'postcode' => $p['postcode'],
            'city'     => $p['city'],
            'lat'      => $p['latitude'],
            'lng'      => $p['longitude'],
            'hours'    => $p['opening_hours'],
            'distance' => $p['distance_km'],
        ];
    }

    Cache::store($cacheKey, json_encode($points));
    return $points;
}

#Guardar punto seleccionado

AJAX para guardar seleccion + usar en pedido
php
<?php

// ── Controller AJAX para guardar punto seleccionado ──
// modules/mymodule/controllers/front/pickupselect.php
class MyModulePickupSelectModuleFrontController extends ModuleFrontController
{
    public function initContent(): void
    {
        if (!$this->isTokenValid()) {
            $this->ajaxRender(json_encode(['error' => 'Invalid token']));
            return;
        }

        $pointId   = Tools::getValue('point_id');
        $pointName = Tools::getValue('point_name');
        $pointAddr = Tools::getValue('point_address');
        $cartId    = (int) Context::getContext()->cart->id;

        // Guardar en tabla custom
        Db::getInstance()->insert('mymodule_pickup_selection', [
            'id_cart'       => $cartId,
            'point_id'      => pSQL($pointId),
            'point_name'    => pSQL($pointName),
            'point_address' => pSQL($pointAddr),
        ], false, true, Db::ON_DUPLICATE_KEY);

        $this->ajaxRender(json_encode(['success' => true]));
    }
}

// ── Copiar seleccion al pedido cuando se valida ──
public function hookActionValidateOrder(array $params): void
{
    $order = $params['order'];
    $cart  = $params['cart'];

    $pickup = Db::getInstance()->getRow(
        'SELECT * FROM `' . _DB_PREFIX_ . 'mymodule_pickup_selection`
         WHERE id_cart = ' . (int) $cart->id
    );

    if ($pickup) {
        Db::getInstance()->insert('mymodule_pickup_order', [
            'id_order'      => (int) $order->id,
            'point_id'      => pSQL($pickup['point_id']),
            'point_name'    => pSQL($pickup['point_name']),
            'point_address' => pSQL($pickup['point_address']),
        ]);
    }
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.