Copiar y pegar de Excel a Salesforce usando LWC

He de decir que Salesforce Inspector es una de mis herramientas favoritas como Admin.

Una de mis capacidades favoritas es el importador de datos. Teniendo unos power users bien entrenados, con buenas plantillas y un objeto con buen external ID, puedes insertar o actualizar datos que, de otro modo, exigirían procesos más complicados. El 90% de los usos para importar desde excel quedan resueltos así.

Pero me he topado con un caso de uso que no es tan sencillo. Por ejemplo, ¿Y si queremos cargar contactos asociados a una cuenta, pero sin duplicar los contactos por email? ¿Y si queremos hacer una carga inicial (insert) pero no actualizar registros si estos ya existen? ¿Y si queremos pegar desde Excel pero sin tener que dar permisos de API User? ¿No hay una forma de que un usuario pueda pegar de excel y se carguen masivamente esos datos contemplando las reglas de negocio?

OJO: No estoy hablando de miles de registros, que para eso hay otras herramientas. Pero para cargar unas decenas o incluso cientos de registros puede ser muy útil.

Como siempre, he trasteado un poco, y me encontré con una buena y una mala noticia. La buena: Excel copia al portapapeles en formato TSV (texto separado por tabulaciones). La mala: el modelo de seguridad de los LWC no permite leer el portapapeles. Pero hay un workaround: si se hace pegar sobre un textarea no se pierde el formato de tabulaciones y retornos de linea, así que se puede utilizar un textarea para procesar la información.

El XML del LWC expone el componente con un único target, lightning__Tab, para poder mostrarlo en una tab, aunque puede modificarse para cualquier otro objetivo.

A nivel visual, la primera iteración es un componente muy sencillo:

  • un textarea con un evento onchange para identificar actualizaciones, y disperar la generación del JSON en Javascript.

  • un datatable que muestre datos en formato JSON.

  • un par de botones, uno para limpiar y empezar de nuevo, y un botón para invocar al controller.

En el Javascript es donde ocurren las partes mas importante; poco a poco:

  • Se importa la función procesar del controller, para poder invocarla desde el botón.

  • Se definen dos variables datosJSON y columnas, que serán las que controlen qué se muestra en el datatable.

  • La variable esProcesando, que convierte al textarea en solo lectura, y la variable error para mostrar errores en la llamada al controller.

  • El método refrescarTabla, al que se invoca en el evento onchange del textarea, y que pasa el contenido del textarea al método convertirTabla, basado en este javascript de Khoj Badami. Este método hace lo siguiente:

    • Separa las filas por "\n", y de la primera fila obtiene las columnas separándolas por tabulaciones "\t".

    • Genera la variable columnas para crear las columnas del datatable, añadiendo dos columnas: resultado y resultadoMsg.

    • Para las subsiguientes columnas, separa por tabulaciones y genera un objeto JSON por cada fila con el formato

          {
              'TituloColumna1': 'ValorColumna1FilaN',
              'Titulocolumna2': 'ValorColumna2FilaN',
              /**... **/
              'rowId': 'NumeroDeFila'
          }
      
    • El array de estos objetos filas es lo que se devuelve en la variable datosJSON, y que será lo que se mande al controlador Apex.

  • El método limpiarTabla, que simplemente reinicia los valores del textarea y la variable datosJSON, para recomenzar el proceso.

  • Por último, el método procesarTabla, que invoca la función procesar de la clase Apex, pasándole como parámetros el JSON de la tabla, y recibe de vuelta también un JSON que realimenta al datatable.

Con esto está prácticamente todo resuelto. Ya solo nos queda la clase Apex en la que haremos lo necesario, y rellenemos los campos resultado y resultadoMsg con los resultados del procesado, que se mostrarán en sus columnas de la tabla.

En el ejemplo de controller, se comprueba que hay una columna Correo en los datos de entrada, y se añade un guión al correo como muestra de que se ha modificado el campo. También se indica que el resultado es OK y un mensaje de éxito. En caso que no se encuentre la columna Correo o esta esté en blanco, se muestra un error.

Con esto podemos probar un excel sencillo

Y el resultado será algo así:

Obviamente, esta es una prueba de concepto, y hay que mejorar el control de errores, el procesado en paralelo (por ejemplo, para insertar más de X registros), y la validación de los datos del lado del servidor (en Apex) y, si queremos más, también en el lado del cliente (en Javascript). Y pulir la interfaz, sobre todo durante el tiempo de procesado. ¡Ah! y un botón para mostrar en "formato Excel" la tabla de resultados también sería interesante, así se puede copiar y llevar de vuelta a Excel los resultados.

Os dejo aquí el código completo: