Comment j'ai créé un service de contrôle qualité à partir de tables et de bâtons

Bonjour, Habr! Souvent, lorsqu'ils envisagent de lancer un pilote, les gestionnaires commencent à compliquer la situation, à créer des feuilles de route et à attendre le MVP des développeurs, au lieu de prendre et de tester l'idée par eux-mêmes. Sous la coupe, je veux partager l'histoire de la création d'un service de contrôle de qualité basé sur les formulaires Google, VK et des dizaines de lignes de code, dans lequel aucun développeur n'a été blessé, seulement 1 agent de commercialisation.



Avertissement : dans cet article, j'attends des exemples de code qui vous poseront des questions, des doutes, peut-être même des larmes sanglantes et la cécité. Pour le justifier, il n'y a qu'une seule chose à dire - ce code a fonctionné comme Papa Carlo, et a rempli sa mission à 100%, et certains scripts fonctionnent toujours.

Évaluation du First Dodo Pizzeria


L'un des grands principes de notre entreprise - celui qui ne peut pas être mesuré, n'existe pas . La pizza existe, ce qui signifie que vous devez en quelque sorte évaluer sa qualité.

Tout a commencé en 2013. A cette époque, il y avait 7 pizzerias sur le réseau. Puis, à Dodo, ils ont décidé de lancer un projet de contrôle de la qualité et des normes des produits - une note de pizzerias ouverte à tous les partenaires.

Il ressemblait à ça.



