---
name: shopify-productos-mas-vendidos
description: "Ordena tus productos por ingresos, unidades vendidas y tasa de reembolso en un rango de fechas, a partir de las líneas de los pedidos. Úsala cuando quieras ver qué productos venden más y cuáles se devuelven demasiado."
---

## Propósito
Ordena los productos por ingresos, unidades vendidas y tasa de reembolso en un rango de fechas, sumando las líneas de pedido y las líneas de reembolso de todos los pedidos del período. Sirve para identificar los productos estrella y los que tienen tasas de reembolso altas. 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 API: `read_orders`

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., mitienda.myshopify.com) |
| format | string | no | human | Formato de salida: `human` o `json` |
| dry_run | bool | no | false | Muestra las operaciones sin ejecutar mutaciones |
| date_range_start | string | sí | — | Fecha de inicio en ISO 8601 (p. ej., `2025-01-01`) |
| date_range_end | string | sí | — | Fecha de fin en ISO 8601 (p. ej., `2025-01-31`) |
| top_n | integer | no | 20 | Cantidad de productos que se muestran en el ranking |
| sort_by | string | no | revenue | Métrica para ordenar: `revenue`, `units` o `refund_rate` |

## Pasos

1. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `first: 250`, `query: "created_at:>='<date_range_start>' created_at:<='<date_range_end>'"` y el cursor de paginación
   **Resultado esperado:** Todos los pedidos del rango con sus líneas de pedido (`title`, `quantity`, `originalTotalSet`, `refundableQuantity`) y sus líneas de reembolso; pagina hasta `hasNextPage: false`; suma en memoria por producto: `originalTotalSet` para los ingresos brutos, los montos reembolsados para los ingresos netos y las cantidades para las unidades vendidas, y calcula la tasa de reembolso

## Operaciones GraphQL

```graphql
# orders:query (para los ingresos por producto) — validada con api_version 2025-01
query OrdersForProductPerformance($first: Int!, $after: String, $query: String) {
  orders(first: $first, after: $after, query: $query) {
    edges {
      node {
        id
        createdAt
        lineItems(first: 50) {
          edges {
            node {
              title
              quantity
              variant {
                id
                sku
                product {
                  id
                  title
                }
              }
              originalTotalSet {
                shopMoney { amount currencyCode }
              }
              refundableQuantity
            }
          }
        }
        refunds {
          refundLineItems(first: 50) {
            edges {
              node {
                quantity
                lineItem {
                  variant {
                    id
                    product { id title }
                  }
                }
                subtotalSet {
                  shopMoney { amount currencyCode }
                }
              }
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

**Claude DEBE mostrar lo siguiente en cada etapa. Es obligatorio.**

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Productos más vendidos               ║
║  Tienda: <dominio de la tienda>              ║
║  Inicio: <AAAA-MM-DD HH:MM UTC>              ║
╚══════════════════════════════════════════════╝
```

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

**Al terminar**, muestra:

Para `format: human` (predeterminado):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  Pedidos procesados:   <n>
  Productos ordenados:  <n>
  Rango de fechas:      <inicio> a <fin>
  Ordenado por:         <revenue|units|refund_rate>
  Errores:              0
  Archivo:              ninguno
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-productos-mas-vendidos",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "completed_at": "<ISO8601>",
  "dry_run": false,
  "steps": [
    { "step": 1, "operation": "OrdersForProductPerformance", "type": "query", "params_summary": "<date_range_start> a <date_range_end>", "result_summary": "<n> pedidos procesados", "skipped": false }
  ],
  "outcome": {
    "orders_processed": 0,
    "products_ranked": 0,
    "date_range_start": "<date_range_start>",
    "date_range_end": "<date_range_end>",
    "sort_by": "revenue",
    "results": [],
    "errors": 0,
    "output_file": null
  }
}
```

## Formato de salida
Tabla ordenada que se muestra en la conversación (sin CSV), limitada a `top_n` filas:

| Puesto | Producto | Unidades vendidas | Ingresos brutos | Monto reembolsado | Ingresos netos | Tasa de reembolso % |
|--------|----------|-------------------|-----------------|-------------------|----------------|---------------------|
| 1 | ... | ... | ... | ... | ... | ... |

Para `format: json`, `results` es un arreglo de objetos con las claves: `rank`, `product_id`, `product_title`, `units_sold`, `gross_revenue`, `refunded_amount`, `net_revenue`, `refund_rate_pct`.

## Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| No se devolvieron pedidos | No hay pedidos en el rango de fechas | Amplía el rango de fechas |
| `variant` es null en una línea de pedido | El producto o la variante se eliminó | Igual se suma por título; product_id quedará en null |
| Límite de solicitudes (429) | Demasiadas solicitudes paginadas | Acorta el rango de fechas |

## Buenas prácticas
1. En tiendas con muchos pedidos, empieza con una ventana de 30 días. Las ventanas más amplias requieren mucha más paginación y tardan más.
2. `sort_by: refund_rate` resalta productos con problemas de calidad o de expectativas: vale la pena investigar una tasa de reembolso superior al 10 %.
3. Los ingresos se muestran brutos (antes de reembolsos) y netos (después de reembolsos): usa los ingresos netos para un ranking de rentabilidad preciso.
4. Los productos eliminados igual aparecen si se compraron dentro del rango de fechas: se muestran con `product_id: null` y con el título que quedó en la línea del pedido.
5. Combínala con `shopify-comparar-codigos-descuento` para ver qué códigos de descuento generaron más ingresos en tus productos estrella.
