---
name: shopify-limpiar-descuentos
description: "Encuentra códigos de descuento vencidos, sin uso o duplicados y, si quieres, los elimina. Úsala cuando la lista de Descuentos esté llena de códigos viejos de campañas pasadas."
---

## Propósito
Revisa el catálogo de descuentos en busca de códigos vencidos, códigos que nunca se han usado y prefijos de código duplicados. Los descuentos se acumulan tras meses de campañas y hacen difícil moverse por el admin. De forma opcional, elimina los códigos marcados. Reemplaza la limpieza manual de descuentos y complementa la skill `shopify-comparar-codigos-descuento` con un paso que escribe en la tienda.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., mitienda.myshopify.com) |
| flag_expired | bool | no | true | Marca o elimina los descuentos cuya fecha de fin ya pasó |
| flag_zero_usage | bool | no | true | Marca o elimina los descuentos con 0 usos que tengan más de N días |
| zero_usage_min_age_days | integer | no | 30 | Antigüedad mínima para marcar un descuento sin uso |
| dry_run | bool | no | true | Muestra una vista previa sin ejecutar mutaciones |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ⚠️ `discountCodeDelete` elimina códigos de descuento de forma permanente. Los códigos eliminados no se pueden recuperar. Los clientes que recibieron un código eliminado lo encontrarán inválido. Ejecuta con `dry_run: true` para revisar la lista de marcados antes de confirmar. Antes de eliminar, verifica siempre que los códigos vencidos no aparezcan en campañas de correo activas.

## Pasos

1. **OPERACIÓN:** `discountNodes` — consulta
   **Entradas:** `first: 250`, selecciona `discount { ... on DiscountCodeBasic { codes, usageLimit, asyncUsageCount, endsAt, status } }` y el cursor de paginación
   **Resultado esperado:** Todos los códigos de descuento con sus datos de uso y vencimiento; pagina hasta `hasNextPage: false`

2. Marca los descuentos que cumplan: `flag_expired` (status = EXPIRED) y/o `flag_zero_usage` (asyncUsageCount == 0 Y creado hace más de `zero_usage_min_age_days` días)

3. **OPERACIÓN:** `discountCodeDelete` — mutación
   **Entradas:** `id: <discount_node_id>`
   **Resultado esperado:** `deletedCodeDiscountId`, `userErrors`

## Operaciones GraphQL

```graphql
# discountNodes:query — validada con api_version 2025-01
query DiscountAudit($after: String) {
  discountNodes(first: 250, after: $after) {
    edges {
      node {
        id
        discount {
          ... on DiscountCodeBasic {
            title
            status
            createdAt
            endsAt
            asyncUsageCount
            usageLimit
            codes(first: 5) {
              edges {
                node {
                  id
                  code
                }
              }
            }
          }
          ... on DiscountCodeBxgy {
            title
            status
            createdAt
            endsAt
            asyncUsageCount
            usageLimit
          }
          ... on DiscountCodeFreeShipping {
            title
            status
            createdAt
            endsAt
            asyncUsageCount
            usageLimit
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

```graphql
# discountCodeDelete:mutation — validada con api_version 2025-01
mutation DiscountCodeDelete($id: ID!) {
  discountCodeDelete(id: $id) {
    deletedCodeDiscountId
    userErrors {
      field
      message
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Limpieza de descuentos               ║
║  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>
```

Si `dry_run: true`, antepón `[SIMULACIÓN]` a cada paso de mutación y no lo ejecutes.

**Al terminar**, muestra:

Para `format: human` (predeterminado):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  Descuentos revisados:      <n>
  Vencidos:                  <n>
  Sin uso (> <n> días):      <n>
  Total marcados:            <n>
  Eliminados:                <n>
  Errores:                   <n>
  Archivo:                   discount_cleanup_<date>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-limpiar-descuentos",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "dry_run": true,
  "outcome": {
    "scanned": 0,
    "flagged_expired": 0,
    "flagged_zero_usage": 0,
    "deleted": 0,
    "errors": 0,
    "output_file": "discount_cleanup_<date>.csv"
  }
}
```

## Formato de salida
Archivo CSV `discount_cleanup_<YYYY-MM-DD>.csv` con las columnas:
`discount_id`, `title`, `status`, `created_at`, `ends_at`, `usage_count`, `usage_limit`, `flag_reason`, `action`

## 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 |
| `userErrors` al eliminar | El descuento ya se eliminó o lo está usando un pedido activo | Registra el error, omítelo y continúa |
| Ningún descuento marcado | El catálogo de descuentos está limpio | Termina con ✅ no hace falta limpiar |

## Buenas prácticas
- Ejecútala cada trimestre: los códigos de descuento se acumulan rápido con las campañas de temporada.
- Consulta con tu equipo de email marketing antes de eliminar códigos sin uso: pueden estar en una campaña programada que todavía no ha salido.
- Mantén la antigüedad de `flag_zero_usage` en 30 días o más para no eliminar códigos de campañas recién lanzadas.
- Esta skill no limpia los descuentos automáticos o de porcentaje (los que no usan código): esos se administran por separado.
