> ## Documentation Index
> Fetch the complete documentation index at: https://muveya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Importar y exportar

> Crea muchos insumos de una vez desde un archivo CSV, sigue la importación, corrige las filas rechazadas y exporta tu catálogo.

Una importación CSV crea insumos nuevos en bloque. Nunca actualiza ni elimina insumos existentes. Una exportación CSV descarga todo el catálogo en un archivo, con costos solo para quienes pueden verlos.

## Quién puede hacerlo

| Acción | Quién |
| - | - |
| Importar un archivo CSV | Personas con el rol **Propietario** o **Administrador**. El servidor revisa el rol en sí: un miembro al que se le otorgó `catalog.manage` ve **Importar CSV**, pero la carga se rechaza. Mientras la importación avanza, cada fila también se valida contra el `catalog.manage` de quien cargó el archivo. |
| Abrir la página de estado de una importación | Personas de la misma clínica dental que tengan el enlace. |
| Exportar el catálogo | Personas con el rol **Propietario** o **Administrador**. El botón **Exportar CSV** se muestra a quienes tienen `catalog.manage`; a un miembro con ese permiso se le rechaza de la misma forma. |
| Recibir las columnas de costo en una exportación | Quienes exportan y además tienen `catalog.cost.read`. |

La importación y la exportación están marcadas como acciones sensibles. En la versión actual, la verificación en dos pasos (MFA) es opcional y no las bloquea; si alguna vez la consola muestra **Verifica tu identidad para continuar.**, confirma con tu app autenticadora y vuelve a intentar. Consulta [Seguridad de la cuenta](/docs/es/account/security) y [Roles y permisos](/docs/es/account/roles-and-permissions).

## Dónde

| Pantalla | Ruta | Cómo llegar |
| - | - | - |
| **Importar CSV** | `/catalog/imports/new` | **Catálogo** y luego **Importar CSV**. |
| **Estado de importación** | `/catalog/imports/:importId` | Se abre sola después de cargar un archivo. |
| Exportación | `/catalog` | **Catálogo** y luego **Exportar CSV**. |

<Note>
  No existe una lista de importaciones anteriores. Guarda la dirección de la página **Estado de importación** si quieres revisarla después.
</Note>

## Prepara el archivo

La pantalla **Importar CSV** (**Agrega insumos desde un archivo CSV. Los insumos existentes no se actualizan.**) incluye una guía, **Prepara tu archivo**, con:

* **Columnas obligatorias** y **Columnas opcionales**.
* **Unidades admitidas** y **Criticidades admitidas**, con sus códigos.
* **Descargar plantilla de columnas**: un archivo llamado `muveya-catalog-template.csv` que solo trae la fila de encabezado.
* **ID de categorías para tu CSV**: cada **Nombre de la categoría** junto a su `categoryId`, con **Copiar ID de categoría**.

### Formato del archivo

* CSV simple con coma como separador. Los campos que contienen comas, comillas dobles o saltos de línea van entre comillas dobles, y una comilla doble dentro de ellos se escribe dos veces (`""`).
* Codificado en UTF-8, con o sin marca de orden de bytes. En una hoja de cálculo, guárdalo como "CSV UTF-8".
* El primer registro es el encabezado. Los nombres de columna son los nombres en inglés de abajo, escritos exactamente igual (importan las mayúsculas), en cualquier orden.
* Las columnas que muveya no conoce se ignoran. Si una columna aparece dos veces se usa la primera, salvo `unitOfMeasure`, `cost`, `currency` y las columnas de metadatos de costo: un duplicado de cualquiera de ellas rechaza el archivo completo.
* Las líneas vacías se omiten. Se quitan los espacios alrededor de cada valor.

<Warning>
  Las hojas de cálculo configuradas en español o portugués suelen guardar los CSV con punto y coma. muveya lee ese archivo como una sola columna y la importación falla con **El archivo no contiene las columnas CSV obligatorias.** Guárdalo con comas.