Les données ont été tirées des appels des clients, des avis sur le social. réseaux et un peu de Dodo IS (notre système d'information).

Un plus évident à cette époque - la notation a commencé à pousser les pizzerias à gérer la qualité pour être au top.

Pizzerias Second Mystery Shop


Environ un an plus tard, nous avons réalisé que nous devions évaluer le produit lui-même et avons pris le fameux modèle - «mystery shoppers». À ce moment, nous avons fait une percée - le premier en Russie a décidé que nos clients seraient les acheteurs mystères.

L'émergence d'un groupe fermé VK


Au départ, nous avons découvert comment ils travaillent avec les clients mystères dans les agences qui fournissent de tels services. Il s'est avéré qu'ils communiquaient par e-mail ou appelaient directement pour proposer une vérification.

Cette option ne nous a pas immédiatement séduits. Nous n'allions certainement pas appeler, car pour nous, c'était long, mais pour un client, c'était douloureux et comparable au spam. Le courrier était utilisé pour les envois de masse, mais il a été rapidement abandonné.

Nous avons trouvé:

  1. Pour la communication avec les agents secrets et la coordination des contrôles, ils ont utilisé la page habituelle en VK.
  2. Pour collecter des reportages photo, ils ont créé un groupe à VK avec un mur ouvert.
  3. Et pour les enquêtes de service, nous avons choisi les formulaires Google. Quoi? Idéalement, vous n'avez pas besoin de couper un service distinct, et il est bien affiché sur le téléphone mobile.
  4. Toutes les instructions étaient dans Google Docs.

Tout est à genoux. Tout est comme il se doit pour une startup.


Photo d'un client mystère. Oui, ils ont mesuré la largeur avec une règle, ont coupé le bord de la pizza pour montrer la cuisson et la qualité de la pâte.

Plus d'exemples de reportages photo de 2015 sont ici.





La note changeait constamment, de nouveaux critères d'évaluation ont été ajoutés. Par exemple, il s'agit de 131 points pour l'évaluation de la pizzeria Abakan-1.



L'enfer du processus était que toutes les violations des points étaient notées manuellement, pas d'automatisation. Et tout cela a été fait par un employé.

La magie des feuilles de calcul Google


En 2016, nous avons appris (mûri) que l'humanité a longtemps inventé des fonctions autres que = SUM. Et ce qui peut être fait en utilisant des scripts et des fonctions d'importation de données entre les tables ... Construction CRM directe.

Par exemple, pour évaluer chaque pizzeria dans le tableau était une feuille, et en elle les critères d'évaluation et les scores. 1 pizzeria = 1 feuille. Plus il y a de pizzerias, plus il y a de feuilles. Chaque semaine, un nouveau signe. En appuyant sur le bouton magique, la feuille de modèle dans le tableau a été développée en 120 feuilles. Wah, comme c'est bon!



Cette étape de l'automatisation «Dodo Controlling» a duré environ six mois. Nous avons progressé pas à pas: nous avons appris quelque chose de nouveau - mis en œuvre, nous avons appris quelque chose d'autre de nouveau - introduit à nouveau.

La limitation comme moteur de progrès


Dès le début, nous avons parlé avec des acheteurs mystères au nom d'un compte personnel dans VK. Et puis est venu le jour où nous avons été confrontés à des problèmes insolubles de pages personnelles:

  • il y a une limite de 10 000 amis;
  • Il y a une limite à l'envoi de messages: parfois nous ne pouvions pas envoyer de messages, parce que VK nous bloquait avec la formulation «vous avez envoyé trop de messages, venez demain».

Habituellement, VK a bloqué l'envoi de messages vers 16h00. C'était une happy hour où l'équipe pouvait se reposer.

Peu à peu, nous avons rencontré presque toutes les limites du VK et avons presque réussi à cesser d'aimer ce site. Mais un miracle s'est produit et VK a donné aux groupes la possibilité de connecter des widgets de messages, des robots de discussion et d'autres goodies.

En fait, cette possibilité était antérieure à décembre 2016, mais avec une limitation critique pour nous: le groupe ne pouvait répondre au message que dans les 10 jours suivant l'envoi du dernier message du client. Lorsqu'ils ont supprimé cette restriction, la vie de notre équipe a commencé à briller de nouvelles couleurs. Depuis lors, nous avons commencé la voie de l'automatisation à l'aide de l'API VK et des feuilles de calcul Google.

Peur et dégoût dans un script utilisateur


Au départ, pour devenir un client mystère, vous deviez remplir un formulaire, puis postuler au groupe, nous écrire un mot de code et attendre que nous répondions. Cette attente peut durer jusqu'à 48 heures. Elle a été indécemment longue et le désir de procéder à des vérifications après cet enregistrement s'est estompé.

Avec un nouveau magasin de connaissances, nous avons commencé à automatiser l'enregistrement.

Nous avions plusieurs méthodes API, un formulaire, plusieurs dizaines de tableaux, une page de destination, un bot en PHP, des scripts dans le tableau qui ont été écrits par le marketing le plus cool Dodo et le premier directeur financier de Dodo en une seule personne, des dizaines de modèles de messages pour différentes situations. Ensuite, je ne savais même pas que cela s'appelait un script utilisateur:

  1. Le client mystère a rempli un questionnaire (il s'agit d'une version obsolète et maintenant elle ne fonctionne plus).
  2. Les données du formulaire sont tombées d'abord dans la base de données, puis dans le tableau. Le bot a d'abord frappé la base de données pour vérifier les données sur le profil, car le délai de réponse de la plaque en dizaines de milliers de lignes était important, et la base de données la digérait facilement).
  3. Après avoir rempli le questionnaire dans le formulaire, un message est apparu à l'écran: «Merci, il reste à rejoindre le groupe (lien) et à écrire le mot de code« Sherlock »».
  4. Ensuite, le client mystère a envoyé une demande pour rejoindre le groupe et a écrit le mot de code "Sherlock". Le mot a été le déclencheur pour exécuter le script de validation:
    - une demande a été envoyée à la base de données pour savoir si l'agent nous convient selon l'âge;
    - si oui, alors la personne a été ajoutée aux groupes, et dans le tableau en face du questionnaire du candidat, le statut «ok / not ok» a été noté;
    - Plus de données ont été peintes en couleur turquoise et c'était important. Donc, avec mes yeux, il était plus facile de comprendre qui nous convient et avec qui nous pouvons parler. Le script a peint des profils rouges inappropriés;
    - puis l'acheteur secret a été automatiquement accepté dans le groupe, et un message a été envoyé au chat avec d'autres étapes et instructions.



Telle est l'automatisation de l'enregistrement. Maintenant, toute la procédure est devenue presque simple et compréhensible.

De plus, tout s'est passé comme sur des roulettes. Il est devenu clair que nous pouvons envoyer des messages via des tables directement à PM à des agents secrets via des messages de groupe.



Et vous n'aviez que 46 lignes de code!

