Auto Copying Rows in Google Sheets - google-apps-script

I'm attempting to write a few functions that
copy google form submission to from "form submission" sheet to "All Leads" sheet
move whole row from "All Leads" sheet to "Open Leads" sheet based on a cell value = "open"
move whole row data either back to "All Leads" or "closed","lost" sheets based on cell value ="closed/lost/blank"
var sheetNameToWatch = "Form Responses";
var columnNumberToWatch = 3;
var sheetNameToMoveTheRowTo = "All Leads";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && isBlank(range) == FALSE) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
//sheet.deleteRow(range.getRow());
}
}
But I'm not getting this to trigger onEdit or onFormSubmission. Any help is appreciated, and as you can tell i'm new to scripting.
Here is the shared google spreadsheet
https://docs.google.com/spreadsheets/d/13090GHrXY17lRzA9ppQHZZGyT9yUNk6hMMXDQIKmddI/edit?usp=sharing

Since you already have entries stored in your Spreadsheet, you should just run this snippet once to copy the already stored values in their place. This works by gathering all the data wanted from the Form Responses sheet by using the getRange(row, col, numrows, numcols) method and then pasting the values by using the setValues() method.
function copyStuff() {
var spreadsheet = SpreadsheetApp.openById("ID_OF_YOUR_SPREADSHEET");
var allLeads = spreadsheet.getSheetByName("All Leads");
var formSub = spreadsheet.getSheetByName("Form Responses");
var valsFromForm = formSub.getRange(3, 1, 53, 13).getValues();
allLeads.getRange(2, 1, 53, 13).setValues(valsFromForm);
}
Afterwards, you should replace the above snippet with this one:
function onFormSubmit() {
var spreadsheet = SpreadsheetApp.openById("ID_OF_YOUR_SPREADSHEET");
var allLeads = spreadsheet.getSheetByName("All Leads");
var formSub = spreadsheet.getSheetByName("Form Responses");
var openSheet = spreadsheet.getSheetByName("Open Leads");
var closedSheet = spreadsheet.getSheetByName("Closed");
var lostSheet = spreadsheet.getSheetByName("Lost");
var lastVals = formSub.getRange(formSub.getLastRow(), 1, 1, 13).getValues();
allLeads.getRange(allLeads.getLastRow(), 1, 1, 13).setValues(lastVals);
var cellValue = spreadsheet.getSheetByName("THE_NAME_OF_YOUR_SHEET_WHERE_CELL_VALUE_IS").getValue();
if (cellValue == "OPEN")
openSheet.getRange(openSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
else if (cellValue == "CLOSED")
closedSheet.getRange(closedSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
else if (cellValue == "LOST")
lostSheet.getRange(lostSheet.getLastRow(), 1, 1, 13).setValues(lastVals);
var lastVals = formSub.getRange(formSub.getLastRow(), 1, 1, 13).getValues();
allLeads.getRange(allLeads.getLastRow(), 1, 1, 13).setValues(lastVals);
}
The above snippet works by getting the last row from the Spreadsheet and then pasting it in the right place based on the cellValue. To get the last row of the sheet, the getLastRow() method has been used.
Since you want this to run on every form submission, you should use an onFormSubmit() installable trigger, and configure it like this:
Note: You will have to have the script linked to the form.
Reference
Sheet Class Apps Script - getRange();
Sheet Class Apps Script - getLastRow();
Installable Triggers Apps Script.

Related

Move and organize rows from main worksheet into multiple/respective sheets

For starters, I am a complete beginner at using Apps Scripts for Google Sheets at my new workplace, and we do not have an IT department who can help us create this file. I am trying to create a shared file that can be accessed by our client, our service technicians, and our main office simultaneously, so I opted to create a Google Sheet.
I am hoping to automate this process to prevent users (except myself) from needing to manually edit, move and sort data across multiple sheets that might cause the file to break or become inconsistent. For this to work, I need users to only be able to create entries in our 'main' worksheet and only view the other sheets. From here, I'd like to automate the file to move rows to specific sheets named after each unit when it's marked "DONE", and also organize each unit's sheet by the date column. Our intention is for these sheets to provide us with a running history of all the work that has been done each unit.
NOTE: I have 54 units and counting and I currently will have to copy & paste the code multiple times and edit each one to match the unit numbers. I currently have a one unit set-up, but I think there's something wrong with the code or the triggers I have set-up as it does not automatically sort the destination sheet. Either way, I think there has to be a simpler way to do this.
Any advice would be appreciated!
Here's the code that I've used thus far:
function trailer27() {
// moves a row from a sheet to another when a magic value is entered in a column
// adjust the following variables to fit your needs
// see https://productforums.google.com/d/topic/docs/ehoCZjFPBao/discussion
var sheetNameToWatch = "WORKSHEET";
var columnNumberToWatch = 6;2 // column A = 1, B = 2, etc.
var valueToWatch = "Yes";"27"
var sheetNameToMoveTheRowTo = "27"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
SpreadsheetApp.flush()
}
}
function Sort27() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("27")
var range = sheet.getRange("A3:F1000");
// Sorts by the values in column 1 (J)
range.sort({column: 1, descending: false});
}
function SortWorksheet(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WORKSHEET")
var range = sheet.getRange("A3:F1000");
// Sorts by the values in column 10 (J)
range.sort({column: 1, descending: false});
}
function undoMove() {
// moves a row from a sheet to another when a magic value is entered in a column
// adjust the following variables to fit your needs
// see https://productforums.google.com/d/topic/docs/ehoCZjFPBao/discussion
var sheetNameToWatch = "27"
var columnNumberToWatch = 6; // column A = 1, B = 2, etc.
var valueToWatch = "CALLED"; "EMAIL"
var sheetNameToMoveTheRowTo = "WORKSHEET";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
SpreadsheetApp.flush()
}
}
If this is meant to be an onEdit function it's worth using the event object even considering the difficulty in debugging
function trailer27(e) {
const sheet = e.range.getSheet();
var sheetNameToWatch = "WORKSHEET";
var columnNumberToWatch = 6; 2 // column A = 1, B = 2, etc.
var valueToWatch = "Yes"; "27"
var sheetNameToMoveTheRowTo = "27"
if (sheet.getName() == sheetNameToWatch && e.range.columnStart == columnNumberToWatch && e.value == valueToWatch) {
var targetSheet = e.source.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(e.range.rowStart, 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(e.range.rowStart);
SpreadsheetApp.flush();
}
}

Google Script - Unable to copy from one sheet to another

This is my first Google Script and I am coming from a VBA background so I have likely missed something obvious. I am attempting to copy from one sheet to another, some that is quite simple in VBA, but I am struggling with it and I dont understand what I am missing
The below code I would have though would copy a range in one sheet to another sheet. Not the whole range, just a section of it and only 1 row per an OnEdit()
I checked the ranges I am wanting to copy from and copy to using targetSheet.getRange(targetSheet.get1stNonEmptyRowFromBottom(1) + 1, 1,1,numColumns-1).activate(); & sheet.getRange(row, 1, 1, numColumns-1).activate(); and it selects the range I would expect
Currently the execution doesn't show any fails either
function onEdit(e) {
//This is sheet we will be copied to
const VALUE = ["LEAD","LANDSCAPE"];
//This is the column for the check box
const COLUMN_NUMBER = 25
//The main sheet that is being copied from
const MAIN_SHEET = 'Form Responses 1'
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var lead_or_landscape = sheet.getRange(row,20).getValue();
//This is so we dont run this by mistake on another cell edit or sheet
if((COLUMN_NUMBER == cell.getColumn() && MAIN_SHEET == sheet.getName && cell.isChecked() == true)
&& (lead_or_landscape == VALUE[0] || lead_or_landscape == VALUE[1])){
//copies row from current sheet to the specificed sheet (Lead or landscape)
var numColumns = sheet.getLastColumn();
var targetSheet = spreadsheet.getSheetByName(lead_or_landscape);
var target = targetSheet.getRange(targetSheet.get1stNonEmptyRowFromBottom(1) + 1, 1,1,numColumns-1);
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target());
}
}
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
You've to use parentheses in sheet.getName() and not use them in copyTo(target())
And you can use sheet.appendRow() method instead of copyTo(), that is easier.
function onEdit(e) {
//This is sheet we will be copied to
const sheets = ["LEAD","LANDSCAPE"];
//This is the column for the check box
const colNumber = 25;
//The main sheet that is being copied from
const mainSheet = 'Form Responses 1';
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var leadOrLandscape = sheet.getRange(row,20).getValue();
//This is so we dont run this by mistake on another cell edit or sheet
if(colNumber == cell.getColumn()
&& mainSheet == sheet.getName()
&& cell.isChecked() == true
&& sheets.includes(leadOrLandscape)){
//copies row from current sheet to the specificed sheet (Lead or landscape)
var numColumns = sheet.getLastColumn();
var targetSheet = spreadsheet.getSheetByName(leadOrLandscape);
targetSheet.appendRow(sheet.getRange(row, 1, 1, numColumns-1).getValues()[0])
}
}
I just took a quick look at your code, are you sure about this line?
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target());
it shouldn't rather be
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target);

