How to connect autoincrement with auto_date_stamp - google-apps-script

I have autoincremment in my google scripts. I would like add script with fixed timestamp. And connect with auto_increment in one time.
I started auto_increment script and next I start insert_timestamp
function auto_increment() {
var AUTOINC_COLUMN = 0; //start column
var HEADER_ROW_COUNT = 340;// start row
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var worksheet = spreadsheet.getSheetByName("Sheet 1");
var rows = worksheet.getDataRange().getNumRows() - 1;
var vals = worksheet.getSheetValues(1, 1, rows+1, 2);
for (var row = HEADER_ROW_COUNT; row < vals.length; row++) {
try {
var id = vals[row][AUTOINC_COLUMN];
Logger.log(id);Logger.log((""+id).length ===0);
if ((""+id).length === 0) {
// Here the columns & rows are 1-indexed
worksheet.getRange(row+1, AUTOINC_COLUMN+1).setValue(row);
}
} catch(ex) {
// Keep calm and carry on
}
}
}
function insert_timestamp() { //function onEdit() I cannot because I need fixed date one day
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
var tz = Session.getScriptTimeZone();
if( r.getColumn() != 0 ) {
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, tz, "dd.MM.yyyy");//"dd.MM.yyyy hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('C' + row.toString()).setValue(time);
}
}
When I write on cell "E" scripts insert new ID and timestamp "dd.mm.yyyy" and fixed when I change text in cell "E" date fixed the last.
Thank you for your help

Related

Filter Blank cells only in an array of cells and set new values to them

I am trying to select the blank cells only in Column no. 22 and if found put a Date & Timestamp in that cell.
function () {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lastrow = sheet.getLastRow();
var timestamp = sheet.getRange(2,22,lastrow-1).getValues();
var blank = timestamp.filter(function(blanks){return blanks =='';});
for (var i = 0; i < blank.length ; i++ )
blank.setValue(new Date);
}
I can give you one of the possible solutions. Feel free to change the timestamp format.
The high-level idea here is to build the data for all the cells in the range and set them at once (for performance purposes).
function fillTimestamp() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName("Sheet1");
var lastrow = sheet.getLastRow();
var targetRange = sheet.getRange(2,22,lastrow-1);
var values = targetRange.getValues();
var data = [];
for (var row in values) {
for (var col in values[row]) {
if(values[row][col] == ''){
data.push([Utilities.formatDate(new Date(), spreadsheet.getSpreadsheetTimeZone(), 'MMMM dd, yyyy HH:mm:ss Z')]);
}
else{
data.push([values[row][col]])
}
}
}
targetRange.setValues(data);
}

cannot target specific cell in a sheet (google app script)

