---
name: shopify-pasivo-tarjetas-regalo
description: "Solo lectura: calcula el saldo total pendiente de las tarjetas de regalo como pasivo financiero, desglosado por mes de emisión y por rango de saldo. Úsala al cierre contable para saber cuánto le debes en productos a quienes tienen tarjetas sin usar."
---

## Propósito
Calcula el pasivo total pendiente por tarjetas de regalo de la tienda: la suma de los saldos no redimidos, que representan una obligación futura de entregar productos. Desglosa el pasivo por **cohorte de mes de emisión** y por **rango de saldo restante** para que el área de finanzas pueda dimensionar la obligación, ver su antigüedad y proyectar el saldo que nunca se redimirá (breakage). Es el complemento contable de `shopify-saldos-tarjetas-regalo` (que lista las tarjetas una por una). Solo lectura: no hace cambios.

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

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., mitienda.myshopify.com) |
| status | string | no | enabled | Filtra por estado: `enabled`, `disabled` o `all` |
| balance_bands | array | no | `[10, 50, 100, 250, 500]` | Límites superiores de los rangos de saldo (en la moneda de la tienda) para la tabla de distribución |
| stale_days | integer | no | 365 | Las tarjetas sin movimiento por más de estos días se marcan como candidatas a breakage |
| as_of | string | no | hoy (UTC) | Fecha ISO para la etiqueta de «fecha de corte» del reporte |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ℹ️ Skill de solo lectura: no ejecuta cambios. La cifra que produce es el pasivo por ingresos diferidos para fines contables; revísala con tu contador antes de registrar asientos contables.

## Modelo del pasivo

Para cada tarjeta de regalo activa con `balance > 0`:

1. **Saldo pendiente** = suma de `balance.amount` (el pasivo)
2. **Cohorte de emisión** = año-mes de `createdAt`
3. **Rango de saldo** = el primer límite de rango que sea ≥ al saldo restante, o `>max` para las tarjetas por encima del límite más alto
4. **Candidata a breakage** = tarjeta con `balance > 0` y (`updatedAt` anterior a hace `stale_days` días O `expiresOn` dentro de los próximos 30 días)

Totales que se calculan:
- Total pendiente (general + por cohorte + por rango)
- Cantidad de tarjetas por cohorte y por rango
- Promedio ponderado de días desde la emisión
- Total de candidatas a breakage: útil para el reconocimiento de ingresos bajo ASC 606 / NIIF 15 en tiendas de jurisdicciones donde se permite reconocer el breakage

## Pasos

1. **OPERACIÓN:** `giftCards` — query
   **Entradas:** `query: "status:<status> balance:>0"`, `first: 250`, selecciona `id`, `balance`, `initialValue`, `createdAt`, `updatedAt`, `expiresOn`, `enabled`, `lastCharacters`, cursor de paginación
   **Resultado esperado:** Todas las tarjetas de regalo con saldo positivo; pagina hasta `hasNextPage: false`

2. Para cada tarjeta, calcula la cohorte de emisión, el rango de saldo y la marca de breakage

3. Suma los totales: pasivo general, tabla por cohorte, tabla por rango y subtotal de candidatas a breakage

4. Calcula lo redimido a la fecha como `Σ(initialValue - balance)` como contexto

## Operaciones GraphQL

```graphql
# giftCards:query — validado con api_version 2025-01
query GiftCardLiability($query: String, $after: String) {
  giftCards(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        balance {
          amount
          currencyCode
        }
        initialValue {
          amount
          currencyCode
        }
        enabled
        createdAt
        updatedAt
        expiresOn
        lastCharacters
        customer {
          id
          displayName
          defaultEmailAddress {
            emailAddress
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Pasivo por tarjetas de regalo        ║
║  Tienda: <dominio de la tienda>              ║
║  Fecha de corte: <AAAA-MM-DD>                ║
║  Inicio: <AAAA-MM-DD HH:MM UTC>              ║
╚══════════════════════════════════════════════╝
```

**Después de cada paso**, muestra:
```
[N/TOTAL] <QUERY|MUTATION>  <NombreDeOperación>
          → Parámetros: <resumen breve de las entradas clave>
          → Resultado: <conteo o resultado>
```

**Al terminar**, muestra:

Para `format: human` (predeterminado):
```
══════════════════════════════════════════════
PASIVO POR TARJETAS DE REGALO  (corte al <fecha>)
  Tarjetas activas con saldo:   <n>
  Total pendiente:              <monto>
  Valor inicial emitido:        <monto>
  Redimido a la fecha:          <monto>  (<pct>%)
  Candidatas a breakage:        <n>  (<monto>)

  Por cohorte de emisión (AAAA-MM):
    2024-12  Tarjetas: <n>  Pasivo: <n>
    2025-01  Tarjetas: <n>  Pasivo: <n>

  Por rango de saldo:
    ≤ 10      Tarjetas: <n>  Pasivo: <n>
    ≤ 50      Tarjetas: <n>  Pasivo: <n>
    ≤ 100     Tarjetas: <n>  Pasivo: <n>
    > 500     Tarjetas: <n>  Pasivo: <n>

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

Los montos se expresan en la moneda de la tienda.

Para `format: json`, muestra:
```json
{
  "skill": "shopify-pasivo-tarjetas-regalo",
  "store": "<dominio>",
  "as_of": "<AAAA-MM-DD>",
  "active_with_balance": 0,
  "total_outstanding": 0,
  "initial_value_issued": 0,
  "redeemed_to_date": 0,
  "redemption_rate_pct": 0,
  "breakage_candidates_count": 0,
  "breakage_candidates_value": 0,
  "currency": "<moneda de la tienda>",
  "by_cohort": [],
  "by_band": [],
  "output_file": "gift_card_liability_<fecha>.csv"
}
```

## Formato de salida
Archivo CSV `gift_card_liability_<AAAA-MM-DD>.csv` con las columnas:
`gift_card_id`, `last_characters`, `initial_value`, `balance`, `redeemed`, `currency`, `created_at`, `issue_cohort`, `balance_band`, `updated_at`, `expires_on`, `breakage_candidate`, `customer_email`

## 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 |
| No hay tarjetas de regalo con saldo positivo | La tienda no ha emitido ninguna, o todas se redimieron | Termina con un pasivo de 0 |
| Tarjetas en varias monedas | Tarjetas emitidas en distintas monedas de presentación | Agrupa los totales por código de moneda; no sumes entre monedas |
| Tarjeta con `expiresOn` en `null` | No tiene política de vencimiento | Trátala como sin vencimiento; no la incluyas en el breakage por vencimiento |

## Buenas prácticas
- Córrela el **último día de cada periodo contable** para que la cifra coincida con el cierre de tu balance general.
- El total pendiente es el **pasivo por ingresos diferidos**: regístralo en tu sistema contable y no trates las tarjetas de regalo emitidas como ingresos.
- La política de breakage cambia según la jurisdicción; consulta a tu contador antes de reconocer como ingreso las candidatas a breakage. Las marcas de `stale_days` y `expiresOn` son insumos para esa política, no la reemplazan.
- Sigue la tendencia de la tasa de redención mes a mes: si la redención baja, puede haber un problema en la experiencia del cliente (quienes reciben la tarjeta no la encuentran o no la recuerdan).
- Combínala con `shopify-emitir-tarjetas-regalo` para vigilar el flujo: el pasivo debería subir con las emisiones y bajar con las redenciones + el breakage.
