---
name: shopify-comparar-codigos-descuento
description: "Solo lectura: compara dos o más códigos de descuento por usos, pedidos, ingresos y ticket promedio en un rango de fechas. Úsala al cerrar una campaña para decidir qué oferta repetir."
---

## Propósito
Compara cómo rinden distintos códigos de descuento entre sí, según la cantidad de usos y los ingresos que generan. Sirve para hacer pruebas A/B de ofertas promocionales sin una app de analítica dedicada: indica dos o más códigos y un rango de fechas, y la skill consulta en Shopify los datos de cada descuento y los ingresos de los pedidos, y arma una tabla comparativa lado a lado. Solo lectura: no ejecuta mutaciones.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | texto | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| format | texto | no | human | Formato de salida: `human` o `json` |
| dry_run | booleano | no | false | Muestra las operaciones sin ejecutar mutaciones |
| discount_codes | lista | sí | — | Lista de 2 o más códigos de descuento para comparar (p. ej., `["SAVE10", "WELCOME15"]`) |
| date_range_start | texto | sí | — | Fecha de inicio en ISO 8601 (p. ej., `2025-01-01`) |
| date_range_end | texto | sí | — | Fecha de fin en ISO 8601 (p. ej., `2025-01-31`) |

## Pasos

1. **OPERACIÓN:** `discountNodes` — consulta
   **Entradas:** `first: 50`, `query: "code:<code>"` (una consulta por cada código de `discount_codes`)
   **Resultado esperado:** Datos de cada descuento: título, códigos, `asyncUsageCount`, estado, `startsAt` y `endsAt` por código

2. **OPERACIÓN:** `orders` — consulta (una consulta paginada por cada código de descuento)
   **Entradas:** `first: 250`, `query: "discount_code:<code> created_at:>='<date_range_start>' created_at:<='<date_range_end>'"` y el cursor de paginación
   **Resultado esperado:** Pedidos en los que se usó el código, con `totalPriceSet`; pagina hasta que `hasNextPage: false`; totaliza: cantidad de pedidos, suma de ingresos y ticket promedio

## Operaciones GraphQL

```graphql
# discountNodes:query — validada con api_version 2025-01
query DiscountNodes($first: Int!, $query: String) {
  discountNodes(first: $first, query: $query) {
    edges {
      node {
        id
        discount {
          ... on DiscountCodeBasic {
            title
            codes(first: 10) {
              edges {
                node {
                  code
                  asyncUsageCount
                }
              }
            }
            usageLimit
            status
            startsAt
            endsAt
          }
          ... on DiscountCodeBxgy {
            title
            codes(first: 10) {
              edges {
                node {
                  code
                  asyncUsageCount
                }
              }
            }
            status
          }
          ... on DiscountCodeFreeShipping {
            title
            codes(first: 10) {
              edges {
                node {
                  code
                  asyncUsageCount
                }
              }
            }
            status
          }
        }
      }
    }
  }
}
```

```graphql
# orders:query (por código de descuento) — validada con api_version 2025-01
query OrdersByDiscountCode($first: Int!, $after: String, $query: String) {
  orders(first: $first, after: $after, query: $query) {
    edges {
      node {
        id
        createdAt
        totalPriceSet {
          shopMoney { amount currencyCode }
        }
        discountCodes
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: shopify-comparar-codigos-descuento   ║
║  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):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  Códigos analizados:   <n>
  Rango de fechas:      <inicio> a <fin>
  Errores:              0
  Archivo:              ninguno
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-comparar-codigos-descuento",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "completed_at": "<ISO8601>",
  "dry_run": false,
  "steps": [
    { "step": 1, "operation": "DiscountNodes", "type": "query", "params_summary": "<n> códigos consultados", "result_summary": "<n> descuentos encontrados", "skipped": false },
    { "step": 2, "operation": "OrdersByDiscountCode", "type": "query", "params_summary": "rango de fechas <inicio> a <fin>", "result_summary": "<n> pedidos totalizados", "skipped": false }
  ],
  "outcome": {
    "codes_analyzed": 0,
    "date_range_start": "<inicio>",
    "date_range_end": "<fin>",
    "results": [
      {
        "code": "SAVE10",
        "async_usage_count": 0,
        "orders_in_range": 0,
        "total_revenue": "0.00",
        "avg_order_value": "0.00",
        "revenue_per_use": "0.00"
      }
    ],
    "errors": 0,
    "output_file": null
  }
}
```

## Formato de salida

Una tabla comparativa por código (se muestra en la respuesta):

| Código | Usos (asyncUsageCount) | Pedidos en el rango | Ingresos totales | Ticket promedio | Ingresos por uso |
|--------|------------------------|---------------------|------------------|-----------------|------------------|
| SAVE10 | ... | ... | ... | ... | ... |
| WELCOME15 | ... | ... | ... | ... | ... |

Para `format: json`, el arreglo `results` trae un objeto por código con las claves: `code`, `async_usage_count`, `orders_in_range`, `total_revenue`, `avg_order_value`, `revenue_per_use`.

## Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| No se encuentra el código de descuento | El código no existe o se eliminó | Verifica el código en el panel de Shopify |
| Ningún pedido para un código | Ningún pedido usó ese código en el rango de fechas | Amplía el rango de fechas o verifica que el código estuviera activo |
| `discount_codes` tiene menos de 2 códigos | No se puede hacer una prueba A/B con 1 solo código | Indica al menos 2 códigos |
| Límite de solicitudes (429) | Demasiadas consultas paginadas de pedidos | Espera y reintenta; acorta el rango de fechas |

## Buenas prácticas
1. `asyncUsageCount` es la cantidad de usos de toda la vida del descuento; `orders_in_range` es lo que se canjeó dentro de tu rango de fechas. Se reportan los dos para tener el contexto completo.
2. En códigos con muchos usos, la consulta de pedidos se pagina: los rangos de fechas amplios pueden generar muchas llamadas a la API. Considera acortar el rango para obtener resultados más rápido.
3. Los ingresos por uso son la mejor señal para comparar códigos que tienen volúmenes de uso distintos.
4. Haz este análisis al cerrar una campaña, antes de decidir qué estrategia de descuento repetir.
5. Si `asyncUsageCount` es 0 para un código, revisa que el código estuviera activo en el rango de fechas y que se haya aplicado bien en el checkout.
