---
name: shopify-mensajes-de-regalo
description: "Saca los mensajes de regalo, los destinatarios y las marcas de regalo de los pedidos pendientes para que tu equipo de despacho los imprima y los incluya en el paquete. Úsala antes de cada ronda de alistamiento, sobre todo en temporadas de regalos. Solo lee, no cambia nada."
---

## Propósito
Extrae los mensajes de regalo, los nombres de los destinatarios y las marcas "is_gift" de los atributos personalizados y las notas de los pedidos que están pendientes o en proceso de despacho. Genera una sola hoja que el equipo de despacho puede usar para imprimir tarjetas o insertos de regalo y enrutar bien los pedidos de regalo. 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., tu-tienda.myshopify.com) |
| days_back | integer | no | 7 | Ventana de días de pedidos a revisar |
| status | string | no | unfulfilled | Filtro por estado del pedido: `unfulfilled`, `partial`, `any` |
| message_keys | array | no | `["gift_message","gift_note","Gift Message","Gift Note","message","note_to_recipient"]` | Claves de atributos personalizados (sin importar mayúsculas o minúsculas) que pueden contener un mensaje de regalo |
| recipient_keys | array | no | `["gift_recipient","recipient_name","Gift Recipient","To"]` | Claves de atributos personalizados que pueden contener el nombre del destinatario |
| flag_keys | array | no | `["is_gift","gift","Gift Wrap","gift_wrap"]` | Claves de atributos personalizados cuya presencia o valor marca un pedido como regalo |
| include_order_note | bool | no | true | Revisa también el campo `note` del pedido en busca de mensajes de regalo escritos como texto libre |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta mutaciones. El resultado puede contener textos personales escritos por los clientes: maneja el CSV con el mismo cuidado que cualquier exportación de datos de clientes.

## Reglas de detección

Para cada pedido:

1. **Atributos personalizados**: para cada `lineItem.customAttributes` y `order.customAttributes`:
   - Si la `key` (sin importar mayúsculas o minúsculas) ∈ `message_keys` → guárdala como `gift_message`
   - Si la `key` ∈ `recipient_keys` → guárdala como `gift_recipient`
   - Si la `key` ∈ `flag_keys` Y el valor es verdadero (`true`, `yes`, `1`, texto no vacío) → marca `is_gift: true`
2. **Nota del pedido**: si `include_order_note: true` y `order.note` coincide con `/gift|recipient|deliver to|message:/i`, guarda la nota como `note_hint`
3. Un pedido entra en el reporte si `is_gift: true` O se capturó un `gift_message` O se capturó un `gift_recipient`

## Pasos

1. Calcula el filtro: `created_at:>='<NOW - days_back days>'` y convierte `status` → `fulfillment_status:unfulfilled` / `:partial` / sin filtro

2. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: <filter>`, `first: 250`, selecciona `name`, `note`, `customAttributes { key, value }`, `lineItems { name, quantity, customAttributes { key, value } }`, `shippingAddress`, `customer { displayName, defaultEmailAddress { emailAddress } }` y el cursor de paginación
   **Resultado esperado:** Los pedidos candidatos

3. Aplica las reglas de detección a cada pedido

4. Arma las filas del reporte: una por cada pedido que califica, con sus artículos para que quien empaca sepa qué envolver

## Operaciones GraphQL

```graphql
# orders:query — validado con api_version 2025-01
query OrdersForGiftExtraction($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        createdAt
        note
        displayFulfillmentStatus
        customAttributes {
          key
          value
        }
        shippingAddress {
          firstName
          lastName
          address1
          address2
          city
          provinceCode
          countryCodeV2
          zip
          phone
        }
        customer {
          id
          displayName
          defaultEmailAddress {
            emailAddress
          }
        }
        lineItems(first: 50) {
          edges {
            node {
              id
              name
              quantity
              sku
              customAttributes {
                key
                value
              }
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Extrae los mensajes de regalo        ║
║  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):
```
══════════════════════════════════════════════
EXTRACCIÓN DE MENSAJES DE REGALO  (<days_back> días, estado: <status>)
  Pedidos revisados:        <n>
  Pedidos de regalo:        <n>
   ↳ Con mensaje:           <n>
   ↳ Con destinatario:      <n>
   ↳ Solo con la marca:     <n>
  Hallados en la nota:      <n>

  Archivo: gift_messages_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-mensajes-de-regalo",
  "store": "<dominio>",
  "period_days": 7,
  "orders_scanned": 0,
  "gift_orders": 0,
  "with_message": 0,
  "with_recipient": 0,
  "flag_only": 0,
  "from_order_note": 0,
  "output_file": "gift_messages_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `gift_messages_<AAAA-MM-DD>.csv` con las columnas:
`order_name`, `created_at`, `is_gift`, `gift_recipient`, `gift_message`, `note_hint`, `ship_to_name`, `ship_to_address`, `line_items_summary`, `customer_email`

`line_items_summary` es una lista `qty × title` unida con `; `.

## 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 |
| Las claves de los atributos cambian de nombre según el tema | Distintas plantillas de la tienda escriben claves diferentes | Quien ejecuta la skill puede ampliar `message_keys` / `recipient_keys` / `flag_keys` |
| HTML codificado en los mensajes | La tienda guardó entidades HTML | Decodifica `&amp;`, `&#39;`, `&quot;` antes de imprimir |
| Mensajes de varias líneas | El cliente presionó Enter dentro del campo | Las celdas del CSV pueden contener saltos de línea: ponles comillas correctamente al exportar |

## Buenas prácticas
- Ejecútala dos veces al día, en la ronda de alistamiento de la mañana y en la de la tarde: los mensajes de regalo son urgentes y olvidar uno arruina la experiencia.
- Compara los nombres de las claves de atributos con la forma en que tu tema implementa el mensaje de regalo; amplía `message_keys` / `recipient_keys` si tu tema usa claves distintas a las predeterminadas.
- En las temporadas fuertes de regalos (Día de la Madre, San Valentín, diciembre), amplía `days_back` a 14 y cambia a `status: any` para incluir los pedidos que ya están en preparación.
- Trata el CSV como datos personales: los mensajes de regalo pueden contener sentimientos íntimos. Limita el acceso al personal de despacho que lo necesita.
- Ordena el resultado por `ship_to_address` para que quienes empacan puedan juntar todos los pedidos de regalo que van a la misma dirección.
