---
name: shopify-ventas-por-canal
description: "Solo lectura: desglosa ingresos, unidades y ticket promedio por canal de ventas (tienda online, POS, borradores de pedido, etc.). Úsala cuando vendas por varios canales y quieras saber de dónde vienen tus ventas."
---

## Propósito
Analiza los pedidos según su canal de origen para obtener un desglose de ingresos, unidades vendidas y ticket promedio (AOV) por canal. Ayuda a las tiendas que venden por varios canales a entender de dónde vienen los ingresos: tienda online, POS, borradores de pedido (B2B), app móvil o canales de terceros. 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 (scopes) de la API: `read_orders`

## Parámetros

| Parámetro | Tipo | Obligatorio | Por defecto | Descripción |
|-----------|------|-------------|-------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| days_back | integer | no | 30 | Cuántos días hacia atrás analizar |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta mutaciones. Puedes correrla en cualquier momento.

## Pasos

1. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: "created_at:>='<NOW - days_back days>'"`, `first: 250`, selecciona `channelInformation { channelDefinition { handle, displayName } }`, `totalPriceSet`, `lineItems { quantity }`, cursor de paginación
   **Resultado esperado:** Pedidos con su canal de origen; pagina hasta que `hasNextPage: false`

2. Agrupa por `channel.displayName`; calcula por canal: cantidad de pedidos, ingresos totales, unidades totales y ticket promedio

## Operaciones GraphQL

```graphql
# orders:query — validado con api_version 2025-01
query OrdersByChannel($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        createdAt
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        channelInformation {
          channelDefinition {
            handle
            displayName
          }
        }
        lineItems(first: 50) {
          edges {
            node {
              quantity
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

**Claude DEBE mostrar esta salida en cada etapa. Es obligatorio.**

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

**Después de cada paso**, muestra:
```
[N/TOTAL] <CONSULTA|MUTACIÓN>  <NombreOperación>
          → Parámetros: <resumen breve de las entradas clave>
          → Resultado: <conteo o resultado>
```

**Al terminar**, muestra:

Para `format: human` (por defecto):
```
══════════════════════════════════════════════
VENTAS POR CANAL  (<days_back> días)
  Ingresos totales:  $<monto>
  Total de pedidos:  <n>

  Canal                  Pedidos  Ingresos   Ticket   Unid.  Part.
  ─────────────────────────────────────────────────────────────────
  Tienda online          <n>      $<n>       $<n>     <n>    <pct>%
  POS                    <n>      $<n>       $<n>     <n>    <pct>%
  Borradores de pedido   <n>      $<n>       $<n>     <n>    <pct>%
  Archivo: sales_by_channel_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-ventas-por-canal",
  "store": "<dominio>",
  "period_days": 30,
  "total_revenue": 0,
  "total_orders": 0,
  "currency": "<moneda de la tienda>",
  "by_channel": [],
  "output_file": "sales_by_channel_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `sales_by_channel_<YYYY-MM-DD>.csv` con las columnas:
`channel_handle`, `channel_name`, `order_count`, `total_revenue`, `aov`, `total_units`, `revenue_share_pct`, `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 |
| Información de canal en null | Pedidos de canales eliminados o desconocidos | Agrúpalos como «Desconocido» |
| No hay pedidos en el rango | Período sin movimiento | Termina con ingresos en 0 |

## Buenas prácticas
- Si los pedidos de POS tienen un ticket promedio mucho más bajo que los de la tienda online, puede haber abuso de descuentos del personal o errores al cobrar: vale la pena cruzar los datos.
- El canal de borradores de pedido corresponde a pedidos B2B o mayoristas; si está creciendo, puede justificar un flujo de reportes dedicado a B2B.
- Los cambios en la mezcla de canales a lo largo del tiempo muestran dónde está funcionando la inversión en marketing; combínala con `shopify-ticket-promedio` para tener el panorama completo.
