logo

NJP

Actualización masiva de asset desde un fichero .CSV con selección dinámica de los campos a actualizar en el asset

Import · Feb 28, 2018 · article

Objetivo/Necesidad

  • Se nos planteó la necesidad de implementar un proceso por el cual un usuario gestor del inventario pudiera actualizar, a partir de un Excel (que convierte en un fichero .CSV) la tabla de asset (alm_asset) de forma autónoma y lo más dinámica posible.

Requisitos

  • Que el usuario final, a través del Service Portal, pueda elegir que campos de la tabla alm_asset quiere actualizar
  • Adjuntar un fichero .CSV que contiene la información en columnas que se corresponden con los campos de alm_asset

Restricciones

  • Lo único que indicamos como obligatorio por parte del usuario en la generación del fichero .CSV es que la primer columna sea el asset_tag (el campo por el cual podemos saber que asset vamos a actualizar) y que las columnas estén en el mismo orden que los campos que elige en el item de actualización masiva
  • El fichero .CSV no lleva encabezado

Implementación

  • Creamos un item de catálogo donde le pedimos que campos, mediante variables del tipo Reference a la tabla sys_dictionary, quiere actualizar. Con esto nos aseguramos varias cosas:
  • * Que el nombre del campo será el correcto (evitamos tener que poner un encabezado en el .CSV)
    • Que solo los campos que nosotros "publicamos" se puedan actualizar
    • Obtener información de metadatos de los campos para saber si son a su vez Reference a otras tablas para su tratamiento posterior
  • Un workflow con una tarea del tipo "run script" que se encarga de procesar el excel y actualizar la tabla alm_asset

Detalle de la implementación

  • Las variables reference a los campos de la tabla alm_asset tienen esta carecterística:
  • * La tabla es alm_asset
    • Los campos no contienen "sys"
    • Y así se puede ir filtrando que campos queremos que aparezcan (el filtro es más grande en mi caso)

image

El ítem, para elegir los campos, queda así (puse 4 campos, pero podemos poner 2, 6, 10, los que querramos)

image

