From b604060bc721ecbc296ed16f26fc8bc2458c3200 Mon Sep 17 00:00:00 2001
From: Matt Lott <mattlott@live.com>
Date: Tue, 10 May 2016 14:40:41 -0700
Subject: [PATCH] Add call tasks to inbound leads after 3 days

---
 .../mongodb/queries/maybeStudentTeacher.js    |   2 +-
 scripts/followupCloseIoLeads.js               | 241 +++++++++++++++++-
 2 files changed, 240 insertions(+), 3 deletions(-)

diff --git a/scripts/analytics/mongodb/queries/maybeStudentTeacher.js b/scripts/analytics/mongodb/queries/maybeStudentTeacher.js
index 444598527..debde0cf2 100644
--- a/scripts/analytics/mongodb/queries/maybeStudentTeacher.js
+++ b/scripts/analytics/mongodb/queries/maybeStudentTeacher.js
@@ -9,7 +9,7 @@
 // Classroom owner, teacher role (GOOD)
 // Classroom member, no role
 // Classroom member, teacher role
-// Classroom member, studnet role (GOOD)
+// Classroom member, student role (GOOD)
 
 'use strict';
 const scriptStartTime = new Date();
diff --git a/scripts/followupCloseIoLeads.js b/scripts/followupCloseIoLeads.js
index cdad03c1a..b6abbebe8 100644
--- a/scripts/followupCloseIoLeads.js
+++ b/scripts/followupCloseIoLeads.js
@@ -11,6 +11,7 @@ if (process.argv.length !== 6) {
 // TODO: 2nd follow up email activity does not handle paged activity results
 // TODO: sendMail copied from updateCloseIoLeads.js
 // TODO: template values copied from updateCloseIoLeads.js
+// TODO: status change is not related to specific lead contacts
 
 const createTeacherEmailTemplatesAuto1 = ['tmpl_i5bQ2dOlMdZTvZil21bhTx44JYoojPbFkciJ0F560mn', 'tmpl_CEZ9PuE1y4PRvlYiKB5kRbZAQcTIucxDvSeqvtQW57G'];
 const demoRequestEmailTemplatesAuto1 = ['tmpl_s7BZiydyCHOMMeXAcqRZzqn0fOtk0yOFlXSZ412MSGm', 'tmpl_cGb6m4ssDvqjvYd8UaG6cacvtSXkZY3vj9b9lSmdQrf'];
@@ -31,7 +32,9 @@ earliestDate.setUTCDate(earliestDate.getUTCDate() - 10);
 // ** Main program
 
 async.series([
-  sendSecondFollowupMails
+  sendSecondFollowupMails,
+  addCallTasks
+// TODO: Cancel call tasks
 ],
 (err, results) => {
   if (err) console.error(err);
@@ -69,6 +72,14 @@ function isCreateTeacherTemplateAuto1(template) {
   return createTeacherEmailTemplatesAuto1.indexOf(template) >= 0;
 }
 
+function isDemoRequestTemplateAuto2(template) {
+  return demoRequestEmailTemplatesAuto2.indexOf(template) >= 0;
+}
+
+function isCreateTeacherTemplateAuto2(template) {
+  return createTeacherEmailTemplatesAuto2.indexOf(template) >= 0;
+}
+
 function log(str) {
   console.log(new Date().toISOString() + " " + str);
 }
@@ -325,7 +336,9 @@ function sendSecondFollowupMails(done) {
         if (error) return done(error);
         try {
           const results = JSON.parse(body);
-          console.log(`sendSecondFollowupMails total num leads ${results.total_results} has_more=${results.has_more}`);
+          if (skip === 0) {
+            console.log(`sendSecondFollowupMails total num leads ${results.total_results} has_more=${results.has_more}`);
+          }
           has_more = results.has_more;
           const tasks = [];
           for (const lead of results.data) {
@@ -357,3 +370,227 @@ function sendSecondFollowupMails(done) {
     nextPage(0);
   });
 }
+
+function createAddCallTaskFn(userApiKeyMap, latestDate, lead, email) {
+  // Check for activity since second auto mail and status update
+  // Add call task
+  // TODO: Very similar function to createSendFollowupMailFn
+  const auto1Statuses = ["Auto Attempt 1", "New US Schools Auto Attempt 1"];
+  const auto2Statuses = ["Auto Attempt 2", "New US Schools Auto Attempt 2"];
+  return (done) => {
+    // console.log("DEBUG: addCallTask", lead.id);
+
+    // Skip leads with tasks
+    const url = `https://${closeIoApiKey}:X@app.close.io/api/v1/task/?lead_id=${lead.id}`;
+    request.get(url, (error, response, body) => {
+      if (error) {
+        console.log(error);
+        return done();
+      }
+      try {
+        const results = JSON.parse(body);
+        if (results.total_results > 0) {
+          // console.log(`DEBUG: ${lead.id} has ${results.total_results} tasks`);
+          return done();
+        }
+      }
+      catch (err) {
+        return done(err);
+      }
+
+      // Find all lead activities
+      const url = `https://${closeIoApiKey}:X@app.close.io/api/v1/activity/?lead_id=${lead.id}`;
+      request.get(url, (error, response, body) => {
+        if (error) {
+          console.log(error);
+          return done();
+        }
+        try {
+          const results = JSON.parse(body);
+          if (results.has_more) {
+            console.log(`ERROR: ${lead.id} has more activities than returned!`);
+            return done();
+          }
+
+          // Find second auto mail and status change
+          let sentSecondCreateTeacherEmail = false;
+          let sentSecondDemoRequestEmail = false;
+          let secondMailActivity;
+          let statusUpdateActivity;
+          let contactReplyMail;
+          for (const activity of results.data) {
+            if (activity._type === 'Email' && activity.to[0] === email) {
+              if (isCreateTeacherTemplateAuto2(activity.template_id)) {
+                if (sentSecondCreateTeacherEmail || sentSecondDemoRequestEmail) {
+                  console.log(`ERROR: ${lead.id} ${email} sent multiple auto2 emails!? ${sentSecondCreateTeacherEmail} ${sentSecondDemoRequestEmail}`);
+                  return done();
+                }
+                sentSecondCreateTeacherEmail = true;
+                secondMailActivity = activity;
+              }
+              else if (isDemoRequestTemplateAuto2(activity.template_id)) {
+                if (sentSecondCreateTeacherEmail || sentSecondDemoRequestEmail) {
+                  console.log(`ERROR: ${lead.id} ${email} sent multiple auto2 emails!? ${sentSecondCreateTeacherEmail} ${sentSecondDemoRequestEmail}`);
+                  return done();
+                }
+                sentSecondDemoRequestEmail = true;
+                secondMailActivity = activity;
+              }
+            }
+            else if (activity._type === 'LeadStatusChange' && auto1Statuses.indexOf(activity.old_status_label) >= 0
+              && auto2Statuses.indexOf(activity.new_status_label) >= 0) {
+                statusUpdateActivity = activity;
+            }
+          }
+
+          if (!secondMailActivity) {
+            // console.log(`DEBUG: No auto2 mail sent for ${lead.id} ${email}`);
+            return done();
+          }
+          if (!statusUpdateActivity) {
+            console.log(`ERROR: No status update for ${lead.id} ${email}`);
+            return done();
+          }
+          if (new Date(secondMailActivity.date_created) > latestDate) {
+            // console.log(`DEBUG: Second auto mail too recent ${secondMailActivity.date_created} ${lead.id}`);
+            return done();
+          }
+
+          if (sentSecondCreateTeacherEmail && sentSecondDemoRequestEmail) {
+            console.log(`ERROR: ${lead.id} ${email} sent multiple auto2 emails!? ${sentSecondCreateTeacherEmail} ${sentSecondDemoRequestEmail}`);
+            return done();
+          }
+          // console.log(secondMailActivity);
+
+          // Find activity since second auto mail and status update
+          // Skip email to a different contact's email
+          // Skip note about different contact
+          let recentActivity;
+          for (const activity of results.data) {
+            if (activity.id === secondMailActivity.id) continue;
+            if (activity.id === statusUpdateActivity.id) continue;
+            if (new Date(secondMailActivity.date_created) > new Date(activity.date_created)) continue;
+            if (new Date(statusUpdateActivity.date_created) > new Date(activity.date_created)) continue;
+            if (activity._type === 'Note' && activity.note
+              && activity.note.indexOf('demo_email') >= 0 && activity.note.indexOf(email) < 0) {
+              // console.log(`DEBUG: Skipping ${lead.id} ${email} auto import note for different contact`);
+              // console.log(activity.note);
+              continue;
+            }
+            recentActivity = activity;
+            break;
+          }
+
+          // Create call task
+          if (!recentActivity) {
+            console.log(`DEBUG: adding call task for ${lead.id} ${email}`);
+            const postData = {
+              _type: "lead",
+              lead_id: lead.id,
+              assigned_to: secondMailActivity.user_id,
+              text: `Call ${email}`,
+              is_complete: false
+            };
+            const options = {
+              uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/task/`,
+              body: JSON.stringify(postData)
+            };
+            request.post(options, (error, response, body) => {
+              if (error) return done(error);
+              const result = JSON.parse(body);
+              if (result.errors || result['field-errors']) {
+                const errorMessage = `Create call task POST error for ${email} ${lead.id}`;
+                console.error(errorMessage);
+                // console.error(body);
+                // console.error(postData);
+                return done(errorMessage);
+              }
+              return done();
+            });
+          }
+          else {
+            // console.log(`DEBUG: Found recent activity after auto2 mail for ${lead.id} ${email}`);
+            // console.log(recentActivity);
+            return done();
+          }
+        }
+        catch (err) {
+          console.log(err);
+          console.log(body);
+          return done();
+        }
+      });
+    });
+  };
+}
+
+function addCallTasks(done) {
+  // Find all leads with auto 2 status, created since earliestDate
+  // TODO: Very similar function to sendSecondFollowupMails
+  // console.log("DEBUG: addCallTasks");
+  const userApiKeyMap = {};
+  let createGetUserFn = (apiKey) => {
+    return (done) => {
+      const url = `https://${apiKey}:X@app.close.io/api/v1/me/`;
+      request.get(url, (error, response, body) => {
+        if (error) return done();
+        const results = JSON.parse(body);
+        userApiKeyMap[results.id] = apiKey;
+        return done();
+      });
+    };
+  }
+  const tasks = [];
+  for (const apiKey of closeIoMailApiKeys) {
+    tasks.push(createGetUserFn(apiKey));
+  }
+  async.parallel(tasks, (err, results) => {
+    if (err) console.log(err);
+    const latestDate = new Date();
+    latestDate.setUTCDate(latestDate.getUTCDate() - 3);
+    const query = `date_created > ${earliestDate.toISOString().substring(0, 19)} (lead_status:"Auto Attempt 2" or lead_status:"New US Schools Auto Attempt 2")"`;
+    const limit = 100;
+    const nextPage = (skip) => {
+      let has_more = false;
+      const url = `https://${closeIoApiKey}:X@app.close.io/api/v1/lead/?_skip=${skip}&_limit=${limit}&query=${encodeURIComponent(query)}/`;
+      request.get(url, (error, response, body) => {
+        if (error) return done(error);
+        try {
+          const results = JSON.parse(body);
+          if (skip === 0) {
+            console.log(`addCallTasks total num leads ${results.total_results} has_more=${results.has_more}`);
+          }
+          has_more = results.has_more;
+          const tasks = [];
+          for (const lead of results.data) {
+            // console.log(`${lead.id}\t${lead.status_label}\t${lead.name}`);
+            // if (lead.id !== 'lead_foo') continue;
+            const existingContacts = lead.contacts || [];
+            for (const contact of existingContacts) {
+              if (contact.emails && contact.emails.length > 0) {
+                if (contact.phones && contact.phones.length > 0) {
+                  tasks.push(createAddCallTaskFn(userApiKeyMap, latestDate, lead, contact.emails[0].email.toLowerCase()));
+                }
+              }
+              else {
+                console.log(`ERROR: lead ${lead.id} contact has non-1 emails`);
+              }
+            }
+            // if (tasks.length > 10) break;
+          }
+          async.series(tasks, (err, results) => {
+            if (err) return done(err);
+            if (has_more) {
+              return nextPage(skip + limit);
+            }
+            return done(err);
+          });
+        }
+        catch (err) {
+          return done(err);
+        }
+      });
+    };
+    nextPage(0);
+  });
+}