---
name: shopify-encuesta-poscompra
description: "Solo lectura: identifica los pedidos preparados hace 7 a 14 días que sirven para una campaña de encuesta poscompra, sin incluir pedidos reembolsados ni cancelados. Úsala cuando quieras armar la lista de clientes a quienes enviarles la encuesta."
---

## Propósito
Arma la lista de destinatarios de una campaña de encuesta poscompra seleccionando los pedidos que se prepararon hace entre `survey_min_days` y `survey_max_days` días, que no están reembolsados ni cancelados y que (opcionalmente) son de clientes que aceptaron recibir marketing. El resultado es una lista depurada de destinatarios que puedes cargar directamente en tu automatización de correo o SMS. Solo lectura: no ejecuta mutaciones.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| survey_min_days | integer | no | 7 | Mínimo de días después de la preparación para encuestar (da tiempo para la entrega y el primer uso) |
| survey_max_days | integer | no | 14 | Máximo de días después de la preparación para encuestar (el recuerdo se desvanece después de unas 2 semanas) |
| marketing_consent_only | bool | no | true | Limita a clientes con `marketingState: SUBSCRIBED` |
| exclude_repeat_recipients_days | integer | no | 90 | Omite a los clientes que ya estuvieron en una lista de encuesta dentro de esta ventana (el control lo lleva quien ejecuta la skill) |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta mutaciones. La skill produce una lista de destinatarios; enviar la encuesta desde tu propia plataforma de correo o SMS te corresponde a ti. Respeta `marketing_consent_only: true` en las encuestas promocionales para cumplir las normas de consentimiento.

## Pasos

1. Calcula la ventana: `latest_fulfilled_at = NOW - survey_min_days`, `earliest_fulfilled_at = NOW - survey_max_days`

2. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: "fulfillment_status:fulfilled financial_status:paid -status:cancelled updated_at:>=<earliest_fulfilled_at>"`, `first: 250`, selecciona `displayFulfillmentStatus`, `displayFinancialStatus`, `cancelledAt`, `fulfillments { createdAt, displayStatus, deliveredAt }`, `refunds { id, createdAt }`, `customer { id, defaultEmailAddress { emailAddress, marketingState }, displayName, locale }`, cursor de paginación
   **Resultado esperado:** Todos los pedidos candidatos; pagina hasta `hasNextPage: false`

3. Filtra los pedidos a la ventana de la encuesta usando el `createdAt` de la **primera preparación**:
   - Omite el pedido si `fulfilled_at` queda fuera de `[earliest_fulfilled_at, latest_fulfilled_at]`
   - Omítelo si `cancelledAt != null`
   - Omítelo si se emitió algún reembolso (total o parcial)
   - Omítelo si el cliente es null (pedido como invitado sin correo)
   - Si `marketing_consent_only: true`, omítelo si `marketingState != SUBSCRIBED`

4. Quita duplicados por correo del cliente: varios pedidos del mismo cliente se reducen a una sola invitación a la encuesta

5. Entrega la lista de destinatarios

## Operaciones GraphQL

```graphql
# orders:query — validada con api_version 2025-01
query SurveyEligibleOrders($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        createdAt
        cancelledAt
        displayFinancialStatus
        displayFulfillmentStatus
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        fulfillments(first: 5) {
          id
          createdAt
          displayStatus
          deliveredAt
        }
        refunds {
          id
          createdAt
        }
        customer {
          id
          displayName
          locale
          defaultEmailAddress {
            emailAddress
            marketingState
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔════════════════════════════════════════════════╗
║  SKILL: Pedidos listos para encuesta poscompra ║
║  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):
```
══════════════════════════════════════════════
LISTA PARA ENCUESTA POSCOMPRA
  Ventana:                      <survey_min_days>–<survey_max_days> días después de la preparación
  Pedidos considerados:         <n>
  Reembolsados (excluidos):     <n>
  Cancelados (excluidos):       <n>
  Sin consentimiento (excl.):   <n>
  Pedidos de invitado (excl.):  <n>
  ─────────────────────────────
  Destinatarios elegibles:      <n>
  Archivo: post_purchase_survey_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-encuesta-poscompra",
  "store": "<dominio>",
  "window_min_days": 7,
  "window_max_days": 14,
  "orders_considered": 0,
  "excluded": { "refunded": 0, "cancelled": 0, "no_consent": 0, "guest": 0 },
  "eligible_recipients": 0,
  "output_file": "post_purchase_survey_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `post_purchase_survey_<AAAA-MM-DD>.csv` con las columnas:
`customer_id`, `email`, `name`, `locale`, `order_name`, `order_total`, `currency`, `fulfilled_at`, `delivered_at`, `days_since_fulfilled`

## 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 |
| Pedido con varias preparaciones | Envío dividido | Usa el `createdAt` más antiguo para calcular la ventana; indícalo en el CSV como `multi_fulfillment: true` |
| `deliveredAt` es null | La transportadora no reportó la entrega | Usa `fulfillments.createdAt` como aproximación (puede quedarse un poco corta o pasarse) |
| Cliente sin correo | Perfil solo con teléfono | Omítelo: las campañas de encuesta asumen el canal de correo |

## Buenas prácticas
- Envía la encuesta entre 7 y 14 días después de la preparación: 7 días alcanzan para la entrega y el primer uso, y 14 días es el punto ideal antes de que el recuerdo se desvanezca.
- En categorías de alto costo o de compra muy pensada (muebles, electrónica), amplía `survey_max_days` a 30: los clientes se forman una opinión más tarde.
- Combínala con `shopify-cohortes-clientes` para comparar la retención de quienes responden la encuesta frente a quienes no: los que responden suelen ser tu cohorte más fiel.
- Nunca incluyas a clientes con pedidos reembolsados o cancelados: encuestarlos atrae quejas, no comentarios que puedas aprovechar.
- Programa esta skill para que corra a diario y carga el CSV directamente en tu automatización de correo; una frecuencia manual arruina la segmentación por ventana de tiempo.
