使用Google Apps脚本发送股票警报电子邮件

时间:2018-09-02 19:30:55

标签: google-apps-script google-sheets

我正在尝试设置一个简单的Google Apps脚本,以在各种组件的库存达到定义的阈值时发送电子邮件。阅读和搜索后,我整理了一个脚本,该脚本似乎可以正常工作,但是当我增加从电子表格中提取的范围时,就开始发送错误的电子邮件。

这是我的代码,下面是更多详细信息。

var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Inventory Report");
var howFar = 5 //sheet.getMaxRows(); // how many rows of data
var onHand = sheet.getRange(2,14,howFar,1).getValues();
var minimum = sheet.getRange(2,16,howFar,1).getValues();
var itemNum = sheet.getRange(2,1,howFar,1).getValues();
var itemName = sheet.getRange(2,2,howFar,1).getValues();

var sendTo = "test@gmail.com";
var overStock = 1.5;  // warning factor over minimum

function stockAlert() {
  for (var i = 0; i < onHand.length; i++) { 
    if (onHand[i] < minimum[i] * overStock && onHand[i] > minimum[i]) {
        MailApp.sendEmail( sendTo , "Testing Stock Reorder Notifications", itemNum[i] + " " + itemName[i] +" - Stock is low! Current stock is " + onHand[i] + ". Minimum is " + minimum[i] + ".");
    }
    else if (minimum[i] > 0 && onHand[i] < minimum[i]) {
        MailApp.sendEmail( sendTo , "Testing Stock Cirtical Notifications", itemNum[i] + " " + itemName[i] +" - Stock is Critical and will be depleted! Current stock is " + onHand[i] + ". Minimum is " + minimum[i] + ".");
    } 
  }
}

在我的工作表中,最小值为200、400、200、300、600
在我的工作表中,onHand的值为270、270、920、920、1830

这意味着我应该在第一组值中看到一封低库存电子邮件,在第二组值中看到一封关键库存电子邮件,而后三组值则没有电子邮件。

如果为var howfar = 3,脚本将发送两封适当的电子邮件。 如果为var howfar = 5,我将收到第三封重要股票电子邮件,其中包含不应发送的第五组值。有趣的是,电子邮件正文显示它正在引用正确的值集,但是else if应该为假。

不正确的电子邮件正文显示为:

  

itemNum itemName-库存至关重要,库存将耗尽!当前库存为1830。最小值为600。

鉴于我在编码方面的广泛背景,我希望并认为这将是一个简单的解决方法,但是所有帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

是否有可能在电子表格中将值视为文本?请注意,字符串"1830"确实是<字符串"600"。如果它们是电子表格中的文本(而不是数字),则当Apps Script读取其中的值时,它们将保留为String

编辑:的确,这就是问题的根源-您在Array级别比较2D阵列:

Logger.log(minimum[i]); // "[600.0]"
Logger.log(typeof minimum[i]); // object

Logger.log(minimum[i][0]); // 600.0
Logger.log(typeof minimum[i][0]); // number

然后,最简单的解决方法是简单地访问2D数组的所需元素。由于您仅获取单列,因此每个内部数组(索引为0)只有1个元素。因此,用<array>[i][0]代替了<array>[i]

对此的扩展(适用于工作表值可能是文本的情况)将在使用JS函数parseInt(val, radix)进行比较之前显式转换为数字。假设minimum和其他二维数组是您问题代码中的二维数组:

for (var i = 0; i < onHand.length; i++) {
  var min = parseInt(minimum[i][0], 10),
      avail = parseInt(onHand[i][0], 10);
  if (avail < min) {
    // send critical stock email
  }
  else if (avail < min * overStock) {
    // send reorder email
  }
  else {
    // on hand amount is > needed
  }
}

对于空白字符串,例如parseInt("", 10)或其他非数字输入,返回值是数字NaN,它既不是>也不是<,而不是实际数字,因此错误的输入不应导致产生电子邮件被发送。


另一个问题是您的脚本会使用接口调用填充全局变量,这会导致 any 脚本的执行速度变慢。更好的方法是将相关的设置包装在一个函数中:

function getStockAmounts() {
  // Return an object of the inventory values.
  const stock = SpreadsheetApp.getActive().getSheetByName("some name");
  const numHeaders = 1,
        numVals = stock.getLastRow() - numHeaders;
  return [
    {p: 'minimum', col: 16},
    {p: 'onHand', col: 14},
    {p: 'itemName', col: 2},
    {p: 'itemNum', col: 1}
  ].reduce(function (obj, key) {
    obj[key.p] = stock.getRange(numHeaders + 1, key.col, numVals, 1)
      .getValues()
      // Return a 1-D array, rather than a 2-D array, since all these are single-column variables.
      .map(function (row) { return row[0]; });
    return obj;
  }, {'numVals': numVals});
}

,然后从您的脚本中调用它:

function foo() {
  const stocks = getStockAmounts();
  for (var i = 0; i < stocks.numVals; i++) {
    var min = stocks.minimum[i]; // 1D arrays, so only 1 index is needed.
    ...