Copiar rangos de celdas entre planillas de Google

Una de las fórmulas más famosas de las planillas de Google es IMPORTRANGE, la cual permite conectar rangos de celdas entre planillas sin esfuerzo. Pero esta fórmula tiene dos limitaciones:

La planilla que importa datos no puede evitar actualizarse cuando la planilla de origen es actualizada.
La fórmula IMPORTRANGE tiene un límite de celdas y no es muy rápida en su ejecución.

Para estos casos podemos utilizar un Apps Script que copie hojas de una planilla a otra a demanda, de esta forma el usuario tiene control de la actualización de datos.

// Hoja de los Drive fuente donde se consolida el informe
var linkPlanillaOrigenDatos = "https://docs.google.com/spreadsheets/d/1if4jdub72bZnr4TyiTuSKorFj35ifBvonSkNsU0CDro/edit#gid=0";
var hojaFuente = "BD";
var hojaDestino = "BD";

function onOpen() {
    // La función onOpen se ejecuta automáticamente cada vez que se carga un Libro de cálculo
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var menuEntries = [];
 
    menuEntries.push({
        name : "Copiar Datos",
        functionName : "copiarDatos"
    });
    menuEntries.push(null);

    ss.addMenu("Actualizar", menuEntries);
}

function copiarDatos() {  
  
  // Mensaje al usuario
  SpreadsheetApp.getActiveSpreadsheet().toast('Copiando datos '+hojaDestino+'...', 'Estado');

  // Limpieza en hoja destino
  var destSS = SpreadsheetApp.getActiveSpreadsheet();
  var destSheet = destSS.getSheetByName(hojaDestino); // la planilla actual, hoja destino de los datos
  var range = destSheet.getRange("A2:U");
  range.clear();
  
  // Buscamos hoja preprocesada
  var sourceSS = SpreadsheetApp.openByUrl(linkPlanillaOrigenDatos);
  var sourceSheet = sourceSS.getSheetByName(hojaFuente); // todas las hojas de fuente, vamos a buscar la que ya esta preprocesada
  
  Logger.log("Entramos en la hoja: "+hojaFuente);

  // Datos de origen  
  var sourcerange = sourceSheet.getRange(2,1,sourceSheet.getLastRow()-1,20);
  var sourcevalues = sourcerange.getValues();

  // Datos, saltamos columna de titulo
  var iniRow = 2;
  var destRange = destSheet.getRange(iniRow,1,sourcevalues.length,sourcevalues[0].length);
  destRange.setValues(sourcevalues); 
  
  // Podemos agregar formulas adicionales a los datos importados
  var destRange = destSheet.getRange(iniRow,22,sourcevalues.length,1);
  destRange.setValue("=M2*Datos!$B$1"); 
  
  // Mensaje al usuario
  SpreadsheetApp.getActiveSpreadsheet().toast('Copiado finalizado de '+hojaDestino+' finalizado. Se actualizarán formulas.', 'Estado', 2);

}
twitterpinterest