0

There are 2 tabs:

  • Alerts
  • MASTER

The script:

  • In Alerts tab, if A is empty and H >= 45, copies the value from G to A, on the next empty row, in MASTER
  • Ads specific values to some columns in tab MASTER, on the recently added row. All new rows will have those same values.

The script was retrieving ocasionally some timeouts and I tried to add some

SpreadsheetApp.flush();

With our without any relation to these additions, the script started to work better but I'm sure it will return more timeouts as the list may grow.

Is it possible to speed it up?

function CopyPendingPayment(){
  var sheet = SpreadsheetApp.getActive();
  var sourceSheet = sheet.getSheetByName("Alerts");
  var destination = sheet.getSheetByName("MASTER");
  var lastRow = sourceSheet.getDataRange().getLastRow();
  var column = destination.getRange('A' + destination.getMaxRows())
  SpreadsheetApp.flush();

  for(var row=3; row<=lastRow; row++){
  if(sourceSheet.getRange(row,1).getValue() == "" & sourceSheet.getRange(row,8).getValue() >= "45"){
      var rangeToCopy = "G"+row+":G"+row;
      var lastFilledRow = parseInt(column.getNextDataCell(SpreadsheetApp.Direction.UP).getA1Notation().slice(1))
      SpreadsheetApp.flush();
      
      sourceSheet.getRange(rangeToCopy).copyTo(destination.getRange(lastFilledRow+1,1)),{contentsOnly:true};
      destination.getRange(lastFilledRow+1, 9).setValue("No Payment Received");
      destination.getRange(lastFilledRow+1, 10).setValue(new Date());
      destination.getRange(lastFilledRow+1, 12).setValue("PENDING");
      destination.getRange(lastFilledRow+1, 13).setValue("- Reminder sent");
      destination.getRange(lastFilledRow+1, 14).setValue(new Date());
    }
    }
  }

I guess at least the part where it ads the values on the different columns it could be done quicker, right?

Can anyone give me a hand? Thank you in advance

Sample

Tanaike
  • 181,128
  • 11
  • 97
  • 165