image

  • La tarea del tipo "Run Script" del workflow, tiene el siguiente código, y las siguientes consideraciones (o retos image
  • * Como la selección del campo es dinámica, se presentaban dos retos: Saber el nombre del campo para luego actualizarlo, y los campos del tipo Reference (a otras tablas) debía identificarlos, saber de que tabla se trataba, con el dato del fichero .CSV ir a buscar el registro y obtener el SYS_ID para la actualización.
//Variables globales
var vSysId1 = '';
var vSysId2 = '';
var vSysId3 = '';
var vSysId4 = '';
var vValor1 = '';
var vValor2 = '';
var vValor3 = '';
var vValor4 = '';
var debug = true;
var attachment = '';
var attachmentData = '';
var splited = '';
var splited2 = '';
var vAssetTag = '';

//Recupero attach
var attGr = new GlideRecord('sys_attachment');
attGr.addQuery('table_name', 'sc_req_item');
attGr.addQuery('table_sys_id', current.sys_id);
attGr.query();

//Si tengo attach
if(attGr.next()) {

    //Proceso attach
    var gsu = (typeof GlideStringUtil != 'undefined') ? (GlideStringUtil) : (Packages.com.glide.util.StringUtil);
    var gsa = (typeof GlideSysAttachment != 'undefined') ? (new GlideSysAttachment()) : (new Packages.com.glide.ui.SysAttachment());
    var attachmentData = gsa.getBytes(attGr);
    var attachment = String(Packages.java.lang.String(attachmentData));

    //Splito
    splited = attachment.split('\n');

    //Itero cada fila del attach
    for (var i=0; i<splited.length; i++) {
        //Splito again
        split2 = splited[i].split(';');

        vAssetTag = split2[0].trim();

        //Valores de campo directos
        vValor1 = split2[1].trim();
        vValor2 = split2[2].trim();
        vValor3 = split2[3].trim();
        vValor4 = split2[4].trim();

        //Si los valores de campos son reference
        //asset_field1
        if (current.variables.asset_field1.internal_type == 'reference') {
            //es reference, va el sys_id
            vSysId1=devuelveSYSID(current.variables.asset_field1.reference,vValor1);
            vValor1 = vSysId1;
        }

        //asset_field2
        if (current.variables.asset_field2.internal_type == 'reference') {
            //es reference, va el sys_id
            vSysId2=devuelveSYSID(current.variables.asset_field2.reference,vValor2);
            vValor2 = vSysId2;
        }

        //asset_field3
        if (current.variables.asset_field3.internal_type == 'reference') {
            //es reference, va el sys_id
            vSysId3=devuelveSYSID(current.variables.asset_field3.reference,vValor3);
            vValor3 = vSysId3;
        }

        //asset_field4
        if (current.variables.asset_field4.internal_type == 'reference') {
            //es reference, va el sys_id
            vSysId4=devuelveSYSID(current.variables.asset_field4.reference,vValor4);
            vValor4 = vSysId4;
        }

        //Recupero asset a actualizar
        var grAssetUpd = new GlideRecord("alm_asset");
        grAssetUpd.addQuery("asset_tag", vAssetTag);
        grAssetUpd.query();

        if (grAssetUpd.next()) {

            grAssetUpd.setValue(current.variables.asset_field1.element,vValor1);
            grAssetUpd.setValue(current.variables.asset_field2.element,vValor2);
            grAssetUpd.setValue(current.variables.asset_field3.element,vValor3);
            grAssetUpd.setValue(current.variables.asset_field4.element,vValor4);

            //Actualizo
            grAssetUpd.update();
        }
        else {gs.log('NOOOOOO encontre asset ' + vAssetTag);}
        }
    }

    //Funcion que devuelve el sys_id segun el reference y el valor
    function devuelveSYSID (vReference,vValor) {
        var vQuery = '';

        //Segun que tabla sea debo filtrar por diferentes campos
        if (vReference == 'u_acreditaciones') {
            vQuery = "u_acreditacion";
        }
        if (vReference == 'core_company') {
            vQuery = "u_codigo";
        }
        if (vReference == 'cmn_department') {
            vQuery = "name";
        }
        if (vReference == 'cmdb_model_category') {
            vQuery = "name";
        }
        if (vReference == 'cmdb_model') {
            vQuery = "name";
        }
        if (vReference == 'cmn_location') {
            vQuery = "name";
        }
        if (vReference == 'u_secciones') {
            vQuery = "u_name";
        }
        if (vReference == 'sys_user') {
            vQuery = "user_name";
        }

        //Busco la tabla segun vReference
        var gr = new GlideRecord(vReference);
        gr.addQuery(vQuery,vValor);
        gr.query();

        //Encuentro
        if (gr.next()) {
            var retorno = gr.getUniqueValue();
            return retorno;
        }
    }

Conclusiones

  • Como todo, el proceso es mejorable y hay muchas cosas por hacer, pero es un método bastante sencillo y fiable para darle al usuario una funcionalidad de actualización masiva de asset (podría ser realmente cualquier otra tabla), que no tiene que entrar en la interface UI y que le facilita su operación porque están muy acostumbrados al uso del Excel/CSV

Espero que os sea de utilidad, y como digo siempre, no he inventado nada, solo he reaprovechado lo que la propia comunidad comparte, modificado un poco allí, retocado aquí e implementado en nuestras instancias para obtener un resultado. Por eso, gracias por compartir y os animo a hacerlo!

PD: Si el artículo te ha sido de utilidad, te agradeceré lo marques como tal y lo compartas.

image

View original source

https://www.servicenow.com/community/spain-snug/actualizaci%C3%B3n-masiva-de-asset-desde-un-fichero-csv-con-selecci%C3%B3n/ta-p/2328386