Auto Archive Schedule; Time-based Trigger

I have been asked to create a live Google Sheets Spreadsheet to track the work schedule at our yard. I have no experience with a script but found out I could program my sheet instead of hiding formulas and it would yield a cleaner result. I have been able to make the sheet organize itself and I was able to make it Archive manually (onEdit). What I'm looking for is to have it automatically run the code at 1 am so when we arrive at work it archives based on a cell value in a certain column.
This is an example of my onEdit script that works, but when someone is trying to check off the "YES" column there is some lag and can cause the wrong cell to be checked, which I then manually correct.
function onEdit() {
var sheetNameToWatch = "Schedule";
var columnNumberToWatch = 28;
var valueToWatch = "Yes";
var sheetNameToMoveTheRowTo = "Archive";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
}
}
So this code runs at 100% failure but saves and executes, and I honestly don't know why. Could be I misunderstand the values I need to insert after the "function" area. I did have this setup with an "Auto Archive" trigger that created a menu button with a "Run" option on the sheet, but when you click that it only does the last row with "Yes" in column 28 (every press of the button will move 1 row until all rows are moved) and the button won't work for the other users of the sheet.
function createTrigger() {
ScriptApp.newTrigger("Move Archive") //Move Archive is the name of the script
.timeBased()
.everyMinutes(1) // only set to 1 minute for testing, I can change this out for a daily timer
.create();
}
function myFunction() {
var sheetNameToWatch = "Schedule"; // "schedule" is the sheet we enter info on
var columnNumberToWatch = 28; //Column is "AB"
var valueToWatch = "Yes";
var sheetNameToMoveTheRowTo = "Archive"; //"Archive is the sheet the info is sent to"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // I get its programmed for last row with "Yes" here, unsure on how to change this.
sheet.deleteRow(range.getRow());
function myfunction() {
ScriptApp.deleteTrigger("Move Archive"); // could have wrong value here
}
}
}
All I want is the sheet to "Archive" based on a "Yes" value in Column 28 (AB). I want every row with that column value to Archive at 1 am automatically. Any help is appreciated. If someone even wants to recommend a book or digital instruction for beginners that would be great.
You have four project files each containing scripts of the same name, performing the same or similar tasks. You are experiencing lagging because you have multiple simple and installable scripts of the same name. Essentially, they are all trying to execute at the same time.
The following answer should be considered as one possible solution to your situation.
The elements of this script are:
There is a single project file. Unnecessary project files have been deleted.
There is a single function.
The function is a single "simple" trigger (onEdit(e)) which takes advantage of the various event objects returns by onEdit. There are no installable triggers, and any/all installable triggers have been deleted.
The function updates the "Schedule" and "Archive" sheets as described in the question; and then sorts both the "Schedule" and "Archive" sheets.
If there is a change on the "Railcars" sheet, the function sorts that sheet.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var testrange = e.range;
var testsheet = testrange.getSheet();
var testsheetname = testsheet.getSheetName();
var testrow = testrange.getRow();
var testcolumn = testrange.getColumn();
var testvalue = e.value;
var testsheetLC = testsheet.getLastColumn();
var testsheetRange = testsheet.getRange(testrow,1,1,testsheetLC);
//Logger.log("DEBUG: the test sheet range is "+testsheetRange.getA1Notation());
//Logger.log("DEBUG: Range: "+testrange.getA1Notation());
//Logger.log("DEBUG: The row is "+testrow+", and the column is "+testcolumn);
//Logger.log("DEBUG: The spreadheetsheet is "+e.source.getName()+", the sheet name is "+testsheet+", the range = "+testrange.getA1Notation()+", and the new value = "+testvalue);
//Logger.log(JSON.stringify(e));
// Copy/Paste to Schedule/Archive
var sheetNameSchedule = "Schedule";
var colNumberSchedule = 28;
var valueSchedule = "Yes";
var sheetNameArchive = "Archive";
// Sort Schedule
var sortSchedule = [{column: 1, ascending: true},{column: 2, ascending: true},{column: 7, ascending: false}];// date // Appt (time) // Type (Out/In/RR)
// Sort Railcars
var sheetNameRailcars = "Railcars";
var sortRailcars = [{column: 1, ascending: true}];
if (testsheetname === sheetNameSchedule && testcolumn === colNumberSchedule && testvalue === valueSchedule){
// this is a match
// Logger.log("DEBUG: this was a match");
// copy/paste to archive
var targetSheet = ss.getSheetByName(sheetNameArchive);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
//Logger.log("DEBUG: the target range is "+targetRange.getA1Notation());
testsheetRange.moveTo(targetRange);
testsheet.deleteRow(testrow);
// sort the Schedule Sheet
var Avals = testsheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortSchedule);
// sort the Archive Sheet
var ATvals = targetSheet.getRange("A1:A").getValues();
var ATlast = ATvals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+ATlast+", and the last column = "+testsheetLC);
var sortrange = targetSheet.getRange(2,1,ATlast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortSchedule);
}
else if (testsheetname === sheetNameRailcars){
// sort the sheet
var Avals = testsheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortRailcars);
}
}
You can set up an installable trigger to run this function at 1am every morning:
function scheduleToArchive() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var schedule = sheet.getSheetByName("Schedule");
var archive = sheet.getSheetByName("Archive");
var scheduleData = schedule.getRange(2, 1, (sheet.getRange('A:A').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()), 28);
for (row = 2; row <= scheduleData.getNumRows(); row++){
var data = schedule.getRange(row, 1, 1, 28).getValues();
if (data[0][27] == 'Yes'){
archive.getRange((archive.getLastRow() + 1), 1, 1, 28).setValues(data);
}
schedule.getRange(row, 1, 1, 28).clear();
}
}
In your spreadsheet, when getDataRange() is run on the sheet named 'Schedule', it returns row 631 as the last row with data even though there is only data in the first 20 rows, so to get around that I've used SpreadsheetApp.Direction.DOWN instead and run that on column A.