I currently have a script that takes the selected option in column F and updates a different sheet with the selected value. The first sheet is set up like this
A
B
C
D
E
F
Date
Names of other sheets
Month
Day
Weekday
Options
The other sheets are set to start on the 16th of the month and finish on the 15th of the following month. So the sheet labeled (2023/01) has dates starting from row 7. The dates are in column A and the value to be updated is in column D.
The problem
In the script, the dates are all offset by one. So if you select 23/01/16 it actually matches 23/01/17. This doesn't seem to be a problem except when the 15th of every month is selected. Since the sheets end on the 15th and the dates are offset it matches the 16th but the 16th does not exist on the sheet so the cell is not updated.
MY solution
To fix this issue I created a condition to check if the selected date includes '/16' then run some code. I then created a variable to get the previous sheet and got the last row and set the value that way. I used toast() to check if the values I am selecting are correct and they seem to be. The sheet name is correct and the last row is correct but I am not actually seeing the cell being updated. I am not sure what I am doing wrong so any help would be greatly appreciated.
/* 休日入力イベント
--------------------------------------*/
function changeHoliday(ss) {
var sheet = ss.getActiveSheet(); //アクティブなシート
var sheetName = sheet.getSheetName();
var atvc = sheet.getActiveCell(); //アクティブセル
//休日シートの休日を変更した時だけ
if(sheetName=='休日' || sheetName && atvc.getColumn() == 6){
var flag = atvc.getValue(); //休日かどうか
var targetSheetName = String(atvc.offset(1, -4).getValue()); //対応するシート名
//Get previous sheet name
var prevSheetName = String(atvc.offset(-1,-4).getValue());
var targetDate = Utilities.formatDate(atvc.offset(1, -5).getValue(),"JST", "yyyy/MM/dd"); //対応する日付
// var targetDateEndofSheet = Utilities.formatDate(atvc.offset(0, -5).getValue(),"JST", "yyyy/MM/dd");
var targetSheet = ss.getSheetByName(targetSheetName);
var lastRow = targetSheet.getLastRow();
var values = targetSheet.getRange(1,1,lastRow,1).getValues();
// 取得したデータから一致する日付を探す
//original i=7
for (var i=7; i<lastRow; i++){
var d = Utilities.formatDate(values[i][0],"JST", "yyyy/MM/dd");
//My if statement
if(targetDate.includes("/16")) {
var targetS = ss.getSheetByName(prevSheetName); //get the pervious sheet
var lastR = targetS.getLastRow(); //get the last row of the previous sheet
//check the values
ss.toast( "prev sheet name " + prevSheetName +"last r: " + lastR + "flag" + flag + "td " + targetDate)
//select the cell 4 of the last row
var r = prevSheetName.getRange(lastR,4);
r.setValue(flag); //set the select value
}
if(d == targetDate){
var range = targetSheet.getRange(i,4);
// データ追加
range.setValue(flag);
}
}
}
//一度に1つの日付を入力してください
}
/* 休日の保護の解除
--------------------------------------*/
function protectionRemove_(targetDate){
var ss = SpreadsheetApp.getActive();
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
// 説明文が一致したら削除
if (protection.getDescription() == targetDate) {
protection.remove();
}
}
}
I was able to solve it with some of the suggestions made in the comments
I added this to my code
if(d.includes("/16") && targetDate.includes("/16")) {
var prevSheetName = String(atvc.offset(-1, -4).getValue()); //get target page
var targetSheet = ss.getSheetByName(prevSheetName);
var lr= targetSheet.getLastRow(); //select the last of the target page
var r = targetSheet.getRange(lr,4); //set the range
r.setValue(flag);
}
Please find my explanation in the comments:
function changeHoliday(ss) {
var sheet = ss.getActiveSheet(); //アクティブなシート
var sheetName = sheet.getSheetName();
var atvc = sheet.getActiveCell(); //アクティブセル
//休日シートの休日を変更した時だけ
/* Should be AND OPERATOR */
if(sheetName=='休日' && sheetName && atvc.getColumn() == 6){
var flag = atvc.getValue(); //休日かどうか
/* Should check the value */
if (flag == '休日') {
/* Row offset should be 0 */
var targetSheetName = String(atvc.offset(0, -4).getValue()); //対応するシート名
//Get previous sheet name
/* Not needed */
// var prevSheetName = String(atvc.offset(-1,-4).getValue());
/* Row offset should be 0 */
var targetDate = Utilities.formatDate(atvc.offset(0, -5).getValue(),"JST", "yyyy/MM/dd"); //対応する日付
// var targetDateEndofSheet = Utilities.formatDate(atvc.offset(0, -5).getValue(),"JST", "yyyy/MM/dd");
var targetSheet = ss.getSheetByName(targetSheetName);
var lastRow = targetSheet.getLastRow();
var values = targetSheet.getRange(1,1,lastRow,1).getValues();
// 取得したデータから一致する日付を探す
//original i=7
/* i should starts from 6 */
for (var i=6; i<lastRow; i++){
var d = Utilities.formatDate(values[i][0],"JST", "yyyy/MM/dd");
//My if statement
/* Not needed */
/*
if(targetDate.includes("/16")) {
var targetS = ss.getSheetByName(prevSheetName); //get the pervious sheet
var lastR = targetS.getLastRow(); //get the last row of the previous sheet
//check the values
ss.toast( "prev sheet name " + prevSheetName +"last r: " + lastR + "flag" + flag + "td " + targetDate)
//select the cell 4 of the last row
var r = prevSheetName.getRange(lastR,4);
r.setValue(flag); //set the select value
}
*/
if(d == targetDate){
/* Row should be i + 1 */
var range = targetSheet.getRange(i + 1,4);
// データ追加
range.setValue(flag);
/* Better to break */
break;
}
}
}
}
//一度に1つの日付を入力してください
}
To simplify:
function changeHoliday(ss) {
var sheet = ss.getActiveSheet();
var sheetName = sheet.getSheetName();
var atvc = sheet.getActiveCell();
if(sheetName=='休日' && sheetName && atvc.getColumn() == 6){
var flag = atvc.getValue();
if (flag == '休日') {
var targetSheetName = String(atvc.offset(0, -4).getValue());
var targetDate = Utilities.formatDate(atvc.offset(0, -5).getValue(),"JST", "yyyy/MM/dd"); //対応する日付
var targetSheet = ss.getSheetByName(targetSheetName);
var lastRow = targetSheet.getLastRow();
var values = targetSheet.getRange(1,1,lastRow,1).getValues();
for (var i=6; i<lastRow; i++){
var d = Utilities.formatDate(values[i][0],"JST", "yyyy/MM/dd");
if(d == targetDate){
var range = targetSheet.getRange(i + 1,4);
range.setValue(flag);
break;
}
}
}
}
}

