Fichier de commande envois automatique + pdf
Bonjour
Apres quelque sujet ET avoir pas mal parcouru vos tutos / cours qui mon fortement aidé
J 'ai grâce a vous notamment améliorer / éviter les erreurs du fichier existant en place utilisé par mes collaborateurs précèdent ( tout était à la manuel..... )
Bref un fichier de suivit de commande / facturation ci joint
je constate que je suis malgré mes efforts pas très doué j 'ai réussi a obtenir un bon résultat ci joint le fichier qui fonctionne !!!
(pas trop mal pour le novice que je suis mais j 'ai besoin de vos conseils)
https://docs.google.com/spreadsheets/d/1mzqDCmEVP9YSQK1MpwBShh0zL_RndHpDVDZZ0I19QOQ/edit?usp=sharing
Plusieurs sujet sur mon fichier joint vont nécessité vos avis
- 1 er point le script me semble long a l 'exécution ceci est sans doute du a mes nombreuse variable j 'ai sans doute trop ??? votre avis
- 2 eme point
je rencontre une difficulté l 'avantage de Sheets est de pouvoir bosser a plusieurs sur le même fichier
mais la création de ma commande me permet de bosser sur une seul page commune ce qui est bloquant lorsque plusieurs utilisateur veulent crée une commande au même moment!! d 'ailleurs la création de la commande en doublons crée aussi une ligne de commande problématique a tester en simultanée
option 1 crée autant de page que d 'utilisateur et liée l 'utilisateur a la page de commande définit ( vous me suivez bien sur ?? )
option 2 votre idée ??
- 3 eme point
je cherche le moyen de valider facilement la facturation je reçois la facture avec le numéros de commande et le code chantier
majoritairement donc suivant je dois trouver la ligne de la commande et valider celle ci
j 'apprécie le forum et j'apprecie pouvoir échanger étant seul a progresser sur ce domain
Si lors de votre reponse vous pouvez me donner des piste et pas une solution toute faite cela serait ideal pour ma progression
ou bien des fichiers auquel je pourrait m 'inspiré pour modifier mon code
merci a vous encore une fois
Bonjour,
J'ai été voir succinctement vu ton fichier + script.
1- script long :
Il y a des variables que tu utilises à de nombreuses reprises et qui pourrais être des constantes, à mettre dans le scope global (càd en dehors des fonctions), par exemple, tes feuilles, au lieu d'avoir toutes ces lignes :
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
const pageactive = SpreadsheetApp.getActiveSheet().getSheetName();
//Logger.log(celluleA1)
if (pageactive == 'COMMANDE') {
...
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
const pageactive = SpreadsheetApp.getActiveSheet().getSheetName();
//Logger.log(celluleA1)
if (pageactive == 'COMMANDE') {
...
// DECLARE LA VARIABLE DE ID DOSSIER
var pagecommande = spreadsheet.getSheetByName('COMMANDE');
var pageimpre = spreadsheet.getSheetByName('COMMANDE IMPRESSION')
var newlignechrono = spreadsheet.getSheetByName('2024')Tu déclare au haut de ton script, à l'instar de FOLDER_ID toutes tes feuilles :
const SS = SpreadsheetApp.getActiveSpreadsheet();
const SHEET_COMMANDE = SS.getSheetByName('COMMANDE');
const SHEET_IMPRESSION = SS.getSheetByName('COMMANDE IMPRESSION');
const SHEET_LIGNES_CHRONO = SS.getSheetByName('2024');
...Ensuite, tu as j'ai l'impressions des bouts de script qui font la même chose, il faut mieux avoir 12 function que 3, par exemple créer l'URL du document.
Autre point ensuite, tu peux inserer des console.time("label") / console.timeEnd("label") afin de chronométrer les executions et voir quelles sont tes fonctions chronophage.
Dernier point concernant le gains de temps, ce genre de script prends tu temps, il faut mieux avoir une liste, dictionnaire avec les éléments et itérer en une fois pour prendre les données et en une fois pour les écrire :
var montant = pagecommande.getRange('L40').getValue()
var nomchantier = pagecommande.getRange('F6').getValue()
var codechantier = pagecommande.getRange('F7').getValue()
var date = pagecommande.getRange('K4').getValue()
var entite = pagecommande.getRange('K5').getValue()
var fournisseur = pagecommande.getRange('K8').getValue();
var cellmontant = newlignechrono.getRange("H5");
cellmontant.setValue(montant);
var cellnomchantier = newlignechrono.getRange("E5");
cellnomchantier.setValue(nomchantier);
var cellcodechantier = newlignechrono.getRange("D5");
cellcodechantier.setValue(codechantier);
var celldate = newlignechrono.getRange("A5");
celldate.setValue(date);
var cellentite = newlignechrono.getRange("F5");
cellentite.setValue(entite);
var cellfournisseur = newlignechrono.getRange("G5");
cellfournisseur.setValue(fournisseur);
var lienurl = newlignechrono.getRange("P5");
lienurl.setValue(docUrl)
var lienurlsheet = newlignechrono.getRange("Q5")
lienurlsheet.setValue(newSpreadSheet.getUrl())
var lienurldossier = newlignechrono.getRange("R5")Concernant le coté "collaboratif", en effet s'il faut remplir une page sheet, puis exectuer une fonction pour travailler sur cette page, une personne peut travailler à la fois, une solution serai de passer par un formulaire en popup, ou en barre latérale :
https://sheets-pratique.com/fr/apps-script/fenetres-personnalisees
https://sheets-pratique.com/fr/codes/sidebar
Pour ta facturation, j'ignore si c'est dans le même fichier mais lors de la génération d'une commande tu peux exectuer un petit script qui vient écrire une ligne dans ton fichier de suivi de facturation et qui écris par exemple :
intel a crée tel commande / pour tel fournisseur / tel montant / tel échéance
MERCI pierre
j 'étudie ton poste ce jour et je reviens
JE TE CITE
"Ensuite, tu as j'ai l'impressions des bouts de script qui font la même chose, il faut mieux avoir 12 function que 3, par exemple créer l'URL du document."
OUI c 'est vrai par exemple j 'ai fonction "envoyez la commande" qui me crée la page commande en impression PDF et en Sheets, qui crée le dossier dans nommé de la commander dans le drive qui crée l' envois par mail
ET
j 'ai la fonction "enregistré la commande " qui me crée la page commande en impression PDF et en Sheets, qui crée le dossier dans nommé de la commander dans le drive
Effectivement c 'est des doublons de tache il faudrait que je divise celle ci en fonction "envois mail", "création dossier", "creation pdf ", "creation sheet" et que je les appels dans ma fonction "envoyé la commande " et c 'est ca ?
JE TE CITE
"il faut mieux avoir une liste, dictionnaire avec les éléments et itérer en une fois pour prendre les données et en une fois pour les écrire :"
le je t 'ai pas compris un exemple ?
Effectivement c 'est des doublons de tache il faudrait que je divise celle ci en fonction "envois mail", "création dossier", "creation pdf ", "creation sheet" et que je les appels dans ma fonction "envoyé la commande " et c 'est ca ?
Ce que tu peux faire c'est une fonction "genereUrl(feuille)" par exemple
dans ta fonction envoiMail() au moment ou tu as besoin de l'url tu fais un truc du genre :
let url = genreUtl(feuille);(en passant comme argument la feuille a générer comme url).
"il faut mieux avoir une liste, dictionnaire avec les éléments et itérer en une fois pour prendre les données et en une fois pour les écrire :"
le je t 'ai pas compris un exemple ?
Par exemple, au lieu de :
cette fonction pas optimisé :
function myFunction() {
console.time('test_unit');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
var val1 = sheet.getRange('A1').getValue();
var cellVal1 = sheet.getRange('A20');
cellVal1.setValue(val1);
var val2 = sheet.getRange('B2').getValue();
var cellVal2 = sheet.getRange('A21');
cellVal2.setValue(val2);
var val3 = sheet.getRange('C3').getValue();
var cellVal3 = sheet.getRange('A22');
cellVal3.setValue(val3);
var val4 = sheet.getRange('D4').getValue();
var cellVal4 = sheet.getRange('A23');
cellVal4.setValue(val4);
var val5 = sheet.getRange('E5').getValue();
var cellVal5 = sheet.getRange('A24');
cellVal5.setValue(val5);
var val6 = sheet.getRange('F6').getValue();
var cellVal6 = sheet.getRange('A25');
cellVal6.setValue(val6);
var val7 = sheet.getRange('G7').getValue();
var cellVal7 = sheet.getRange('A26');
cellVal7.setValue(val7);
var val8 = sheet.getRange('H8').getValue();
var cellVal8 = sheet.getRange('A27');
cellVal8.setValue(val8);
console.timeEnd('test_unit');
}On fait ceci avec un dictionnaire :
function myFunction2() {
console.time('test_dic');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
const map = {
'A1': 'A20',
'B2': 'A21',
'C3': 'A22',
'D4': 'A23',
'E5': 'A24',
'F6': 'A25',
'G7': 'A26',
'H8': 'A27'
};
const valuesToSet = [];
for (const sourceCell of Object.keys(map)) {
const value = sheet.getRange(sourceCell).getValue();
valuesToSet.push({ value, targetCell: map[sourceCell] });
}
valuesToSet.forEach(({ value, targetCell }) => {
sheet.getRange(targetCell).setValue(value);
});
console.timeEnd('test_dic');
}bon j 'ai déjà diviser mes fonctions
mais j'ai de nouveau des problèmes de code me revoila il y a 2 mois en arrières
je comprend pas cette partie de code
const valuesToSet = []; for (const sourceCell of Object.keys(map)) { const value = sheet.getRange(sourceCell).getValue(); valuesToSet.push({ value, targetCell: map[sourceCell] }); } valuesToSet.forEach(({ value, targetCell }) => { sheet.getRange(targetCell).setValue(value); });mais le cours qui s 'en approche n 'est pas totalement dans la même destination me semble t 'il
https://sheets-pratique.com/fr/apps-script/boucles
je continuerais ce soir
merci
Bonjour,
Voici une petite parenthèse en passant pour aider zinc78 (et qui intéressera peut-être Pierre).
Quand j'ai vu les 2 codes dans le post de Pierre (myFunction et myFunction2), je me suis demandé pourquoi il y avait une telle différence de timer alors qu'en réalité il y a le même nombre d'appels à getValue/setValue (sachant que ce n'est pas l'utilisation d'un objet {} qui en est la cause)
Après quelques tests, il semblerait que le fait de faire tous les getValue puis tous les setValue soit beaucoup plus rapide que d'alterner getValue/setValue, getValue/setValue, ...
Cela dit, je m'étonne quand même qu'un si petit nombre d'appels à getValue/setValue puisse générer un code aussi lent
je comprend pas cette partie de code
const valuesToSet = []; for (const sourceCell of Object.keys(map)) { const value = sheet.getRange(sourceCell).getValue(); valuesToSet.push({ value, targetCell: map[sourceCell] }); } valuesToSet.forEach(({ value, targetCell }) => { sheet.getRange(targetCell).setValue(value); });mais le cours qui s 'en approche n 'est pas totalement dans la même destination me semble t 'il
Effectivement, ça doit être difficile à comprendre si tu as suivi le cours Apps Script uniquement et dans ce cas, ça peut être fortement simplifié.
Dans ce cas, Pierre a utilisé un objet {} pour lister les paires, puis a créé une boucle pour mettre ça dans un tableau [], puis a parcouru le tableau pour affecter les valeurs aux cellules.
Il n'y a pas de boucles sur un objet {} dans le cours car c'est rarement utile avec Google Sheets ... Dans ce cas, il aurait été plus simple d'utiliser directement un tableau plutôt que de passer d'un objet à un tableau.
Voici une version simplifiée du code myFunction2 de Pierre :
function myFunction3() {
console.time('test_dic');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
const tab = [
['A1', 'A20'],
['B2', 'A21'],
['C3', 'A22'],
['D4', 'A23'],
['E5', 'A24'],
['F6', 'A25'],
['G7', 'A26'],
['H8', 'A27']
];
tab.forEach(i => sheet.getRange(i[1]).setValue(sheet.getRange(i[0]).getValue()));
console.timeEnd('test_dic');
}Bien sûr, comme je le disais dans le cours, si tu n'es pas à l'aise avec les méthodes de tableau (ici, forEach), tu peux aussi le faire avec une boucle for :
function myFunction4() {
console.time('test_dic');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
const tab = [
['A1', 'A20'],
['B2', 'A21'],
['C3', 'A22'],
['D4', 'A23'],
['E5', 'A24'],
['F6', 'A25'],
['G7', 'A26'],
['H8', 'A27']
];
for (let i = 0; i < tab.length; i++) {
const tabPaire = tab[i];
const valeur = sheet.getRange(tabPaire[0]).getValue();
sheet.getRange(tabPaire[1]).setValue(valeur);
}
console.timeEnd('test_dic');
}Mais bon, le problème reste le même qu'avec ton code initial, c'est très lent ...
On va donc récupérer d'abord toutes les valeurs puis affecter toutes ces valeurs aux cellules pour accélérer le code :
function myFunction5() {
console.time('test_dic');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
let tabValeurs = ['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8'];
const tabCibles = ['A20', 'A21', 'A22', 'A23', 'A24', 'A25', 'A26', 'A27'];
tabValeurs = tabValeurs.map(i => sheet.getRange(i).getValue());
tabCibles.forEach((i, j) => sheet.getRange(i).setValue(tabValeurs[j]));
console.timeEnd('test_dic');
}Note qu'on peut aussi simplifier le code comme ceci :
function myFunction5b() {
console.time('test_dic');
const sheet = SpreadsheetApp.getActive().getSheetByName('Feuille 1');
const tabValeurs = ['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8'].map(i => sheet.getRange(i).getValue());
['A20', 'A21', 'A22', 'A23', 'A24', 'A25', 'A26', 'A27'].forEach((i, j) => sheet.getRange(i).setValue(tabValeurs[j]));
console.timeEnd('test_dic');
}Voila pour la "petite" parenthèse
Je laisse la suite à Pierre.
Bonjour et merci pour cette intervention, le temps d’exécution de myFunction5b permet en effet un gain de temps :
@Zinc78 comme tu peux le voir il y a de multiples moyens d'atteindre ton objectif, ce qui compte et qui est "simple" à comprendre c'est qu'il faut mieux faire une seule action pour récupérer les données et une seule action pour les écrire que de faire 8 lectures, puis 8 écritures.
Concernant mon utilisation d'un objet {} plutôt qu'une liste [] dans une telle situation il y a plusieurs raisons, l'objectif ici est de lister des cellules d’origines vers des cellules de destination :
- il ne peut y avoir de doublon dans les clés
- temps d’exécution plus rapide
- possibilité d'atteindre les données avec des noms au lieu de s'embrouiller dans les dimension
Par exemple, pour simplement ensuite retrouver des infos :
const map = {
'téléphone': 'A1',
'adresse': 'B2',
'siret': 'C3',
'email': 'D4',
'nom': 'E5',
'prénom': 'F6',
'cp': 'G7',
'ville': 'H8'
};Afin de récupérer la cellule de l'email il suffit de faire : map['email'].
Il y a toutefois des limites, c'est moins pratique qu'une simple liste, pas 2 fois la même clé, plus compliqué d'itérer dessus (on ne peut pas simplement boucler dessus, prévoir un pas est plus complexe aussi).
Si ta page n'est pas amené a être modifié et que tu veux le plus simple possible, voici une solution la + simple possible :
function myFunction6() {
console.time('test_unit');
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Feuille 1');
const cellOrigines = ['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8']; // cell d'origines
const cellDestination = ['A20', 'A21', 'A22', 'A23', 'A24', 'A25', 'A26', 'A27'];// cell destinations
const values = cellOrigines.map(cell => sheet.getRange(cell).getValue());
cellDestination.forEach((target, i) => sheet.getRange(target).setValue(values[i]));
console.timeEnd('test_unit');
}
Bonjour Pierre,
le temps d’exécution de myFunction5b permet en effet un gain de temps :
Je ne pense pas que ma version 5b soit vraiment plus rapide que ta version 2 (parfois le temps affiché dans l'éditeur varie presque du simple au double pour une même fonction, ce n'est pas très précis), le but était surtout de proposer à zinc78 une version un peu plus facile à comprendre pour lui.
temps d’exécution plus rapide
C'est une fausse croyance que de penser que c'est plus rapide, en réalité objet ou tableau c'est à peu près la même rapidité d'exécution, donc à chacun de choisir ce qu'il préfère utiliser
Mais pour le vérifier, j'ai récupéré une partie du code 5b et du code 2, j'ai supprimé les éléments spécifiques à Apps Script, j'ai bouclé le tout 100'000 fois et j'ai obtenu une durée de 101ms pour chacun des codes. Autrement dit, que ce soit tableau ou objet, c'est similaire et très rapide dans les 2 cas
L'autre chose qu'ont peut remarquer est que si ça fait 101ms pour 100'000 exécutions, ça ne représente donc que 0.001ms pour une exécution ... Le choix [] ou {} a donc un impact complètement négligeable pour un script Apps Script de 300ms (j'ai tenu à te le préciser car si tu t'imposes l'utilisation de {} en pensant que c'est plus rapide, c'est un peu dommage).
Cordialement,
OUI le plus simple a comprendre parce que je suis aussi lent que mon code
c 'est une vrai galere !! merci
J'ai débuté par du python, en apprenant qu'un dictionnaire permettais une exécution plus rapide qu'une liste et en effet je transpose cette idée dans les autres langages que j'utilise
À titre personnel, j'utilise les listes pour des besoins "simple" et les dictionnaires pour des objets complexes, avec de multiples sous niveau, pour s'y retrouver plus facilement entre le frontend et le backend.
Bon suite a vos messages je recommence ,
j 'ai donc identifier une majorité de mes constantes il faut encore que je place en majuscule pour faciliter la lecture des constantes
je me suis dit qu' 'il serait peu être judicieux d 'ouvrir un fichier pour les fonctions qui se répète de manière à l appeler dans la fonction général
du genre envois mail ou sauvegarde PDF ou copie de cellule
mais il semble que j 'ai louper une étape non ??
c 'est quand même vachement compliquer de ce retrouver dans ce code général niveau organisation on peu faire comment ??
Bonjour,
Ton fichier n'étant pas si complexe, je ne mettrais que 2 fichiers :
onOpen.gs
script.gs
Je vais tenter de t'aider dans test_script.gs
Je vais remettre à plat tes différentes fonctions, il y toutes des incohérences ou des choses que j'ignore, pour cela je vais ajouter mes annotations entre /* ... */
EDIT : c'est bon, j'ai restructuré ton code dans le fichier test_script.gs, va voir si tout est correct, étape par étape, j'ai mis des breakpoints au niveau des points d'attention. + une partie du script n'était dans aucune fonctionne, je te l'ai mis en bas, revient moi si besoin.
merci pierre t 'n fais beaucoup de ce que je vois
je comprend pas (j 'ai du être un peu trop léger sur le cours)
savePDF(idFichier, nomFichier) -> pourquoi id fichier, nomFichier entre parenthèse ??
pareil pour ca
const nomDossier = `${nom}-${fournisseur}-`;
ca doit allez avec ca
@param {boolean} [envoyerParMail=true] - Indique si l'email doit être envoyé. */
mais ca sort de quel cours ?
Voici une explication succinte :
j'ai 2 fonction, une grosse fonction qui fait plein de chose, elle a besoin de faire des additions et de les inscrire dans une cellule.
Plutôt que de répéter plusieurs fois les opérations, je vais faire une fonction dédié, qui additionne 2 nombres, met le total dans une cellule et le renvoie à la grosse fonction pour qu'elle s'en serve ultérieurement :
function grosseFonction(){
// bla bla
var nombre1 = 1656;
var nombre2 = 6684;
var totalNombre1PlusNombre2 = additionne2Nombres(nombre1,nombre2);
//bla bla
}
/** Additionne 2 nombres et inscrit le total dans une feuille et le renvoie.
* @param {number} nombre1 - Premier nombre à additionner.
* @param {number} nombre2 - Second nombre à additionner.
* @returns {number} total - le total de l'addition
*/
function additionne2Nombres(nombre1,nombre2) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var total = nombre1+nombre2;
sheet.getRange('A1').setValue(total);
return total;
}les 2 nombres, sont envoyés en arguments dans la fonction d'addition : (ils sont entre parenthèse) car nombre1 et nombre2 étant déclarés dans la grosse fonction, ils n'existent pas dans les autres fonctions.
+ j'ai créé une variable totalNombre1PlusNombre2 qui va contenir le résultat.
var nombre1 = 1656;
var nombre2 = 6684;
var totalNombre1PlusNombre2 = additionne2Nombres(nombre1,nombre2);En entête de la fonction, on documente à quoi elle sert, quels sont les arguments attendus, dans notre cas, 2 nombres, pour les additionner.
puis, ce qu'elle renvoie, dans cet exemple, un nombre, le total.
/** Additionne 2 nombres et inscrit le total dans une feuille et le renvoie.
* @param {number} nombre1 - Premier nombre à additionner.
* @param {number} nombre2 - Second nombre à additionner.
* @returns {number} total - le total de l'addition
*/Ensuite, la fonction en elle même, je déclare la sheet ici mais j'aurais pu le faire en global (une déclaration globale est accessible par toutes les fonctions).
Puis, j'additionne les 2 nombres reçus, j'inscrit le total dans une cellule, et je renvoie le total.
function additionne2Nombres(nombre1,nombre2) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var total = nombre1+nombre2;
sheet.getRange('A1').setValue(total);
return total;
}Si je prends un exemple concret, dans ton script, l'envoi du fichier par email, dans ta fonction validerlacommande on transmet en argument l'url du nouveau fichier et le nom de celui ci :
envoismail(docUrl, nomFichier);
Donc, dans la documentation on explique à quoi sert cette fonction, puis, qu'elle attends 2 arguments, l'url du fichier (format string = texte) et le nom du fichier (format string = texte) :
/**
* Envoie un fichier par email.
* @param {string} docUrl - URL du fichier à envoyer.
* @param {string} nomFichier - Nom du fichier à envoyer.
*/Puis, la fonction en elle même utilise les arguments, celle-ci ne renvoie rien, mais on pourrait imaginer qu'elle créer un horodatage et le renvoie pour que tu puisse inscrire quelque part que le mail a été envoyé à telle date + heure :
function envoismail(docUrl, nomFichier) {
const email = PAGECOMMANDE.getRange('K10').getValue();
const fichier = `${nomFichier}.pdf`;
const objet = `Commande ${nomFichier}`;
const corps = "Veuillez trouver ci-joint la commande suivant votre devis en référence.";
const pdf = UrlFetchApp.fetch(docUrl).getBlob(); // Récupérer le blob du PDF à partir de l'URL
GmailApp.sendEmail(email, objet, corps, {
htmlBody: corps,
attachments: [{
fileName: fichier,
content: pdf.getBytes(),
mimeType: "application/pdf"
}]
});
Browser.msgBox(`Commande envoyée par mail à ${email}`);
}si je comprend bien
j 'avais précédemment commencer a faire des "const" mais ca rassemblais trop de ligne donc
ont raccourcis en utilisant des variables qui seront utilisé dans d 'autre fonction
en écrivant
Function additionne2Nombres (nombre1,nombre2) // les variables que l 'on appel pour notre fonction et qui sont dans d 'autre Function
le texte ecrit avant est juste a titre informatif pour le codeur ??
* @param {number} nombre1 - Premier nombre à additionner.
* @param {number} nombre2 - Second nombre à additionner.
Alors, les données stockées peuvent l'être le plusieurs façons, une constante en gros c'est de la lecture et variable on peut lire et écrire.
Quand on créer une var/const dans une fonction, elle est accessible que dans celle ci, il y a donc 2 moyen de transférer des données entre plusieurs fonctions :
> stocker les données dans la portée globale, ainsi, les données seront accessible partout, dans ton fichier, ce sont les noms des feuilles.
> transférer une donnée à une autre fonction comme argument, c'est dans mon exemple un nombre, on le déclare dans une fonction et on le transmet dans une autre comme argument.
La partie verte au dessus des fonction, c'est de la documentation, ça sert à s'y retrouver et ne pas faire une code illisible, le but est d'expliquer à quoi sert la fonction, ce qui rentre et ce qui sort.
ok ca je comprend !!
donc après test bah ca fonctionne plus forcement ....
je m y retrouve même plus dans mes fonctions
tous a la suite c 'est compliqué des sous fonction appelé dans une fonction je m y perd complet
j 'ai le cerveau en fusion
vous faite comment vous pour vous y retrouver ??
Des logs ! Et y aller étape par étape, n'ayant pas les accès je ne peux effectuer les tests de mon coté, mais je t'ai ajouté quelques logs, essaye de lancer des fonctions, puis, va dans la fenêtre apps script dans l'onglet "Exectuions" > clique sur une fonction que tu as lancé et tu pourras lire ce qui se passe :
Dans un premier temps, j'ai ajouté un log à chaque lancement de fonction, qui dit quelle fonction se lance et quels sont ses arguments, j'ai cliqué ensuite dans le menu sur "Enregistrer la commande", voici le résultat :
Donc, la fonction validercommandesansenvoismail se lance bien > OK
ensuite, elle exécute validercommande en mettant bien le paramètre FAUX pour l'envoi du mail > OK
J'ai ensuite une erreur ligne 44 > NOT OK
voici la ligne concernée :
const listeDossier = DriveApp.getFolderById(FOLDER_ID);On déclarare la constante du dossier G-Drive issu de FOLDER_ID :
const FOLDER_ID = "1QSmpYiyrOi4LHYV6u4YOBfG7jmBuuxjj"; // ID du dossierN'ayant pas accès à ce dossier, le script s'arrête ici me concernant.
Essayes de lancer tes différents fonctions et vois si ça ne marche pas, est ce que tes fonctions se lancent bien, où si tu as des erreurs, quelles-sont-elles.
MàJ
Pour t'aider j'ai mis un de mes drive test, et ainsi debug, voici donc la situation, toujours avec la requête : "Enregistrer la commande"
Comme tu peux le voir, le souci est dans la fonction copyInNewSheet, l'erreur est qu'on ne peut supprimer toutes les feuilles visibles d'un document, cela concerne la ligne où on tente de supprimer "Feuillle 1".
Le problème était que PAGEIMPRESSION est copié masqué, ainsi, le script ne pouvais supprimer Feuille 1, il faut donc dé-masquer la nouvelle feuille avant, comme ceci :
const copySheet = PAGEIMPRESSION.copyTo(copiesheetcommande).setName(nomFichier);
copySheet.showSheet();Une fois ce point réglé, si on relance la même fonction, on avance plus loin :
Cette fois on bloque dans la fonction validerlacommande, à la ligne 61 de ton script, car "getUrl" ne renvoi rien ici :
NEWLIGNESCHRONO.getRange('Q5').setValue(newSPREADSHEET.getUrl());L'url est issu de newSPREADSHEET qui est déclaré ici :
const newSPREADSHEET = copyInNewSheet(nomFichier, idFichier);c'est normalement le retour de la fonction copyInNewSheet, donc, on y retourne :
/**
* Crée un nouveau fichier Sheet avec un nom défini dans un dossier défini.
* @param {string} nomFichier - Nom du fichier.
* @param {string} folderId - ID du dossier de destination.
* @returns {newSPREADSHEET} - La nouvelle feuille de calcul créée.
*/
function copyInNewSheet(nomFichier,folderId) {
console.log("lancement de la fonction copyInNewSheet avec en nomFichier : "+nomFichier)
const copiesheetcommande = SpreadsheetApp.create(nomFichier);
const copySheet = PAGEIMPRESSION.copyTo(copiesheetcommande).setName(nomFichier);
copySheet.showSheet();
var newFile = DriveApp.getFileById(copiesheetcommande.getId());
newFile.moveTo(DriveApp.getFolderById(folderId))
// Supprimer l'onglet par défaut
const defaultSheet = copiesheetcommande .getSheetByName("Feuille 1");
copiesheetcommande.deleteSheet(defaultSheet)
}Et c'est là que la documentation est intéressante, tu vois j'ai bien spécifié dans la doc que cette fonction retourne la feuille créée :
* @returns {newSPREADSHEET} - La nouvelle feuille de calcul créée.Le but est de s'en servir ensuite, dans d'autre fonction, or, le retour à disparu à la fin de la fonction, il suffit donc de le remettre :
return copiesheetcommande;Maintenant on relance :
On arrive plus loin encore, cette fois ci ligne 8, la variable cliquelien n'existe pas...etc...
bon j 'essaye d 'appliquer des teste mais j 'ai toujours des problemes
lors de l'application de la fonction "validerlacommandesansenvoismail"
erreur en ligne 87
il semble que "urldossier " n 'est pas définit
pourtant je le récupère "urldossier " dans la fonction "validerlacommande" en ligne 48
donc je me suis dis je la met en return-> par contre si je la met en return sur la ligne 48 le reste de ma fonction le teste devient grisatre ???
donc je la place en const et en fin de ma fonction validelacommande je place
au titre de la fonction "validerlacommandesansenvoismail" j 'ai mi entre parenthèse (urldossier) pour qu' il aille récupère la valeur
est ce que c 'est en raison d 'une boucle ??
lors de l'application de la fonction "validerlacommandel"
erreur en ligne 142 la j 'ai une erreur mais je ne sais pas pourquoi d 'ailleurs comment fait ont pour connaitre précisément les erreur ??
Il n 'existe pas un tuto expliquant les onglet de gauche et la présentation générale de script ??
je crois également que je peu supprimer la page impression celle ci n 'a il me semble plus d 'utilité et je gagnerais du temps !!