Création de dossier et création/modification de gsheet sous conditions

Bonjour,

Je découvre gsheet et les scripts. Je suis aussi à la recherche de bonnes pratiques.

J'aimerais pouvoir créer un dossier (s’il n’existe pas) et créer un fichier gsheet dans ce dossier (s’il n’existe pas) à partir d’un gsheet template. En créant ce fichier, j’aimerai écrire des valeurs dans ce nouveau fichier. Puis Récupérer les liens sur le dossier et le gsheet.

Pour ce faire, dans un document gsheet (référentiel projets),

J’ai un onglet où je crée des projets (un par ligne) : nom du projet (par exemple, projet zéro), code du projet (par exemple, 75000), date de création (par exemple, 01/08/2021), nom du porteur du projet (par exemple, emmanuel).

Si ces valeurs sont renseignées, je calcule un numéro de projet (par exemple, P-20210801-0001) et le nom du dossier (P-20210801-0001 - 75000 - Projet Zéro)

Si le numéro du projet et le nom du dossier sont générés, j’aimerai pouvoir faire apparaître "un bouton" pour que l’utilisateur puisse cliquer dessus. Action qui ferait apparaître le message : voulez-vous créer le projet "Projet Zéro" ? Et les choix oui/non qui vont bien.

Si oui, créer le dossier (s’il n’existe pas) et, dans ce dossier, créer un gsheet de nom (P-20210801-0001 - Projet Zéro) (s’il n’existe). Le fichier gsheet est une copie d'un gsheet template. dans ce nouveau gsheet j'aimerai pouvoir mettre à jour des named range : ProjetNumero à « P-20210801-0001 », PorteurNom à « Emmanuel »

Puis insérer les liens du dossier et du gsheet dans le "référentiel projets".

Une fois le dossier et le gsheet créés ou modifié, j’aimerai « griser le bouton » ainsi que la date de création, le nom du projet et le code postal pour que l’utilisateur ne puisse plus changer ces valeurs et aussi pour voir visuellement que le projet a bien été créé.

Est-ce la bonne façon de procéder ?

Pour commencer, j’ai essayé de faire apparaître une “tick box” en début de ligne uniquement lorsque le nom du dossier est calculé mais je n’y arrive pas. Visiblement, les “tick box” doivent toujours être visibles.

Faut-il faire un script qui balaye systématiquement toutes les lignes et qui essaye de créer les projets (création du dossier et création/mise à jour du gsheet) ?

J’ai du mal à commencer et je ne parle pas de la suite.

Merci pour votre aide.

Bonjour,

J'aimerais pouvoir créer un dossier (s’il n’existe pas)

houlà, beaucoup de choses à la fois ... trop long pour moi, je me suis arrêté à la première phrase !

Cette fonction va créer le dossier 'trucmuche' dans ton drive s'il n'existe pas, et retourner son ID.

function getFolderId(name = 'trucmuche'){
  var id;
  var dossiers = DriveApp.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = folders.next();
    id = dossier.getId(); }
  else {
    var dossier = DriveApp.createFolder(name);
    id = dossier.getId();
  }
  return id;
}

Il faut savoir que plusieurs dossiers peuvent avoir un même nom (idem pour les fichiers), seul l'ID est unique. Donc les fonctions créent les dossiers mais retournent surtout leur ID.

Si le dossier doit être créé non pas à la racine du drive mais dans un dossier ...

//créer dossier parent si inexistant et enfant dans parent si inexistant
function test(){
  Logger.log(getEnfantId(getParentId('papa'),'toto'))
}
function getParentId(name){
  // avec création si inexistant dans le drive
  var id;
  var dossiers = DriveApp.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = dossiers.next();
    id = dossier.getId(); }
  else {
    var dossier = DriveApp.createFolder(name);
    id = dossier.getId();
  }
  return id;
}
function getEnfantId(parentId,name){
  // avec création si inexistant dans le dossier parent
  var parent = DriveApp.getFolderById(parentId);
  var id;
  var dossiers = parent.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = dossiers.next();
    id = dossier.getId(); }
  else {
    var dossier = parent.createFolder(name);
    id = dossier.getId();
  }
  return id;
}

Essaie déjà cela, je regarde pour le fichier.

Merci bien, je regarde.

Le mécanisme de création du fichier fonctionne bien. Il faut que j'arrive à récuperer le nom du dossier a créer ainsi que le nom ou l'Id du dossier parent directement dans le gsheet.

j'ai créé un named range, DossierProjets, qui contient l'id du dossier parent.

Les noms des dossiers enfants à créer sont dans la feuille gsheet.

Cordialement

Donc pour créer Toto