function send() { var range = SpreadsheetApp.getActiveSpreadsheet().getActiveRange(); var ss = range.getValues(); var carray = range.offset(0, -2).getValues(); var marray = range.offset(0, 1).getValues(); var iarray = range.offset(0, 0).getValues(); ss.forEach(function (r, i) { var tt = range.getRowIndex(); var add = tt + i; var check = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('L' + add).getValue(); if (check != '') { SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('K' + add).setValue("").setBackground("#ffff00"); return; } var payload = { "message" : marray[i][0], "user_id" : r[0], "access_token" : "    ", "v" : "5.74" }; var options = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload, "muteHttpExceptions" : true, }; var jsonData = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.send", options).getContentText()); if (jsonData['error'] != undefined) { SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('K' + add).setValue("").setBackground("#ff0000"); } Logger.log(jsonData); var log = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log'); var int = log.getRange('A1').getValue(); var d = new Date(); log.getRange('B' + int).setValue(d); log.getRange('C' + int).setValue(r[0] + ""); log.getRange('A1').setValue(int + 1); Utilities.sleep(400); }); } 

Dans les tableaux, nous avons généré le texte des messages et créé un mailing personnalisé en utilisant la page d'identification. Nous avons également cessé de copier et d'envoyer des messages manuellement. Aux heures de pointe, nous pouvions envoyer jusqu'à 3000 messages en 45 minutes à l'aide de tableaux. Si nous le faisions à la main, je n'écrirais pas cet article, mais continuerais à envoyer des messages.

Ensuite, je donne un exemple d'une telle tablette miracle. J'ai essayé très fort de créer une UX / UI claire et fonctionnelle. En cliquant sur le bouton rouge, une liste de diffusion a été lancée avec une proposition de procéder à un contrôle secret.



Plus de fonctionnalités pour automatiser les processus infernaux


La société dispose de nombreux formulaires Google qui nous aident à collecter régulièrement des statistiques sur les pizzerias. Chaque formulaire contient une liste de pizzerias qui doivent être tenues à jour. Il existe au total 53 formulaires de ce type, chacun d'entre eux a été mis à jour manuellement auparavant.

Un peu fatigués de ce travail, nous avons réalisé que cette entreprise pouvait être automatisée. Je me suis de nouveau tourné vers notre responsable marketing, après une heure ou deux, tout était prêt et seulement 47 lignes de code.

 function myFunction() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getActiveRange(); var forms = range.offset(0, 1).getValues(); var items = range.offset(0, 2).getValues(); var sources = range.offset(0, 3).getValues(); var ranges = range.offset(0, 4).getValues(); forms.forEach(function (r,i) { var form = FormApp.openById(forms[i]); var values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sources[i]).getRange(ranges[i]).getValues(); var arr = []; values.forEach(function (el,ei) { if (el[0] != '') { arr.push(el[0]); } }); var item = form.getItems()[Number(items[i])].asListItem(); item.setChoiceValues(arr); Logger.log(item.getTitle()); }); } function getData() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getSheetByName("    ").getRange("A2:C").getValues(); Logger.log(range); } function onOpen() { var ui = SpreadsheetApp.getUi(); // Or DocumentApp or FormApp. ui.createMenu('Custom Menu') .addItem('Change', 'myFunction') .addToUi(); } function update() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getSheetByName(" ").getRange("A2:A"); range.activate(); myFunction(); } function createTimeDrivenTriggers() { ScriptApp.newTrigger('update').timeBased().everyDays(1).create(); } 

Les formulaires sont différents, avec différentes listes de pizzerias et l'emplacement de la liste des pizzerias dans le formulaire. Quelque part, nous avons besoin d'étrangers, quelque part de Russie.



Les colonnes B et C indiquent au script sous quel formulaire mettre à jour et à quel endroit le formulaire affiche la liste. Et les colonnes D et E, à partir de quelle feuille et plage vous devez prendre la liste pour la mise à jour.

Ensuite, nous avons défini un déclencheur pour exécuter le script une fois par jour et avons ainsi réussi à vaincre l'enfer du processus de mise à jour des formulaires d'abord pour notre département, puis pour l'ensemble de l'entreprise. Ce script fonctionne toujours.

Le cas le plus difficile d'un escargot


Une fois, nous voulions recevoir des enregistrements audio des contrôles de livraison.

D'où vient l'enregistrement audio: les clients mystères ont enregistré la réunion du courrier avec le client sous forme de message audio dans VK. Il s'agit généralement de 10 à 15 secondes d'enregistrement audio.

Comment nous les avons obtenus: ils ont pris les 20 derniers messages sur l'adresse VK du client mystère, ont recherché le mot «Ulica» parmi eux, puis ont reculé d'un message et ont enlevé le lien vers l'enregistrement audio. (Spoiler: pas le meilleur mot, souvent ils nous ont écrit le mot "Snail").

Il y a déjà plus de lignes de code, préparez-vous.

 function getLastAudio() { var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); var token = ''; var range = ss.getActiveRange().getValues(); var tt = ss.getActiveRange().getRowIndex(); range.forEach(function (r,i) { var ri = tt + i; var cuid = r[0]; var ci = 0; var payload1 = { "q" : '', 'peer_id' : r[0], "access_token" : token, "v" : "5.73", }; var options1 = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload1, "muteHttpExceptions" : true }; var jsonData = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.search", options1).getContentText()); Logger.log(jsonData); if (jsonData['response']['items'] == undefined) { ss.getRange("B" + ri).setValue(' ').setBackground('#f00'); return; } var cmid = jsonData['response']['items'][0]['id']; var date = new Date((jsonData['response']['items'][0]['date']*1000)); var fdate = Utilities.formatDate(date, "GMT+3", "dd-MM-yyyy HH:mm:ss"); ss.getRange("B" + ri).setValue(fdate); var payload2 = { "user_id" : cuid, "count" : '20', "access_token" : token, "v" : "5.73", }; var options2 = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload2, "muteHttpExceptions" : true }; var jsonData2 = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.getHistory", options2).getContentText()); Logger.log(jsonData2); jsonData2['response']['items'].forEach(function (r,i) { if (r['id'] == cmid) { ci = i + 1; Logger.log(jsonData2['response']['items'][ci]); if (jsonData2['response']['items'][ci] == undefined) { ss.getRange("C" + ri).setValue(" "); } else { if (jsonData2['response']['items'][ci] != undefined && jsonData2['response']['items'][ci]['attachments'] != undefined && jsonData2['response']['items'][ci]['attachments'][0]['doc'] != undefined && jsonData2['response']['items'][ci]['attachments'][0]['doc']['url'] != undefined) { ss.getRange("C" + ri).setValue(jsonData2['response']['items'][ci]['attachments'][0]['doc']['url']); } else { ss.getRange("C" + ri).setValue(jsonData2['response']['items'][ci]['body']); } } } }); }); } 