</Warning>

### Columnas

| Columna | Obligatoria | Formato |
| - | - | - |
| `sku` | Sí | De 1 a 64 caracteres: letras, dígitos, `.`, `_`, `/`, `-`. No debe existir todavía en tu clínica dental. |
| `name` | Sí | Hasta 200 caracteres. |
| `categoryId` | Sí | El identificador de una categoría de tu clínica dental, copiado de la guía. |
| `unitOfMeasure` | Sí | `unit`, `box`, `pack`, `bottle`, `ampoule`, `milliliter`, `liter`, `gram`, `kilogram`, `pair` o `kit`. |
| `criticality` | Sí | `low`, `medium` o `high`. |
| `description` | No | Hasta 2.000 caracteres. |
| `packaging` | No | Hasta 200 caracteres. Es el campo de texto libre **Presentación**. |
| `tracksLot`, `tracksSerial`, `tracksExpiry`, `highValue` | No | `true` o `false`. muveya también acepta `1`/`0` y `yes`/`no`, con cualquier combinación de mayúsculas. Vacío significa `false`. |
| `cost` | No | Un número entero de unidades menores, por ejemplo `1200` para USD 12,00 o CLP 1200. Solo dígitos. Requiere `currency`. |
| `currency` | No | Tres letras mayúsculas, por ejemplo `CLP`. Requiere `cost`. |
| `status` | Se ignora | Todo insumo importado se crea como `draft`. |
| `costStatus`, `costUnitOfMeasure`, `costMeasurementVersion`, `costQuantityProtocol` | No | Metadatos de costo que escribe una exportación. Si aparece cualquiera de ellas, deben estar las seis columnas de costo (`cost`, `currency` y estas cuatro). Consulta [Reimportar un archivo exportado](#reimportar-un-archivo-exportado). |

Ejemplo:

```csv theme={null}
sku,name,categoryId,unitOfMeasure,criticality,description,packaging,tracksLot,tracksSerial,tracksExpiry,highValue,cost,currency
GLV-NIT-M,Nitrile gloves size M,665f1a2b3c4d5e6f7a8b9c01,unit,high,"Powder-free, blue",Box of 100,true,false,true,false,12,USD
ANS-LID-2,Lidocaine 2% cartridge,665f1a2b3c4d5e6f7a8b9c02,ampoule,high,,Box of 50,true,false,true,true,,
```

La segunda fila no tiene costo: `cost` y `currency` están vacíos.

### Límites

| Límite | Valor | Si se supera |
| - | - | - |
| Tamaño del archivo | 5 MB (5.242.880 bytes), no vacío | Se rechaza la carga: **El archivo debe pesar 5 MB o menos.** |
| Filas de datos | 10.000 por archivo, sin contar el encabezado | Falla toda la importación: **Usa un máximo de 10.000 filas de datos por archivo.** |
| Archivos por importación | 1 | Divide los catálogos grandes en varios archivos. |

## Importar insumos

<Steps>
  <Step title="Prepara las categorías">
    Crea primero las categorías que falten y copia sus identificadores desde **ID de categorías para tu CSV**. Consulta [Categorías](/docs/es/catalog/categories).
  </Step>

  <Step title="Elige el archivo">
    En **Importar CSV**, haz clic en **Archivo CSV** y elige tu archivo `.csv`.
  </Step>

  <Step title="Carga el archivo">
    Haz clic en **Importar insumos**. Cuando el archivo se acepta, la consola abre **Estado de importación**.
  </Step>

  <Step title="Sigue el avance">
    La página se actualiza sola mientras la importación está pendiente o en curso. **Actualizar estado** vuelve a consultar cuando quieras.
  </Step>

  <Step title="Revisa el resultado">
    Lee los totales y las filas rechazadas. Corrige esas filas en un archivo nuevo y haz clic en **Importar otro archivo**.
  </Step>

  <Step title="Activa los nuevos insumos">
    Los insumos importados quedan en borrador. Abre cada uno y actívalo cuando esté listo para pedirse. No existe activación masiva. Consulta [Insumos del catálogo](/docs/es/catalog/items).
  </Step>
</Steps>

## Estados de la importación

| Estado | Título en la página | Significado |
| - | - | - |
| `pending` | **Importación recibida** | El archivo está guardado y espera su procesamiento. |
| `processing` | **Importando insumos** | Las filas se están creando una por una, en el orden del archivo. |
| `completed` | **Importación completada** | Se intentaron todas las filas. Algunas pueden haberse rechazado. |
| `failed` | **No se pudo completar la importación** | El archivo no se pudo procesar como un todo. Un mensaje explica por qué. |

```mermaid theme={null}
stateDiagram-v2
  [*] --> pending: Archivo aceptado
  pending --> processing: Comienza el procesamiento
  processing --> completed: Todas las filas intentadas
  pending --> failed: No pudo comenzar
  processing --> failed: Archivo rechazado o interrumpido
  failed --> processing: Reintento automático tras una interrupción
```

Al terminar, la página muestra **Filas de datos**, **Creados** y **Rechazados**. Si alguna fila se rechazó, agrega **Algunas filas fueron rechazadas. Revisa los motivos antes de cargar un archivo corregido.** y una tabla con **Fila de datos** y **Motivo**.

Cada fila es independiente: una fila rechazada nunca detiene a las demás, y las filas creadas antes de un rechazo siguen creadas.

### Números de fila

**Se cuentan registros de datos, sin la cabecera; un registro CSV puede ocupar varias líneas de texto.** La fila de datos 1 es el primer registro después del encabezado. Las líneas vacías no se cuentan y un valor entre comillas con saltos de línea cuenta como una sola fila, así que el número de fila de datos puede no coincidir con el número de línea que muestra tu editor.

## Fallas del archivo completo

| Mensaje | Causa | Qué hacer |
| - | - | - |
| **El archivo no contiene las columnas CSV obligatorias.** | Falta una columna obligatoria o está mal escrita, el separador no es coma, quedó una comilla abierta, se duplicó una columna de costo o de unidad, o solo están algunas de las seis columnas de costo. | Corrige el encabezado o las comillas y vuelve a cargarlo. |
| **Usa un máximo de 10.000 filas de datos por archivo.** | Demasiadas filas. | Divide el archivo. |
| **El archivo cargado ya no está disponible. Vuelve a cargarlo.** | No se pudo volver a leer el archivo guardado. | Carga el archivo de nuevo. |
| **El procesamiento se interrumpió. La recuperación automática reintentará el trabajo pendiente.** | Una falla temporal detuvo la importación. | Espera. La página sigue consultando, y las filas ya creadas no se crean dos veces. |
| **Esta importación interrumpida es anterior al registro de progreso. Revisa el catálogo existente antes de cargar un archivo corregido.** | Una importación antigua se interrumpió antes de que muveya registrara el avance por fila. | Busca en el catálogo los SKU del archivo y carga solo los que falten. |

## Filas rechazadas

| Motivo que se muestra | Código | Causas frecuentes | Solución |
| - | - | - | - |
| **Falta un campo obligatorio.** | `catalog.import_row_incomplete` | `sku`, `name`, `categoryId`, `unitOfMeasure` o `criticality` está vacío. | Completa la celda. |
| **Falta un campo obligatorio.** | `catalog.cost_incomplete` | `cost` sin `currency`, o `currency` sin `cost`. | Indica ambos o ninguno. |
| **Revisa los campos de esta fila.** | `catalog.import_row_invalid` | Unidad o criticidad desconocida, un valor de trazabilidad que no es true ni false, un `cost` que no es número, metadatos de costo inconsistentes. | Usa los valores permitidos. |
| **Revisa los campos de esta fila.** | `common.invalid_request` | SKU con espacios u otros caracteres, un texto demasiado largo, un `categoryId` mal formado, un `cost` con decimales o negativo, una `currency` que no son tres letras mayúsculas. | Revisa los formatos de columna de arriba. |
| **Este SKU ya existe.** | `catalog.sku_taken` | Ya existe un insumo con ese SKU, incluido uno creado por una fila anterior del mismo archivo. | Quita la fila o usa otro SKU. |
| **La categoría no existe en esta clínica.** | `catalog.category_not_found` | El `categoryId` tiene buen formato, pero no es una categoría de esta clínica dental. | Copia el identificador desde **ID de categorías para tu CSV**. |
| **El costo registrado requiere revisión. Confirma su unidad e importe antes de importar esta fila.** | `catalog.cost_unverified` | La fila viene de una exportación y su `costStatus` es `review_required` o `invalid`. | Define un costo confirmado o vacía las columnas de costo. |
| **La persona que cargó el archivo ya no tiene permiso.** | `tenants.insufficient_role` | Quien cargó el archivo perdió `catalog.manage` mientras la importación avanzaba. | Pide a alguien con el rol adecuado que cargue las filas que faltan. |
| **No se pudo importar esta fila.** | Cualquier otro | Un rechazo inesperado. | Revisa la fila; si sigue fallando, escribe a [team@muveya.com](mailto:team@muveya.com). |

Para corregir filas rechazadas, prepara un archivo nuevo con *solo* esas filas, ya corregidas. Deja fuera las filas que se crearon: ahora se rechazarían con **Este SKU ya existe.**

## Las importaciones nunca actualizan insumos

* Una importación solo crea insumos. Una fila cuyo SKU ya existe se rechaza, sin importar sus demás valores. Para cambiar insumos existentes, edítalos en la consola.
* Dentro de un archivo, la primera fila con un SKU se crea y las siguientes con el mismo SKU se rechazan.
* Cargar dos veces el mismo archivo no crea nada la segunda vez: todas las filas se rechazan por SKU existente.
* Si el procesamiento se interrumpe y se retoma, muveya recuerda qué filas ya creó y no las vuelve a crear.
* El costo de una fila pasa a ser el costo vigente del insumo, confirmado para la unidad importada. Consulta [Costos](/docs/es/catalog/costs).

## Exportar el catálogo

<Steps>
  <Step title="Inicia la exportación">
    En **Catálogo**, haz clic en **Exportar CSV**. El archivo se genera en el momento.
  </Step>

  <Step title="Descarga">
    Haz clic en **Descargar CSV**. Bajo el enlace, **El enlace vence:** muestra la fecha y la hora.
  </Step>
</Steps>

El enlace es válido por 5 minutos. Después, la consola muestra **Este enlace venció. Genera una nueva exportación.**; haz clic otra vez en **Exportar CSV**. Si la consola no puede verificar el enlace, muestra **No se pudo verificar el enlace de descarga. Genera una nueva exportación.**

### Contenido de la exportación

El archivo se llama `catalog.csv` y contiene todos los insumos de la clínica dental, en todos los estados, del más antiguo al más reciente.

| Columnas | Se incluyen |
| - | - |
| `sku`, `name`, `description`, `categoryId`, `unitOfMeasure`, `packaging`, `criticality`, `tracksLot`, `tracksSerial`, `tracksExpiry`, `highValue`, `status` | Siempre. |
| `cost`, `currency`, `costStatus`, `costUnitOfMeasure`, `costMeasurementVersion`, `costQuantityProtocol` | Solo si tienes `catalog.cost.read`. Sin ese permiso, estas columnas no existen en el archivo. |

* Los valores opcionales vacíos son celdas vacías; las columnas de trazabilidad valen `true` o `false`; `cost` y `currency` quedan vacíos cuando el costo es `unset`.
* El archivo está en UTF-8 con marca de orden de bytes, separado por comas y con saltos de línea de Windows, para que las hojas de cálculo abran bien los nombres con tildes.
* Un valor que empieza con `=`, `+`, `-` o `@` se escribe con un apóstrofo (`'`) delante, para que la hoja de cálculo no lo ejecute como fórmula.
* Las categorías aparecen como `categoryId`, no por nombre. No se exportan presentaciones, códigos de envase ni existencias.

### Reimportar un archivo exportado

Una exportación tiene los mismos nombres de columna que la importación, así que puedes usarla como punto de partida, por ejemplo para cargar el mismo catálogo en otra clínica dental. Antes de cargarla:

* Reemplaza cada `categoryId` por los identificadores de la clínica dental de destino.
* Quita el apóstrofo que la exportación agregó delante de los valores que empiezan con `=`, `+`, `-` o `@`.
* La columna `status` se ignora: todo insumo se crea como borrador.
* Si el archivo trae las columnas de costo, el `costStatus` de cada fila decide qué pasa:
  * `unset`: las demás celdas de costo deben estar vacías.
  * `verified`: `costUnitOfMeasure` debe ser igual a `unitOfMeasure`, `costMeasurementVersion` un número entero desde 1, `costQuantityProtocol` debe ser `base_number_v1`, `cost` un número entero y `currency` tres letras mayúsculas. Si no, la fila se rechaza con **Revisa los campos de esta fila.**
  * `review_required` o `invalid`: la fila se rechaza con **El costo registrado requiere revisión. Confirma su unidad e importe antes de importar esta fila.**
  * Vacío o cualquier otro valor: la fila se rechaza con **Revisa los campos de esta fila.**
* Volver a importar en la misma clínica dental no crea nada, porque todos los SKU ya existen.

## Qué registra el sistema

| Evento | Registro de auditoría |
| - | - |
| Una carga aceptada | `catalog.import`, con el nombre del archivo, su tamaño y quién lo cargó; el registro se cierra cuando la importación termina o falla. |
| Una carga rechazada | `catalog.import.denied`, con el nombre del archivo. |
| Una exportación | `catalog.export`, con la cantidad de insumos y si se incluyeron costos. Nunca los valores de costo. |
| Una exportación rechazada | `catalog.export.denied`. |

La importación también guarda, para cada fila de datos, si se creó y el motivo cuando no se creó. Ese resumen nunca guarda valores de costo. La versión actual no tiene una pantalla para consultar la auditoría.

## Qué puede salir mal al cargar o exportar

| Mensaje | Código | Qué hacer |
| - | - | - |
| **Elige un archivo CSV.** | `catalog.import_file_missing`, `catalog.import_empty` | Elige un archivo que no esté vacío. |
| **El archivo debe pesar 5 MB o menos.** | `catalog.import_too_large` | Divide el archivo. |
| **Tu cuenta no tiene permiso para esta acción.** | `tenants.insufficient_role` | Pide a un propietario o administrador que importe o exporte. |
| **Este registro no está disponible en la cuenta de clínica dental activa.** | `catalog.import_not_found` | La importación pertenece a otra clínica dental o el enlace está mal. |
| **Verifica tu identidad para continuar.** | `auth.mfa_required` | Verifica con tu app autenticadora y vuelve a intentar. |

La API pública no importa ni exporta el catálogo. Para leerlo desde otro sistema, usa `GET /v1/catalog/items`. Consulta [API para desarrolladores](/docs/es/api-reference/introduction).

## Páginas relacionadas

<CardGroup cols={2}>
  <Card title="Insumos del catálogo" icon="box" href="/docs/es/catalog/items">
    Reglas de los campos y activación.
  </Card>

  <Card title="Categorías" icon="tags" href="/docs/es/catalog/categories">
    Crea categorías y encuentra sus identificadores.
  </Card>

  <Card title="Costos" icon="coins" href="/docs/es/catalog/costs">
    Unidades menores y estados del costo.
  </Card>

  <Card title="Roles y permisos" icon="user-shield" href="/docs/es/account/roles-and-permissions">
    Roles que pueden importar y exportar.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.