Con DataScope, puedes mantener tus listas actualizadas de forma automática a partir de respuestas de formularios. Esto es útil cuando necesitas agregar ítems a una lista sin hacerlo manualmente. En este artículo, te mostramos cómo configurarlo paso a paso.
Paso 1: Crear el formulario
Diseña un formulario en DataScope que capture la información que quieres agregar a tu lista.
Asegúrate de que cada pregunta corresponda a un dato que luego usarás en tu lista: nombre, descripción, código y atributos personalizados.
Paso 2: Conectar el formulario a Google Sheets
En DataScope, ve a la configuración del formulario y activa la integración con Google Sheets.
Selecciona o crea una hoja de cálculo donde se registrarán todas las respuestas del formulario.
Verifica que las respuestas se estén guardando correctamente.
Paso 3: Crear la hoja para la lista
Abre el Google Sheet donde llegan las respuestas.
Crea una nueva hoja dentro del mismo archivo. Esta hoja será donde se generará la lista que luego se cargará en DataScope.
Dale un nombre a la hoja. Este nombre debe coincidir con el nombre que luego le darás a la lista en DataScope.
Ejemplo: Si la hoja se llama Lista Productos
, la lista en DataScope también se llamará Lista Productos
.
Paso 4: Crear la lista en DataScope
En DataScope, ve a Ajustes → Listas .
Haz clic en Nueva lista y ponle exactamente el mismo nombre que la hoja que creaste en Google Sheet.
Anota el Código de la lista, lo necesitarás más adelante para configurar el script.
Paso 5: Configurar la hoja de la lista
En la hoja que creaste para la lista, agrega los encabezados en la primera fila de la siguiente manera:
| Nombre | Descripción | Código | Atributo Customizado 1 | Atributo Customizado 2 |
El ID, Estado y Mensaje se llenarán automáticamente al procesar los datos.
Fórmulas recomendadas
Nombre: Para tomar datos de la hoja de integración del formulario, usa algo como:
=ARRAYFORMULA( SI( LARGO('HojaFormulario'!T3:T), 'HojaFormulario'!T3:T & SI(LARGO('HojaFormulario'!U3:U), " - " & 'HojaFormulario'!U3:U, "" ), "" ) )
Código: Debe ser único, por ejemplo:
=ARRAYFORMULA( SI(A2:A<>"", FILA(A2:A)-FILA(A2)+1, "") )
Puedes ajustar las columnas de descripción y atributos si también vienen del formulario.
Paso 6: Configurar el script en Google Apps Script
Ve a Extensiones → Apps Script en tu Google Sheet.
Copia el siguiente script (ya ajustado según tu lista y hoja):
/******************** CONFIG ********************/
const SHEET_NAME = "Prueba listas"; // Hoja con la lista
const METADATA_TYPE = "SeleccinListaDatos_8175b7"; // Código de lista
const API_BASE = "https://www.mydatascope.com/api/external/metadata_object";
const START_ROW = 2; // Encabezados en la fila 1
const COLS = { // Mapeo de columnas
name: 1, // A
description: 2, // B
code: 3, // C
attr1: 4, // D
attr2: 5, // E
id: 6, // F (id devuelto por la API)
status: 7, // G (opcional: estado)
msg: 8 // H (opcional: mensaje)
};
/************************************************/
/**
* Procesa todas las filas "pendientes" en Carga Lista:
* - Pendiente = columna A con valor (display) y columna F vacía.
* - Usa displayValues para respetar formatos de fórmulas.
*/
function processPending() {
const lock = LockService.getScriptLock();
if (!lock.tryLock(30000)) return; // evita solapes
try {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName(SHEET_NAME);
if (!sh) throw new Error(`No existe la hoja '${SHEET_NAME}'.`);
const lastRow = sh.getLastRow();
if (lastRow < START_ROW) return;
// Leemos en bloque (displayValues para respetar fórmulas/formatos)
const numRows = lastRow - START_ROW + 1;
const values = sh.getRange(START_ROW, 1, numRows, Math.max(...Object.values(COLS))).getDisplayValues();
// También necesitamos los valores "crudos" de D/E por si son numéricos
const rawDE = sh.getRange(START_ROW, COLS.attr1, numRows, 2).getValues();
const props = PropertiesService.getScriptProperties();
const token = props.getProperty("DATASCOPE_TOKEN");
if (!token) throw new Error("Falta 'DATASCOPE_TOKEN' en Script Properties.");
for (let i = 0; i < numRows; i++) {
const rowIdx = START_ROW + i;
const row = values[i];
const name = (row[COLS.name - 1] || "").toString().trim();
const description = (row[COLS.description - 1] || "").toString().trim();
const code = (row[COLS.code - 1] || "").toString().trim();
const attr1 = rawDE[i][0]; // D (raw)
const attr2 = rawDE[i][1]; // E (raw)
const id = (row[COLS.id - 1] || "").toString().trim();
// Saltar filas "vacías" por fórmula o sin claves mínimas
if (!name || !code) continue;
// Ya procesada
if (id) continue;
// Upsert
const result = upsertListObject_({ name, description, code, attribute1: attr1, attribute2: attr2 }, token);
// Escribimos resultado
if (result.ok) {
if (result.id) sh.getRange(rowIdx, COLS.id).setValue(result.id);
if (COLS.status) sh.getRange(rowIdx, COLS.status).setValue("OK");
if (COLS.msg) sh.getRange(rowIdx, COLS.msg).setValue("");
} else {
if (COLS.status) sh.getRange(rowIdx, COLS.status).setValue("ERROR");
if (COLS.msg) sh.getRange(rowIdx, COLS.msg).setValue(result.message || "Error");
}
}
} catch (err) {
Logger.log("processPending error: " + err);
} finally {
try { lock.releaseLock(); } catch (_) {}
}
}
/**
* Llamada a la API (POST para crear; PUT para actualizar si viniera id).
* Aquí solo creamos (id vacío). Si quieres soportar PUT, pasa id en data.
*/
function upsertListObject_(data, token) {
const url = API_BASE + "?metadata_type=" + encodeURIComponent(METADATA_TYPE) + (data.id ? "&id=" + encodeURIComponent(data.id) : "");
const method = data.id ? "put" : "post";
const payload = {
list_object: {
name: data.name,
description: data.description,
code: data.code,
attribute1: data.attribute1,
attribute2: data.attribute2
}
};
const headers = {
// Ajusta a lo que espere la API: si requiere "Bearer <token>", cambia aquí:
"Authorization": token,
"Content-Type": "application/json"
};
const options = {
method: method,
headers: headers,
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
// Reintentos para 429/5xx
const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const res = UrlFetchApp.fetch(url, options);
const code = res.getResponseCode();
const text = res.getContentText();
Logger.log(`API attempt ${attempt} → ${code} | ${text}`);
if (code >= 200 && code < 300) {
let json = {};
try { json = text ? JSON.parse(text) : {}; } catch (_) {}
return { ok: true, id: json.id || json._id || "" };
}
if (code === 429 || (code >= 500 && code <= 599)) {
Utilities.sleep(500 * attempt * attempt);
continue;
}
return { ok: false, message: `HTTP ${code}: ${text}` };
} catch (err) {
Logger.log("Fetch exception: " + err);
Utilities.sleep(500 * attempt * attempt);
}
}
return { ok: false, message: "Agotados reintentos." };
}
/********** Disparadores cómodos **********/
// Si ya lo estabas usando, puedes dejar este nombre. Llama al procesador por lotes.
function onFormSubmit(e) {
processPending();
}
// Útil si los datos llegan por fórmulas/otras hojas.
// Crea un trigger instalable "Al producirse un cambio" (no el simple).
function onChange(e) {
processPending();
}
// Para ejecutar manualmente desde el editor (backfill).
function runNow() {
processPending();
}
Ajusta las constantes
SHEET_NAME
yMETADATA_TYPE
con los valores de tu hoja y lista en DataScope.const SHEET_NAME = "Lista Productos"; // Nombre de tu hoja
const METADATA_TYPE = "XXXX"; // ID de tu lista
Paso 6a: Agregar token de DataScope
En el editor de Apps Script, ve a Configuración del proyecto → Propiedades de la secuencia de comandos.
Agrega una propiedad con:
Nombre:
DATASCOPE_TOKEN
Valor: tu clave API de DataScope (desde Integraciones → Clave API).
Paso 7: Configurar disparadores (triggers)
Para que la actualización sea automática:
Ve a Extensiones → Apps Script → Reloj (Triggers).
Crea un trigger instalable que ejecute la función
processPending
cada cierto tiempo, por ejemplo, cada hora o al producirse un cambio en la hoja.
También puedes ejecutar el script manualmente desde Apps Script usando runNow()
para actualizar datos de forma inmediata.
Paso 8: Verificar que la lista se actualice
Cada vez que llegue una nueva respuesta del formulario, se procesará automáticamente y se agregará a la lista de DataScope.
Revisa las columnas ID, Estado y Mensaje para confirmar que los ítems se subieron correctamente.
Consejos finales
Asegúrate de que los nombres de las hojas y de la lista coincidan exactamente.
Cada código debe ser único para evitar conflictos en la lista.
Si deseas, puedes personalizar los atributos para agregar información extra desde el formulario.
Este proceso permite mantener tus listas siempre actualizadas sin intervención manual.