---
title: Puntos de recogida y click & collect
section: carriers
slug: pickup-points
description: "Implementar puntos de recogida en PrestaShop: click & collect, mapa de puntos, seleccion de punto en checkout, integracion con APIs."
keywords: prestashop puntos recogida click collect pickup point mapa checkout API transportista
last_updated: 2024-12-01
source_url: "https://ayudaprestashop.es/carriers/pickup-points"
---

# Puntos de recogida y click & collect

> Implementar puntos de recogida en PrestaShop: click & collect, mapa de puntos, seleccion de punto en checkout, integracion con APIs.

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']),
        ]);
    }
}
```


---

*Fuente: [https://ayudaprestashop.es/carriers/pickup-points](https://ayudaprestashop.es/carriers/pickup-points). Version Markdown generada automaticamente para consumo por LLMs.*