Les feuilles de calcul Google ne sont pas caoutchouteuses, mais je suis un encodeur moyen


Donc tout tournait et tournait, jusqu'à ce que nous soyons passés à 60000 clients mystères au début de 2018.

Nous avons donc déjà rencontré des restrictions de table. Ensuite, un tableau ne pouvait pas contenir plus de 2 millions de cellules, et nous avons utilisé 1,6 million de cellules dans l'une des étiquettes de département les plus fréquentées, dont 135 000 cellules avaient toutes sortes de fonctions de tableau.

Un tel backend. Tout a terriblement ralenti et lorsque plusieurs personnes ont travaillé ensemble, l'assiette a donné "Le document est trop populaire, revenez plus tard".

Ensuite, il est devenu clair que je suis un mauvais encodeur, le système ne supporte pas la charge et je dois être remplacé.

Et puis le vrai développeur est venu ...


Mais c'est une histoire complètement différente et nous en parlerons plus tard. J'espère que ces exemples aideront les managers dans leurs projets, où il existe de nombreux processus infernaux. Les processus peuvent et doivent être automatisés, les tables et zapier (nous l'avons également utilisé) peuvent aider, et héberger des solutions s'il y a des ressources, nous ne les avions pas au départ.

Si vous avez une personne dans l'entreprise qui sait quelque chose sur les scripts, alors elle convient pour organiser les processus infernaux dans les tablettes. Si vous voulez vous-même apprendre quelque chose comme ça, Telegram a un excellent canal pour cela, à partir duquel j'ai pris des informations sur les fonctions et les scripts.

Eh bien, tête de mât pour tous les gestionnaires - connaître les tables chaque jour permet de gagner du temps lorsque vous travaillez avec des données et vous permet de penser et de comprendre au moins un peu ce que le développeur fait avec les données et ce que vous pouvez faire avec les données en général.

Source: https://habr.com/ru/post/fr472856/


All Articles