//créer dossier parent si inexistant et enfant dans parent si inexistant
function test(){
  Logger.log(getEnfantId(getParentId('DossierProjets'),'toto'))
}
function getParentId(name){
  // avec création si inexistant dans le drive
  var id;
  var dossiers = DriveApp.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = dossiers.next();
    id = dossier.getId(); }
  else {
    var dossier = DriveApp.createFolder(name);
    id = dossier.getId();
  }
  return id;
}
function getEnfantId(parentId,name){
  // avec création si inexistant dans le dossier parent
  var parent = DriveApp.getFolderById(parentId);
  var id;
  var dossiers = parent.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = dossiers.next();
    id = dossier.getId(); }
  else {
    var dossier = parent.createFolder(name);
    id = dossier.getId();
  }
  return id;
}

je regarde les fichiers demain

Pour recopier un template dont tu connais l'ID dans le dossier toto lui-même dans le dossier des projets si tu as sauvegardé l'ID

function cloneGoogleSheet() {
  var dossierId = getEnfantId(dossierProjetsId,'toto')
  var dossierDest = DriveApp.getFolderById(dossierId); 
  DriveApp.getFileById('_______id___du___fichier___template____').makeCopy("nouveau nom à créer", dossierDest); 
}

avec

function getEnfantId(parentId,name){
  // avec création si inexistant dans le dossier parent
  var parent = DriveApp.getFolderById(parentId);
  var id;
  var dossiers = parent.getFoldersByName(name);
  if (dossiers.hasNext()) {
    var dossier = dossiers.next();
    id = dossier.getId(); }
  else {
    var dossier = parent.createFolder(name);
    id = dossier.getId();
  }
  return id;
}

pour aller plus loin, il faudrait maintenant que tu donnes un lien vers un projet-type

Dernière brique à ton projet : écrire xx en A1 de la première feuille du nouveau fichier

function maj(){
  var doc = SpreadsheetApp.openById('______id_du_nouveau_fichier_________');
  var f = doc.getSheets()[0];
  f.getRange('A1').setValue('xx')
}

et un amendement à la fonction ci-dessus pour récupérer l'ID du nouveau fichier

function cloneGoogleSheet() {
  var dossierId = getEnfantId(getParentId('DossierProjets'),'toto')
  var dossierDest = DriveApp.getFolderById(dossierId); 
  return (DriveApp.getFileById('_______id___du___fichier___template____').makeCopy("nouveau", dossierDest).getId()); 
}

Bonjour, j'ai pris un peu de temps pour intégrer tout cela. avec vos indications, j'ai réussi à faire une fonction test() qui fonctionne. Quelle est la façon de procéder pour que le script se déclenche sur les lignes du tableau et puisse récupérer les informations dans les colonnes ?

J'ai créé un gsheet test ici : https://docs.google.com/spreadsheets/d/1XFlshB18_gOYFwTdVI29-ZD_Mkk_oXMv7YTXM87BhaI/edit?usp=sharing

L'accès est refusé

image

Il faudrait partager a minima en lecture https://www.sheets-pratique.com/fr/cours/partage

Faut-il faire un script qui balaye systématiquement toutes les lignes et qui essaye de créer les projets (création du dossier et création/mise à jour du gsheet) ?

Pour déclencher le script, je pense en effet qu'il faut mettre des checkboxes et une script de type onEdt(event)

Exemple

//action sur checkbox :
function onEdit(event){
  var feuille = event.source.getActiveSheet();
  var cellule = event.source.getActiveRange();
  if(feuill.getName()=='leNomDeMaFeuille' && cellule.getColumn()==1){  
    if (cellule.getValue()){ 
      // ici mon script qui peut utiliser la ligne
      var ligne = cellule.getRow()
    }
  }
}

merci bien, je regarde.

j'essaye de voir pour afficher une checkbox uniquement si les conditions pour créer le projet sont remplies (champs non vides). Et que une fois le projet créé pouvoir bloquer la checkbox afin que l'on ne puisse plus clicker dessus.

Connaissant le numéro de ligne (via getRow()), je me demande comment récupérer les valeurs dans les différentes colonnes de cette ligne.

Faut-il passer par des getRange(), par exemple getRange("D" + getRow()) ou y a t'il des fonctions où on indique uniquement la lettre la colonne voir, mieux, un libellé de colonne ?

Attention, ne pas utiliser Logger.log sur onEdit, cela n'a pas de sens car onEdit est généré à partir de la feuille même, pas de l'éditeur de script.

Pourquoi l'éditeur de script a du mal avec cette ligne ? quel est le problème ? Si c'est parce que ligne est grisé, c'est tout simplement que tu n'as pas ensuite d'utilisation de ligne. Le but est maintenant d'utiliser cette valeur ligne dans ce que tu veux faire ... en l'intégrant comme paramètre dans l'appel d'une fonction.

Pour l'aide, voir la bible ici https://developers.google.com/apps-script/reference/spreadsheet/range et notamment getValue(), setValue('xxx')

merci bien.

je regarde cela.

j'ai un soucis avec la fonction DriveApp.getFolderById(parentFolderId); dans la fonction getFolderIdByName(parentFolderId,childName).