How to add the condition if a cell value is not an email address in Google App Scripts

My following code is working fine but the issue is, I want to add a third condition range.getCell(i, 3) value is not an email address, then the corresponding row will be deleted. How to fix it?
var spreadsheet = SpreadsheetApp.getActive();
var dashboard = spreadsheet.getSheetByName("Dashboard");
var sheetName = dashboard.getRange("A4").getValue();
//retrieve the start date to use as desired
var startDate = dashboard.getRange("B4").getDisplayValue();
var endDate = dashboard.getRange("C4").getDisplayValue();
var sheet = spreadsheet.getSheetByName(sheetName);
//chose the range within the specified dates, for this first locate the date column
var startRow = 2;
var dateColumn = sheet.getRange(startRow,1,sheet.getLastRow(), 1);
var dates = dateColumn.getDisplayValues().flat();
var firstRow = dates.indexOf(startDate)+startRow;
var lastRow = dates.lastIndexOf(endDate)+startRow;
//now get the range between (and including) those rows
var range = sheet.getRange(firstRow, 1, lastRow-firstRow+1, sheet.getLastColumn());
var deleteRows = 0;
for (var i = range.getHeight(); i >= 1; i--){
if(range.getCell(i, 1).isBlank() || range.getCell(i, 3).isBlank()
**|| range.getCell(i, 3) IS NOT AN EMAIL Address){**
sheet.deleteRow(range.getCell(i, 1).getRow());
deleteRows++;
}
else{
if(range.getCell(i, 6).isBlank()){
range.getCell(i, 6).setValue(sheetName);
range.getCell(i, 1).setNumberFormat("yyyy-mm-dd");
}
}
}
Since I don't have access to your sheet, it is really difficult for me to undestand if the rest of the code works.
But I managed to replicate part of your example and created the following code snippet which you can use instead of your code after range:
var data = sheet.getRange(firstRow, 1, sheet.getLastRow()-firstRow+1, sheet.getLastColumn()).getValues();
var deleteRows = 0;
for (var i = data.length-1; i >= 1; i--){
if(data[i][0] == '' || data[i][2] == '' || !data[i][2].toString().includes('#')){
sheet.deleteRow(i+firstRow)
deleteRows++;
}
else if(data[i][5] == '') {
sheet.getRange(i+firstRow,6).setValue('sheetName');
sheet.getRange(i+firstRow,1).setNumberFormat("yyyy-mm-dd");
}
}

Capture values and send email trigger

