---
name: shopify-comparar-transportadoras
description: "Solo lectura: compara tus transportadoras por días de tránsito, entregas a tiempo y costo de envío por pedido. Úsala para decidir qué transportadora usar por país o zona, o para llegar con datos a una negociación de tarifas."
---

## Propósito
Reúne los despachos (fulfillments) de los pedidos recientes, los cruza con la línea de envío de cada pedido y compara las transportadoras entre sí en (a) días promedio de tránsito, (b) tasa de entregas a tiempo (entregado antes de la fecha estimada que vio el cliente, o ese mismo día) y (c) costo de envío por pedido. Muestra qué transportadora conviene como predeterminada por zona, ruta o rango de peso. Solo lectura: no ejecuta mutaciones.

## Requisitos
- Sesión autenticada de Shopify CLI: `shopify store auth --store <tu-tienda>.myshopify.com --scopes read_orders`
- Las consultas se ejecutan con `shopify store execute`.
- Permisos de la API: `read_orders`

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | texto | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| days_back | entero | no | 60 | Ventana de días hacia atrás para los pedidos despachados |
| min_orders | entero | no | 10 | Mínimo de pedidos por transportadora para incluirla en la comparación |
| segment_by | texto | no | — | Segmentación opcional: `country`, `weight` o `none` |
| format | texto | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta mutaciones. Puedes correrla en cualquier momento. El costo se calcula con el precio de envío que pagó el cliente, no con la tarifa que negociaste con la transportadora; si quieres ver la diferencia real de costos, tienes que cruzarlo tú con las facturas de la transportadora.

## Pasos

1. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: "fulfillment_status:shipped created_at:>='<HOY - days_back días>'"`, `first: 250`; selecciona `fulfillments { trackingInfo, createdAt, deliveredAt, inTransitAt }`, `shippingLine { carrierIdentifier, originalPriceSet, title }`, `totalWeight`, `shippingAddress` y el cursor de paginación
   **Resultado esperado:** Pedidos despachados con su línea de envío y los tiempos de cada despacho; pagina hasta que `hasNextPage: false`

2. **OPERACIÓN:** `fulfillments` — consulta (por ID de despacho, para los pedidos a los que les falten datos en la primera respuesta)
   **Entradas:** `id: <fulfillmentGid>`
   **Resultado esperado:** `events`, `deliveredAt` y `estimatedDeliveryAt` en detalle

3. Agrupa por transportadora (usa `shippingLine.carrierIdentifier` si existe; si no, toma `trackingInfo.company`). Para cada transportadora calcula: días promedio de tránsito, percentil 90 (p90) de días de tránsito, tasa de entregas a tiempo (`deliveredAt <= estimatedDeliveryAt`), precio promedio de envío y cantidad de pedidos.

4. Si `segment_by` tiene valor, repite la agrupación dentro de cada segmento (p. ej., por `shippingAddress.countryCode`).

5. Descarta las transportadoras con menos de `min_orders` pedidos y ordena por días promedio de tránsito, de menor a mayor.

## Operaciones GraphQL

```graphql
# orders:query — validada con api_version 2025-01
query OrdersForCarrierComparison($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        createdAt
        totalWeight
        shippingAddress {
          countryCode
          provinceCode
          zip
        }
        shippingLine {
          carrierIdentifier
          title
          code
          originalPriceSet {
            shopMoney {
              amount
              currencyCode
            }
          }
        }
        fulfillments {
          id
          createdAt
          inTransitAt
          deliveredAt
          estimatedDeliveryAt
          status
          trackingInfo {
            company
            number
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

```graphql
# fulfillments:query — validada con api_version 2025-01
query FulfillmentDetail($id: ID!) {
  fulfillment(id: $id) {
    id
    status
    createdAt
    inTransitAt
    deliveredAt
    estimatedDeliveryAt
    trackingInfo {
      company
      number
      url
    }
    events(first: 50) {
      edges {
        node {
          status
          happenedAt
          message
        }
      }
    }
  }
}
```

## Seguimiento de la sesión

**Claude DEBE mostrar la siguiente salida en cada etapa. Es obligatorio.**

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Compara tus transportadoras          ║
║  Tienda: <dominio de la tienda>              ║
║  Inicio: <YYYY-MM-DD HH:MM UTC>              ║
╚══════════════════════════════════════════════╝
```

**Después de cada paso**, muestra:
```
[N/TOTAL] <QUERY|MUTATION>  <OperationName>
          → Parámetros: <resumen breve de las entradas clave>
          → Resultado: <cantidad o desenlace>
```

**Al terminar**, muestra:

Para `format: human` (predeterminado):
```
══════════════════════════════════════════════
RENDIMIENTO DE TRANSPORTADORAS  (<days_back> días)
  Pedidos analizados:        <n>
  Con datos de entrega:      <n>

  Transportadora   Pedidos  Días prom.  P90  A tiempo %  Costo prom.
  ──────────────────────────────────────────────────────────────────
  <transportadora> <n>      <d>         <d>  <pct>%      $<n>
  <transportadora> <n>      <d>         <d>  <pct>%      $<n>
  Archivo: carrier_performance_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-comparar-transportadoras",
  "store": "<dominio>",
  "period_days": 60,
  "orders_analyzed": 0,
  "carriers": [
    {
      "name": "UPS",
      "orders": 0,
      "avg_transit_days": 0,
      "p90_transit_days": 0,
      "on_time_pct": 0,
      "avg_cost": 0,
      "currency": "USD"
    }
  ],
  "output_file": "carrier_performance_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `carrier_performance_<YYYY-MM-DD>.csv` con las columnas:
`carrier`, `segment`, `orders`, `avg_transit_days`, `p90_transit_days`, `on_time_pct`, `avg_cost`, `total_cost`, `currency`

## Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| `THROTTLED` | Se superó el límite de solicitudes de la API | Espera 2 segundos y reintenta hasta 3 veces |
| `deliveredAt` es nulo | La transportadora no confirmó la entrega | Exclúyelo del promedio de tránsito y cuéntalo como "en tránsito" |
| `estimatedDeliveryAt` es nulo | La transportadora no dio una fecha estimada | Exclúyelo de la tasa de entregas a tiempo; no penalices a la transportadora |
| `carrierIdentifier` y `trackingInfo.company` son nulos | Despacho manual sin número de guía | Agrúpalos como `(desconocida)` y muestra su cantidad aparte |

## Buenas prácticas
- Compara transportadoras solo con `min_orders >= 10`; las muestras más pequeñas son ruido.
- Usa `segment_by: country` para comparaciones internacionales: una transportadora fuerte a nivel nacional puede ser débil en envíos al exterior.
- Combina esta skill con `shopify-tiempos-de-entrega` si solo quieres ver los tiempos; esta skill agrega el costo y las entregas a tiempo.
- Una transportadora con muy buen tiempo de tránsito pero costo alto todavía puede ganar si tus clientes valoran la rapidez (tiendas con ticket promedio alto): cruza este reporte con la satisfacción de tus clientes (NPS) o con sus reseñas.
- Córrela cada trimestre, en las épocas de revisión de contratos, para negociar con las transportadoras con datos y no con intuición.
