---
name: shopify-vigilancia-contracargos
description: "Encuentra a los clientes con pedidos disputados o con contracargo y etiqueta su ficha para revisar con cuidado sus próximos pedidos. Úsala cuando quieras reducir pérdidas repetidas por contracargos sin bloquear clientes."
---

## Propósito
Revisa los pedidos históricos en busca de cualquier contracargo o disputa asociada y etiqueta la ficha del cliente con `chargeback-history` (configurable). Así, el equipo de operaciones puede filtrar los próximos pedidos de estos clientes o retenerlos para revisión manual. Reduce las pérdidas repetidas por contracargos sin bloquear a los clientes de entrada. Por defecto usa `dry_run: true`.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., mitienda.myshopify.com) |
| days_back | integer | no | 730 | Período histórico en el que se buscan disputas (2 años por defecto) |
| watchlist_tag | string | no | chargeback-history | Etiqueta que se aplica a los clientes marcados |
| include_won_disputes | bool | no | false | Si es false, solo etiqueta a los clientes con disputas perdidas o abiertas |
| dry_run | bool | no | true | Muestra una vista previa sin aplicar etiquetas |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ⚠️ `customerUpdate` modifica etiquetas de clientes que ve tu equipo y que pueden activar reglas de segmentación. Si etiquetas mal a un cliente, puedes empeorar su experiencia o bloquear sus pedidos. Ejecuta primero con `dry_run: true` y revisa la lista antes de confirmar. Las disputas ganadas (las que ganó la tienda) se excluyen por defecto para evitar falsos positivos.

## Pasos

1. **OPERACIÓN:** `orders` — consulta
   **Entradas:** `query: "created_at:>='<NOW - days_back days>' chargeback_status:*"` (cualquier estado de contracargo), `first: 250`, selecciona `disputes { id, status, initiatedAs, finalizedOn }`, `customer { id, displayName, tags, defaultEmailAddress { emailAddress } }`, `totalPriceSet` y el cursor de paginación
   **Resultado esperado:** Todos los pedidos que tienen al menos una disputa en el período

2. Agrupa las disputas por cliente. Para cada cliente:
   - Omítelo si todas sus disputas tienen estado `WON` y `include_won_disputes: false`
   - Omítelo si ya tiene la `watchlist_tag`
   - Si no, agrégalo a la cola de etiquetado

3. **OPERACIÓN:** `customerUpdate` — mutación
   **Entradas:** `input: { id, tags: [<existing tags>, watchlist_tag] }` para cada cliente en la cola
   **Resultado esperado:** Cliente actualizado con la nueva lista de etiquetas; `userErrors`

4. Si `dry_run: true`, no llames la mutación: solo reporta la cola.

## Operaciones GraphQL

```graphql
# orders:query — validada con api_version 2025-01
query OrdersWithDisputes($query: String!, $after: String) {
  orders(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        name
        createdAt
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        disputes {
          id
          status
          initiatedAs
          finalizedOn
        }
        customer {
          id
          displayName
          defaultEmailAddress {
            emailAddress
          }
          numberOfOrders
          amountSpent {
            amount
            currencyCode
          }
          tags
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

```graphql
# customerUpdate:mutation — validada con api_version 2025-01
mutation TagChargebackCustomer($input: CustomerInput!) {
  customerUpdate(input: $input) {
    customer {
      id
      tags
    }
    userErrors {
      field
      message
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Vigilancia de contracargos           ║
║  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):
```
══════════════════════════════════════════════
VIGILANCIA DE CONTRACARGOS  (<days_back> días)
  Pedidos con disputas:         <n>
  Clientes únicos:              <n>
  Disputas perdidas/abiertas:   <n>
  Disputas ganadas (excluidas): <n>
  Ya etiquetados:               <n>
  ─────────────────────────────
  Clientes por etiquetar:       <n>
  Etiquetas aplicadas:          <n>   (o [SIMULACIÓN] se aplicarían)
  Errores:                      <n>
  Archivo: chargeback_watchlist_<date>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-vigilancia-contracargos",
  "store": "<dominio>",
  "dry_run": true,
  "orders_with_disputes": 0,
  "unique_customers": 0,
  "customers_to_tag": 0,
  "tags_applied": 0,
  "errors": 0,
  "output_file": "chargeback_watchlist_<date>.csv"
}
```

## Formato de salida
Archivo CSV `chargeback_watchlist_<YYYY-MM-DD>.csv` con las columnas:
`customer_id`, `email`, `name`, `dispute_count`, `latest_dispute_status`, `latest_dispute_initiated_as`, `total_disputed_amount`, `currency`, `existing_tags`, `tag_to_apply`, `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` en customerUpdate | Cliente no encontrado o archivado | Registra el error, omítelo y continúa |
| Pedido sin cliente | Disputa de una compra como invitado | No se puede etiquetar: regístralo en el CSV con `action: skipped_guest` |
| Disputa con estado `null` | Disputa muy reciente, aún sin clasificar | Trátala como abierta / no ganada |

## Buenas prácticas
- Empieza siempre con `dry_run: true` y revisa el CSV: los falsos positivos dañan la confianza de los clientes.
- Combina la `watchlist_tag` con un flujo de Shopify Flow o una regla de enrutamiento de pedidos que retenga los pedidos nuevos de clientes etiquetados hasta que alguien los apruebe.
- Repítela cada trimestre para mantener la lista al día: los patrones de contracargos cambian a medida que crecen tu tienda y tu base de clientes.
- Deja `include_won_disputes: false` (predeterminado). Si ganaste, el banco falló a tu favor: no castigues al cliente.
- Con los reincidentes (varias disputas), considera ir más allá de una etiqueta: revisa manualmente antes de aceptarles más pedidos.