Visiblement quand je l'appel via onEdit(event), elle ne fonctionne pas.

[edit]

j'ai trouvé ceci sur stackoverflow.com /questions/40004382/onedite-driveapp-getfilebyid

ok, je m'y attendais un peu ...

https://developers.google.com/apps-script/guides/triggers

onEdit est un "simple trigger" qui ne nécessite pas d'autorisation sauf dans certains cas ("They cannot access services that require authorization.") Il faut donc définir un déclencheur sur cette fonction à chaque modification car tu dois utiliser des fonctions soumises à autorisation.

Il faut donc définir un déclencheur sur cette fonction à chaque modification car tu dois utiliser des fonctions soumises à autorisation

j'avoue ne pas comprendre ce qu'il faut faire concrètement.

Il faut donc définir un déclencheur sur cette fonction à chaque modification car tu dois utiliser des fonctions soumises à autorisation

j'avoue ne pas comprendre ce qu'il faut faire concrètement.

je viens de voir que l'on devait ajouter via l'éditeur, en cliquant sur le "réveil mécanique" que l’on pouvait ajouter un « Triggers ».

J’ai donc ajouté onEdit comme trigger sur l’évènement onEdit.

Est-ce la bonne façon de procéder ou faut-il créer une fonction spécifique (qui porte donc un autre nom que onEdit) pour le triggers sur onEdit ?

Il faut donc définir un déclencheur sur cette fonction à chaque modification car tu dois utiliser des fonctions soumises à autorisation

j'avoue ne pas comprendre ce qu'il faut faire concrètement.

je viens de voir que l'on devait ajouter via l'éditeur, en cliquant sur le "réveil mécanique" que l’on pouvait ajouter un « Triggers ».

J’ai donc ajouté onEdit comme trigger sur l’évènement onEdit.

Est-ce la bonne façon de procéder ou faut-il créer une fonction spécifique (qui porte donc un autre nom que onEdit) pour le triggers sur onEdit ?

et le résultat est correct ?


oui, il y a une façon d'écrire en script le trigger, mais je le fais rarement ! parce que c'est du one shot et qu'ensuite cela ne sert plus, cela encombre le code, un truc du genre

function myTriggerSetup() {
     if(!isTrigger('maFonction')) {
       ScriptApp.newTrigger('maFonction').forSpreadsheet('________id___________').onChange().create();  
     }
}

fonction qu'on doit pouvoir lancer en onOpen(e) ... il faudrait que je me penche un peu plus sur cette question !

merci.

cela semble le faire.

je vais essayer de me pencher sur Google App Sheet pour construire une app user-friendly au dessus de tout cela.

Hello,

je vais essayer de me pencher sur Google App Sheet pour construire une app user-friendly au dessus de tout cela.

voici un exemple

//Intéressant pour initialiser une appli : demande d'autorisation et mise en place déclencheur

function onOpen() {  
  var menu = [    
    { name: "Etape 1: Autoriser",    functionName: "init"},
    { name: "Etape 2: Configurer",   functionName: "configure"},
    null,
    { name: "✖ Désinstaller (Stop)", functionName: "reset"},
    null
  ];  
  SpreadsheetApp.getActiveSpreadsheet()
  .addMenu("➪ Appli ...", menu);
}

function configure() {
  try {
    reset(true);
    var ss = SpreadsheetApp.getActive();
    var email = ss.getRange("B1").getValue();
    if (email == "") {
      Browser.msgBox("Merci d'indiquer votre nom en B1.");
      return;
    }
    ScriptApp.newTrigger("compter")
      .timeBased()
      .everyMinutes(1)
      .create();
    compter();
    ss.toast("L'application est désormais paramatrée.", "Success", -1);
  } catch (e) {
    Browser.msgBox(e.toString());
  }
}

function init() {  
  SpreadsheetApp.getActive().toast("L'application est désormais initialisée. Passez à l'étape #2");
}

function reset(e) {
  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);    
  }
  if (!e) {
    SpreadsheetApp.getActive().toast("Le script n'est plus actif, vous pourrez le réinitialiser plus tard.", "Stopped", -1);
  }
}

function compter(){
  var f=SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
  f.getRange('B3').setValue(f.getRange('B3').getValue()+1)
}
image

je te laisse le recopier dans une nouvelle appli et voir ce que cela donne ...

Bonjour,

merci, bien vu, ajouter un menu en passant par onOpen.

j'en ai profité pour ajouter une try {} catch section.

j'ai ce message d'erreur alors que le job semble être fait correctement :

Exception: You do not have permission to call DriveApp.getFolderById. Required permissions: (googleapis.com /auth/drive.readonly || googleapis.com /auth/drive)

Est-ce un problème de trigger ?

Cordialement

Rechercher des sujets similaires à "creation dossier modification gsheet conditions"