user1128912
  • 191
  • 1
  • 12
  • Have you read ["Best practices"](https://stackoverflow.com/tags/google-apps-script/info)? Have you attempted to follow those? – TheMaster Dec 14 '21 at 13:17

1 Answers1

4

I believe your goal is as follows.

  • You want to reduce the process cost of your script.

In this case, how about the following modification?

Modified script:

function CopyPendingPayment() {
  var sheet = SpreadsheetApp.getActive();
  var sourceSheet = sheet.getSheetByName("Alerts");
  var destination = sheet.getSheetByName("MASTER");
  
  // I modified below script.
  var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
  var lastRow = destination.getLastRow();
  var obj = srcValues.reduce((o, [a,,,,,,g,h], i) => {
    if (a == "" && h >= 45) {
      o.values.push([g]);
      o["No Payment Received"].push(`I${lastRow + i + 1}`);
      o["date"].push(`J${lastRow + i + 1}`, `N${lastRow + i + 1}`);
      o["PENDING"].push(`L${lastRow + i + 1}`);
      o["- Reminder sent"].push(`M${lastRow + i + 1}`);
    }
    return o;
  }, {values: [], "No Payment Received": [], "date": [], "PENDING": [], "- Reminder sent": []});
  destination.getRange(lastRow + 1, 1, obj.values.length).setValues(obj.values);
  ["No Payment Received", "date", "PENDING", "- Reminder sent"].forEach(e => destination.getRangeList(obj[e]).setValue(e == "date" ? new Date() : e));
}
  • In this modification, the value of column "A" is put with setValues of Class Range. And, the values of columns "I", "J", "L", "M" and "N" are put with setValue of Class RangeList. Because I thought that you might want to keep other columns.

  • As another method, I think that your goal can be also achieved by overwriting the cells of the destination sheet. In that case, how about the following script?

      function CopyPendingPayment() {
        var sheet = SpreadsheetApp.getActive();
        var sourceSheet = sheet.getSheetByName("Alerts");
        var destination = sheet.getSheetByName("MASTER");
        var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
        var lastRow = destination.getLastRow();
        var values = srcValues.reduce((ar, [a,,,,,,g,h], i) => {
          if (a == "" && h >= 45) {
            var date = new Date();
            ar.push([g,,,,,,,,"No Payment Received", date,,"PENDING","- Reminder sent",date]);
          }
          return ar;
        }, []);
        destination.getRange(lastRow + 1, 1, values.length, values[0].length).setValues(values);
      }
    

References:

Added:

From your following replying,

It seems a lot quicker, indeed. I've tested your versions vs mine. The only problem is that if there is an array in any ot the destination sheet columns, the values are pasted below. The original version takes into consideration that and pastes the values on the 1st blank cell of column A.

How about the following sample script?

Sample script:

function CopyPendingPayment_C() {
  // This is from https://stackoverflow.com/a/44563639
  Object.prototype.get1stEmptyRowFromTop = function (columnNumber, offsetRow = 1) {
    const range = this.getRange(offsetRow, columnNumber, 2);
    const values = range.getDisplayValues();
    if (values[0][0] && values[1][0]) {
      return range.getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow() + 1;
    } else if (values[0][0] && !values[1][0]) {
      return offsetRow + 1;
    }
    return offsetRow;
  };

  var sheet = SpreadsheetApp.getActive();
  var sourceSheet = sheet.getSheetByName("Alerts");
  var destination = sheet.getSheetByName("MASTER");
  
  // I modified below script.
  var srcValues = sourceSheet.getRange("A3:H" + sourceSheet.getLastRow()).getValues();
  var lastRow = destination.get1stEmptyRowFromTop(1) - 1;

  // I modified below part.
  var obj = srcValues.reduce((o, [a,,,,,,g,h]) => {
    if (a == "" && h >= 45) {
      o.offset++;
      o.values.push([g]);
      o["No Payment Received"].push(`I${o.offset}`);
      o["date"].push(`J${o.offset}`, `N${o.offset}`);
      o["PENDING"].push(`L${o.offset}`);
      o["- Reminder sent"].push(`M${o.offset}`);
    }
    return o;
  }, {values: [], "No Payment Received": [], "date": [], "PENDING": [], "- Reminder sent": [], offset: lastRow});

  destination.getRange(lastRow + 1, 1, obj.values.length).setValues(obj.values);
  ["No Payment Received", "date", "PENDING", "- Reminder sent"].forEach(e => destination.getRangeList(obj[e]).setValue(e == "date" ? new Date() : e));
}
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Thank you for your help and sorry for the late response. It seems a lot quicker, indeed. I've tested your versions vs mine. The only problem is that if there is an array in any ot the destination sheet columns, the values are pasted below. The original version takes into consideration that and pastes the values on the 1st blank cell of column A. – user1128912 Dec 31 '21 at 11:21
  • @user1128912 Thank you for replying. I apologize for the inconvenience. For your replying, I added one more sample script. Could you please confirm it? If that was not useful, I apologize again. – Tanaike Dec 31 '21 at 12:48
  • Thank you once again for your quick answer. Now it does take into consideration the last filled cell on column A (no problem with array formulas on other columns)! But did you notice that if for example there is only one value to copy to MASTER, the added values by the script go to the wrong row? It also happens, for example, if the 1st value in "Alerts" has 40 days and the others have >=45. I have left the filled example on "sample" sheet. – user1128912 Jan 02 '22 at 22:26
  • @user1128912 Thank you for replying. I apologize for the inconvenience. About `But did you notice that if for example there is only one value to copy to MASTER, the added values by the script go to the wrong row?`, I couldn't notice this. This is due to my poor skill. I deeply apologize for my poor skill. I updated my bottom sample script for your replying. Could you please confirm it? I would be grateful if you can forgive my poor skill. – Tanaike Jan 03 '22 at 00:39
  • thank you so much! It works. Will be using it for the next few days to see if anything else comes up but I've already made several tests without errors. It still seems quicker than the original version, which was the main goal. – user1128912 Jan 03 '22 at 09:21