---
name: shopify-transferir-inventario
description: "Mueve unidades de inventario de una ubicación a otra: descuenta en la de origen y suma en la de destino. Úsala cuando quieras rebalancear stock entre bodegas o tiendas físicas, por ejemplo antes de una promoción."
---

## Propósito
Transfiere una cantidad determinada de inventario de una ubicación de origen a una de destino mediante ajustes de inventario en pareja (resta en el origen, suma en el destino). Sirve para rebalancear entre bodegas, ubicar stock con anticipación antes de una promoción o redistribuir el inventario después de un cambio de ubicación. Reemplaza la transferencia manual de inventario en el admin de Shopify.

## Requisitos
- Sesión autenticada de Shopify CLI: `shopify store auth --store <tu-tienda>.myshopify.com --scopes read_products,write_inventory,read_inventory`
- Las consultas se ejecutan con `shopify store execute`.
- Permisos (scopes) de API: `read_products`, `read_inventory`, `write_inventory`
- Tanto el origen como el destino deben ser ubicaciones activas de Shopify

## Parámetros

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| source_location_id | string | sí | — | GID de la ubicación DESDE la que se mueve el stock |
| destination_location_id | string | sí | — | GID de la ubicación HACIA la que se mueve el stock |
| transfers | array | sí | — | Lista de objetos `{sku, quantity}` que se transfieren |
| dry_run | bool | no | true | Muestra los ajustes sin ejecutar las mutaciones |
| format | string | no | human | Formato de salida: `human` o `json` |

## Seguridad

> ⚠️ `inventoryAdjustQuantities` modifica directamente los niveles de inventario. El origen puede quedar por debajo de cero si la cantidad supera el stock disponible: la skill te avisa, pero Shopify no bloquea los ajustes negativos. Ejecuta con `dry_run: true` para verificar las cantidades disponibles en el origen antes de aplicar cambios. Esto NO crea un registro de orden de transferencia en Shopify; es un ajuste directo.

## Pasos

1. **OPERACIÓN:** `locations` — consulta
   **Entradas:** `first: 50`
   **Resultado esperado:** Todas las ubicaciones con `id` y `name`; valida que existan los ID de origen y destino

2. **OPERACIÓN:** `inventoryItems` — consulta
   **Entradas:** Búsqueda por lotes según el SKU para obtener `inventoryItem.id` de cada SKU que se transfiere
   **Resultado esperado:** Artículos de inventario con sus cantidades actuales en la ubicación de origen

3. Valida: para cada SKU, confirma que `available >= quantity` en el origen. Si no se cumple, avisa, pero continúa si `dry_run: false`

4. **OPERACIÓN:** `inventoryAdjustQuantities` — mutación
   **Entradas:** Dos cambios por SKU: `{ inventoryItemId, locationId: source, delta: -quantity, reason: "correction" }` y `{ inventoryItemId, locationId: destination, delta: +quantity, reason: "correction" }`
   **Resultado esperado:** `inventoryAdjustmentGroup { changes { delta, location } }`, `userErrors`

## Operaciones GraphQL

```graphql
# locations:query — validada con api_version 2025-01
query ActiveLocations {
  locations(first: 50, includeInactive: false) {
    edges {
      node {
        id
        name
        isActive
        fulfillsOnlineOrders
      }
    }
  }
}
```

```graphql
# inventoryItems:query — validada con api_version 2025-01
query InventoryLevelsAtLocation($ids: [ID!]!) {
  nodes(ids: $ids) {
    ... on InventoryItem {
      id
      sku
      inventoryLevels(first: 20) {
        edges {
          node {
            location {
              id
              name
            }
            quantities(names: ["available", "on_hand"]) {
              name
              quantity
            }
          }
        }
      }
    }
  }
}
```

```graphql
# inventoryAdjustQuantities:mutation — validada con api_version 2025-01
mutation InventoryAdjustQuantities($input: InventoryAdjustQuantitiesInput!) {
  inventoryAdjustQuantities(input: $input) {
    inventoryAdjustmentGroup {
      createdAt
      reason
      changes {
        delta
        quantityAfterChange
        item {
          id
          sku
        }
        location {
          id
          name
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

## Seguimiento de la sesión

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

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: Mueve inventario entre bodegas       ║
║  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):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  SKU transferidos:                 <n>
  Unidades movidas en total:        <n>
  Advertencias (stock insuficiente): <n>
  Errores:                          <n>
  Archivo:                          inventory_transfer_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-transferir-inventario",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "dry_run": true,
  "source_location": "<nombre>",
  "destination_location": "<nombre>",
  "outcome": {
    "skus_transferred": 0,
    "units_moved": 0,
    "warnings": 0,
    "errors": 0,
    "output_file": "inventory_transfer_<fecha>.csv"
  }
}
```

## Formato de salida
Archivo CSV `inventory_transfer_<AAAA-MM-DD>.csv` con las columnas:
`sku`, `product_title`, `inventory_item_id`, `source_location`, `destination_location`, `quantity_transferred`, `source_qty_before`, `source_qty_after`, `destination_qty_before`, `destination_qty_after`

## 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 |
| SKU no encontrado | El SKU no está en el catálogo | Registra una advertencia y omite la transferencia de ese SKU |
| `userErrors` en el ajuste | La ubicación no maneja ese artículo | Registra el error, omite el SKU y continúa |
| La cantidad quedaría negativa | Se transfiere más de lo disponible | Registra una advertencia; cancela ese SKU si `dry_run: false` |

## Buenas prácticas
- Ejecuta siempre primero con `dry_run: true`: la skill verifica las cantidades disponibles y muestra exactamente qué va a cambiar.
- Esto crea ajustes de inventario directos, no una orden de transferencia. Para dejar rastro de auditoría, agrega una nota en el campo de motivo y documenta la transferencia por aparte.
- Para transferencias grandes (50 SKU o más), ejecútala en horas de poco movimiento para no interferir con las lecturas de inventario en vivo de la tienda online.
- Combínala con `shopify-auditoria-inventario-bodegas` para identificar qué ubicaciones tienen exceso de stock antes de decidir las cantidades que vas a transferir.