Copy data from one spreadsheet to another onchange

Pardon me as I am fairly new to this and may be missing something easy.
I have a spreadsheet that I create data from a template, run a script over it to create forms which become user tasks. The edit URL from the form is used to complete the task and it records on the master sheet (Sheet2) with the status, attachments, data stamp, and email address. From there I am trying to create a list of tasks that need approvals from my master sheet to another sheet (LOG) on a different spreadsheet but I am having issues with openByID for my target spreadsheet. It says it is undefined. I can get this to work in sheets in the same spreadsheet but I would like it in a different spreadsheet if possible. This is all done onChange of Sheet2 when status changes to yes and only for specific tasks (Verification Report, Maintenance Memo, Check Report)
function onChange() {
// moves a row from one sheet to another sheet when a value is entered in a column and another column has specific values
var columnNumberToWatch = /* column D */ 4; // column A = 1, B = 2, etc.
var valueToWatch = "yes";
var sheetNameToMoveTheRowTo = "LOG";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var cell = sheet.getActiveCell();
var activeRow = cell.getRow();
var taskCheck=sheet.getRange(activeRow, 2);
var target = SpreadsheetApp.openByID("my spreadsheet id");
var targetSheet = target.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
if (sheet.getName() != sheetNameToMoveTheRowTo &&
cell.getColumn() == columnNumberToWatch &&
cell.getValue().toLowerCase() == valueToWatch &&
(taskCheck.getValue() == "Verfication Report" || taskCheck.getValue() == "Maintenance Memo" || taskCheck.getValue() == "Check Report"))
{
sheet.getRange(cell.getRow(), 1, 1, sheet.getLastColumn()).copyTo(targetRange);
}
}

Google Sheets: Row not copying to another sheet

I have two sheets. Pipeline and Archive. I also have a data validation list on column 5 that switches from blank to Yes only. When I debug it, it doesn't throw an error. But when I go to my sheet and change column 5 to yes, it doesn't move to the Archive sheet, nor does it delete anything.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var c = s.getActiveCell();
if (s.getName() == "Pipeline" && c.getColumn() == 5 && c.getValue() == "Yes") {
var targetSheet = ss.getSheetByName("Archive");
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(c.getRow(), 1, 1, sheet.getLastColumn()).copyTo(targetRange, {contentsOnly:true});
s.deleteRow(c.getRow());
}
}
Change:
s.getRange(c.getRow(), 1, 1, sheet.getLastColumn()).copyTo(targetRange, {contentsOnly:true});
s.deleteRow(c.getRow());
To:
s.getRange(c.getRow(), 1, 1, s.getLastColumn()).copyTo(targetRange, {contentsOnly:true});
s.deleteRow(c.getRow());
Hopefully this appeases the PTB...