I managed to collect data of user typing in and by using onChange trigger, I did meet my requirements for my task. However, I realized that for example I am filling up Column A1:A4. If my A1:A3 is out of range, it will trigger the email. But if my A4 is within range, the values of A1:A3 will still trigger the email eventhough it has trigger it before. How do I make sure that the values that have been capture do not trigger the email again?
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
currentsheet = ss.getSheetName();
//var values = ss.getRange(a1Notation)
//console.log(values);
var lastcol = ss.getLastColumn();
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration");
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature");
//console.log(lastcol);
if((currentsheet == 'A Vibration') || (currentsheet == 'B Vibration')){
console.log(currentsheet);
for(var i =2; i<=lastcol; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 8){
console.log("Value is more than 8 and current value is "+cell);
vibrationtemplate.vibrate = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: vibrationtemplate.evaluate().getContent()});
}
}
}
if((currentsheet == 'A Temperature') || (currentsheet == 'B Temperature')){
console.log(currentsheet);
for(var i =2; i<=lastcol; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 80){
console.log("Value is more than 80 and current value is "+cell);
temperaturetemplate.temp = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: temperaturetemplate.evaluate().getContent()});
}
}
}
}
EDIT: Latest code - Using a daily trigger and only checks at the end of the day.
function myFunction() {
const ss = SpreadsheetApp.getActiveSheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetNumber = sheets.length; //Get number of sheets within Spreadsheet
var currentSheet = ss.getIndex()-1; //Get index of current sheet with 0 indexing
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration"); //Create HTML for email by grabbing template from vibration.html
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature"); //Create HTML for email by grabbing template from temperature.html
const vibrationlimit = 8; //Set vibrationlimit as constant equals to 8
const temperaturelimit = 80; //Set temperaturelimit as constant equals to 80
var currentDate = new Date(); //Get system Date and Time
var currentDay = currentDate.getDate(); //Extract Date from Full Date(currentDate)
var currentMonth = currentDate.getMonth() +1; //Extract Month from Full Date(currentDate), add +1 as month index start from 0.
for (var z = currentSheet ; z<sheetNumber ; ++z ){
SpreadsheetApp.setActiveSheet(sheets[z])
var lastcol = sheets[z].getLastColumn();
var lastrow= sheets[z].getLastRow();
var cellDate = sheets[z].getRange(1,lastcol).getValues();
var formattedCellDate = new Date(cellDate);
var cellDay = formattedCellDate.getDate();
var cellMonth = formattedCellDate.getMonth() + 1;
if((z==0) || (z==2)){
if((cellDay == currentDay) && (cellMonth == currentMonth)){
for(var i = 2; i<=lastrow; i++){
var scxvibrationname = sheets[z].getRange(i,1).getValues();
var vibration = sheets[z].getRange(i,lastcol).getValues();
if(vibration > vibrationlimit){
Logger.log("Vibration over 8 - Current Value is "+vibration);
vibrationtemplate.vibrate = vibration;
vibrationtemplate.scxvibration = scxvibrationname;
}
}
}
}
}
You can use PropertiesService to store the last row of the previous script run
The following code sets the start row for the for loop to the (last row+1) of the previous script run, so that only e-mails from newly added rows will be sent:
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
currentsheet = ss.getSheetName();
//var values = ss.getRange(a1Notation)
//console.log(values);
var lastcol = ss.getLastColumn();
var lastrow=ss.getLastRow();
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration");
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature");
//console.log(lastcol);
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperty('startRow', lastrow+1);
}
var startRow=PropertiesService.getScriptProperties().getProperty('startRow');
if((currentsheet == 'A Vibration') || (currentsheet == 'B Vibration')){
console.log(currentsheet);
//I ASSUME THAT YOU WANT TO LOOP THROUGH ALL ROWS AND NOT COLUMNS
for(var i =startRow; i<=lastrow; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 8){
console.log("Value is more than 8 and current value is "+cell);
vibrationtemplate.vibrate = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: vibrationtemplate.evaluate().getContent()});
}
}
}
...
PropertiesService.getScriptProperties().setProperty('startRow', lastrow+1);
}
function myFunction() {
const ss = SpreadsheetApp.getActiveSheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetNumber = sheets.length; //Get number of sheets within Spreadsheet
var currentSheet = ss.getIndex()-1; //Get index of current sheet with 0 indexing
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration"); //Create HTML for email by grabbing template from vibration.html
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature"); //Create HTML for email by grabbing template from temperature.html
const vibrationlimit = 8; //Set vibrationlimit as constant equals to 8
const temperaturelimit = 80; //Set temperaturelimit as constant equals to 80
var currentDate = new Date(); //Get system Date and Time
var currentDay = currentDate.getDate(); //Extract Date from Full Date(currentDate)
var currentMonth = currentDate.getMonth() +1; //Extract Month from Full Date(currentDate), add +1 as month index start from 0.
for (var z = currentSheet ; z<sheetNumber ; ++z ){
SpreadsheetApp.setActiveSheet(sheets[z])
var lastcol = sheets[z].getLastColumn();
var lastrow= sheets[z].getLastRow();
var cellDate = sheets[z].getRange(1,lastcol).getValues();
var formattedCellDate = new Date(cellDate);
var cellDay = formattedCellDate.getDate();
var cellMonth = formattedCellDate.getMonth() + 1;
if((z==0) || (z==2)){
if((cellDay == currentDay) && (cellMonth == currentMonth)){
for(var i = 2; i<=lastrow; i++){
var scxvibrationname = sheets[z].getRange(i,1).getValues();
var vibration = sheets[z].getRange(i,lastcol).getValues();
if(vibration > vibrationlimit){
Logger.log("Vibration over 8 - Current Value is "+vibration);
vibrationtemplate.vibrate = vibration;
vibrationtemplate.scxvibration = scxvibrationname;
}
}
}
}
}
I manipulated by using daily time-driven trigger.

Adding a row to a filtered range

I have a to-do list app in google sheets. I have functions for filtering by "note type" and "done status" that can be in use at any given moment by the user.
I also have functions to easily add a new note of any given type. However, when running the function to add a new note, and the sheet is already filtered, I'm getting the following error:
"This operation is not supported on a range with a filtered out row."
Any advice on how I can add a row to a filtered range?
Here is the code that I am using to add a new note of a particular type:
function addNewCueNote() {
if( sheet.getSheetName() == sheetName ) {
var noteType = "CUE"
//ADDS ROW AND COPIES FORMULA DOWN
//SETS VARIABLES FOR LAST ROW AND LAST COLUMN
var lRow = sheet.getLastRow();
var lCol = sheet.getLastColumn();
//INSERT LAST ROW
sheet.insertRowsAfter(lRow, 1);
//COPY FORMULAS DOWN FOR SPECIFIED COLUMNS
sheet.getRange(lRow,firstCopyCol,1,numColCopy).copyTo(sheet.getRange(lRow+1,firstCopyCol,1,numColCopy));
//SETS NOTE TYPE
sheet.getRange(sheet.getLastRow(),noteTypeCol).setValue(noteType);
}
Grab the existing filter, remove it from the sheet, add the new row, then recreate the filter using the criteria from the initial filter.
function addNewCueNote() {
var sheet = SpreadsheetApp.getActiveSheet(); // added to get code to run; not sure if you handle elsewhere
if (sheet.getSheetName() === sheetName) {
// Save state of existing filter before removing it
var oldCriteria = [];
var filter = sheet.getFilter();
if (filter != null) {
var oldNumColumns = filter.getRange().getNumColumns();
for (var c = 1; c <= oldNumColumns; c++) {
var criteria = filter.getColumnFilterCriteria(c);
if (criteria != null) {
oldCriteria.push([c, criteria.copy()]);
}
}
filter.remove();
}
//*** PUT YOUR ROW INSERT LOGIC HERE ***
// Recreate filter on new data range
var dataRange = sheet.getDataRange();
var newFilter = dataRange.createFilter();
if (filter != null) {
var newNumColumns = dataRange.getNumColumns();
for (var i = 0; i < oldCriteria.length && oldCriteria[i][0] <= newNumColumns; i++) {
newFilter.setColumnFilterCriteria(oldCriteria[i][0], oldCriteria[i][1]);
}
}
}
#Nick there is something wrong with your code logic. In any ways this is a working code
// *** I have to add this for tests ***
var firstCopyCol = 3;
var numColCopy = 2;
var noteTypeCol = 2;
var sheet = SpreadsheetApp.getActiveSheet();
var sheetName = 'MatchImport';
// ************************************
function addNewCueNote() {
if (sheet.getSheetName() === sheetName) {
var filter = sheet.getFilter();
if (filter) {
var dataRange = sheet.getDataRange();
var oldNumColumns = filter.getRange().getNumColumns();
var newNumColumns = dataRange.getNumColumns();
var criterias = {};
for (var c = 1; c <= oldNumColumns && c <= newNumColumns; c++) {
var criteria = filter.getColumnFilterCriteria(c);
if (criteria) criterias['_' + c] = criteria;
}
filter.remove();
}
// START OF YOUR INSERT LOGIC
var noteType = 'CUE';
// ADDS ROW AND COPIES FORMULA DOWN
// SETS VARIABLES FOR LAST ROW AND LAST COLUMN
var lRow = sheet.getLastRow();
var lCol = sheet.getLastColumn(); // This is never used
// INSERT LAST ROW
sheet.insertRowsAfter(lRow, 1);
// COPY FORMULAS DOWN FOR SPECIFIED COLUMNS
sheet
.getRange(lRow, firstCopyCol, 1, numColCopy)
.copyTo(sheet.getRange(lRow + 1, firstCopyCol, 1, numColCopy));
// SETS NOTE TYPE
sheet.getRange(sheet.getLastRow(), noteTypeCol).setValue(noteType);
//* * END OF YOUR INSERT LOGIC
if (!filter) return;
dataRange = sheet.getDataRange();
var newFilter = dataRange.createFilter();
newNumColumns = dataRange.getNumColumns();
for (c = 1; c <= oldNumColumns && c <= newNumColumns; c++) {
if (criterias['_' + c])
newFilter.setColumnFilterCriteria(c, criterias['_' + c]);
}
}
}