---
name: shopify-fraude-devoluciones
description: "Encuentra clientes con devoluciones fuera de lo normal (tasa de devolución alta, usar y devolver o devoluciones en serie) para que los revises a mano. Úsala antes de aprobar devoluciones dudosas. Solo lee y nunca bloquea a nadie."
---

## Propósito
Muestra los clientes cuyo comportamiento de devolución se aleja estadísticamente del promedio de la tienda, para que soporte y operaciones los revisen antes de aprobar la siguiente devolución. Detecta tres patrones: (1) tasa de devolución alta (≥40% de los pedidos devueltos), (2) «wardrobing» (usar y devolver): devoluciones del pedido completo poco después de la entrega, (3) devolvedores en serie: muchas devoluciones a lo largo del tiempo. Solo lectura. El resultado es una lista de candidatos, no una lista de bloqueo automática.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| format | string | no | human | Formato de salida: `human` o `json` |
| days_back | integer | no | 365 | Ventana de días de pedidos y devoluciones |
| min_orders | integer | no | 3 | Mínimo de pedidos históricos para evaluar a un cliente (evita castigar errores aislados) |
| return_rate_threshold | float | no | 0.40 | Fracción de pedidos devueltos a partir de la cual la tasa se marca como alta (predeterminado 40%) |
| wardrobing_window_days | integer | no | 14 | Días entre la entrega y el inicio de la devolución para marcarla como wardrobing |
| serial_threshold | integer | no | 5 | Mínimo de devoluciones totales para marcar a alguien como devolvedor en serie |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta mutaciones. El resultado marca candidatos solo para revisión humana: nunca bloquees ni restrinjas clientes de forma automática. Los falsos positivos son comunes (problemas reales de talla, devoluciones por corrección de dirección, etc.); investiga antes de actuar.

## Pasos

1. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: "created_at:>='<NOW - days_back days>'"`, `first: 250`, selecciona `id`, `customer { id }`, `processedAt`, `fulfillments { deliveredAt }`, `totalPriceSet`, `lineItems { quantity }` y pagina
   **Resultado esperado:** Todos los pedidos de la ventana agrupados por `customer.id`

2. **OPERACIÓN:** `returns` — consulta
   **Entradas:** El mismo filtro de fecha, `first: 250`, selecciona `id`, `createdAt`, `order { customer { id } }`, `returnLineItems { quantity }`, `totalQuantity`
   **Resultado esperado:** Todas las devoluciones de la ventana unidas a su cliente

3. **OPERACIÓN:** `customers` — consulta
   **Entradas:** Solo para los candidatos marcados: `query: "id:<ids>"`, selecciona los campos de identidad y `tags`
   **Resultado esperado:** Los datos de contacto para la lista de candidatos

4. Para cada cliente calcula `total_orders`, `total_returns`, `return_rate` y `wardrobing_count` (devoluciones dentro de los `wardrobing_window_days` posteriores a la entrega en las que Σ cantidad devuelta ≥ Σ cantidad pedida). Reglas para marcar: `high_return_rate` (pedidos ≥ `min_orders` Y tasa ≥ `return_rate_threshold`), `wardrobing` (conteo ≥ 2), `serial_returner` (devoluciones ≥ `serial_threshold`).

## Operaciones GraphQL

```graphql
# orders:query — validado con api_version 2025-01
query OrdersForReturnFraud($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        processedAt
        displayFulfillmentStatus
        totalPriceSet { shopMoney { amount currencyCode } }
        customer { id }
        lineItems(first: 50) {
          edges { node { id quantity } }
        }
        fulfillments {
          deliveredAt
          status
          displayStatus
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}
```

```graphql
# returns:query — validado con api_version 2025-01
query ReturnsForFraud($query: String!, $after: String) {
  returns(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        status
        createdAt
        totalQuantity
        order { id name customer { id } }
        returnLineItems(first: 50) {
          edges { node { id quantity returnReason } }
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}
```

```graphql
# customers:query — validado con api_version 2025-01
query CustomerContactBatch($query: String!) {
  customers(first: 250, query: $query) {
    edges {
      node {
        id
        displayName
        firstName
        lastName
        defaultEmailAddress { emailAddress }
        phone
        numberOfOrders
        amountSpent { amount currencyCode }
        tags
      }
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Detecta abuso de devoluciones        ║
║  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):
```
══════════════════════════════════════════════
CANDIDATOS A FRAUDE EN DEVOLUCIONES  (<days_back> días)
  Clientes evaluados:       <n>
  Candidatos marcados:      <n>

  Por regla:
    Tasa de devolución alta (≥<pct>%):  <n>
    Patrón de usar y devolver:          <n>
    Devolvedor en serie (≥<n>):         <n>

  Principales sospechosos (por riesgo combinado):
    <nombre>  <correo>  Pedidos: <n>  Devoluciones: <n>  Tasa: <pct>%  Marcas: <lista>
  Archivo: return_fraud_candidates_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-fraude-devoluciones",
  "store": "<dominio>",
  "period_days": 365,
  "customers_evaluated": 0,
  "flagged_candidates": 0,
  "by_rule": {
    "high_return_rate": 0,
    "wardrobing": 0,
    "serial_returner": 0
  },
  "output_file": "return_fraud_candidates_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `return_fraud_candidates_<AAAA-MM-DD>.csv` con las columnas:
`customer_id`, `name`, `email`, `phone`, `total_orders`, `total_returns`, `return_rate_pct`, `wardrobing_count`, `flags`, `lifetime_spend`, `last_return_date`, `tags`

## 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 sin cliente | Compra como invitado | Omítelo: no se pueden vincular varios pedidos a un invitado |
| Devolución sin `order.customer` | Datos anonimizados o eliminados | Omite la devolución |
| Falta `deliveredAt` | El pedido todavía no se ha entregado | No apliques la marca de wardrobing a ese pedido |

## Buenas prácticas
- Trata el resultado como una lista de casos por revisar, nunca como una acción automática: valida a mano antes de etiquetar o restringir cualquier cuenta.
- Ajusta `return_rate_threshold` al promedio de tu categoría. Las tiendas de ropa tienen tasas de devolución del 20–30%; marcar desde el 40% detecta los casos atípicos. En electrónica o artículos para el hogar, bájalo a 15–20%.
- Crúzalo con `shopify-motivos-devolucion`: si las devoluciones se concentran en un producto, el problema puede ser de calidad y no de abuso.
- Combínalo con `shopify-clientes-duplicados` y `shopify-unir-clientes`: quienes cometen fraude suelen crear cuentas duplicadas para esquivar las marcas por tasa de devolución.
- Ejecútala cada trimestre con una ventana de 12 meses para obtener una señal estable; las ejecuciones mensuales generan marcas poco confiables por clientes nuevos con una sola devolución.
