Google Sheets script to archive data - google-apps-script

I have created a Google Sheet for an in game Estate Agency.
The first tab "Residential Appraisal" is the data input form, and with the click of a button I want the data entered (C16:C56) to be archived on "Residential Appraisal Archive" on the next available row.
When the data is pasted it will need to be pasted as transposed and values only (due to formulas).
I am very new to the scripting side of things and have attempted to figure it out myself but got nowhere of any note. Please find the link below to the sheet.
https://docs.google.com/spreadsheets/d/1BF4Ao8L7FfitZFGX7QDfqbthmiu2A7CKXuJw0Av-0jY/edit?usp=sharing
Code:
function Reset_Residential() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C16:C20').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C22').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C23').activate();
spreadsheet.getCurrentCell().setValue('10');
spreadsheet.getRange('C24').activate();
spreadsheet.getCurrentCell().setValue('Undetermined');
spreadsheet.getRange('C28:C38').activate();
spreadsheet.getActiveRangeList().check();
spreadsheet.getActiveRangeList().uncheck();
spreadsheet.getRange('C39:40').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C45').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C50').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C52').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
};
function Reset_Buisness() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C16:C21').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C23').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C24').activate();
spreadsheet.getCurrentCell().setValue('10');
spreadsheet.getRange('C25').activate();
spreadsheet.getCurrentCell().setValue('Undetermined');
spreadsheet.getRange('C26').activate();
spreadsheet.getCurrentCell().setValue('Please Select');
spreadsheet.getRange('C30:C31').activate();
spreadsheet.getActiveRangeList().check();
spreadsheet.getActiveRangeList().uncheck();
spreadsheet.getRange('C32:C33').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C38').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C43').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('C45').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
};
function jumpToFirstEmptyBasic() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Appraisal Archive"); // << Change the sheet name to your own sheet.
var lastRow = sheet.getLastRow();
sheet.getRange(lastRow+1,1).activate();
}
function Residential_Archive() {
const ss = SpreadsheetApp.getActive();
const sourceRange = ss.getRange('Residential Appraisal!C16:C56');
const targetRange = ss.getRange('Results Historic!' + ss.getRange('Audit correction!Y3').getValue());
sourceRange.copyTo(targetRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, true);
showMessage_('Values copied.');
}

I believe your goal is as follows.
You want to copy the values from the cells "C16:C56" of "Residential Appraisal" sheet to the sheet "Residential Appraisal Archive". At this time, you want to copy only the values without including the formulas.
You want to run the script when a button is clicked.
When I saw your sheets of "Residential Appraisal" and "Residential Appraisal Archive", I could confirm the cells "C16:C56" of "Residential Appraisal", and I also confirmed that the sheet "Residential Appraisal Archive" has the empty columns of "F", "J", "L", "Z", "AF", and "AH". In this case, I thought that the values can be directly retrieved from the cells "C16:C56" and copy them to the destination sheet.
And also, I noticed that in your Spreadsheet, there are 2 pairs of source and destination sheets.
source sheet: "Residential Appraisal", destination sheet: "Residential Appraisal Archive"
source sheet: "Buisness Appraisal", destination sheet: "Buisness Appraisal Archive"
I thought that you might have wanted to use this script for the above 2 pairs. So in this answer, I would like to propose a sample script that can use these 2 pairs.
Sample script:
Please copy and paste the following script to the script editor of the Spreadsheet. And, please assign the function name of "sample" to the "Archive" button on the sheets of "Residential Appraisal" and "Buisness Appraisal". By this, when you click the button at "Residential Appraisal", the values are copied to the sheet "Residential Appraisal Archive". And, when you click the button at "Buisness Appraisal", the values are copied to the sheet "Buisness Appraisal Archive".
function sample() {
const obj = [
{srcSheetName: "Residential Appraisal", dstSheetName: "Residential Appraisal Archive"},
{srcSheetName: "Buisness Appraisal", dstSheetName: "Buisness Appraisal Archive"}
];
const ss = SpreadsheetApp.getActiveSpreadsheet();
const currentSheet = ss.getActiveSheet().getSheetName();
const sheet = obj.filter(({srcSheetName}) => srcSheetName == currentSheet);
if (sheet.length == 0) return;
const src = ss.getSheetByName(currentSheet);
const dst = ss.getSheetByName(sheet[0].dstSheetName);
src.getRange("C16:C56").copyTo(dst.getRange(dst.getLastRow() + 1, 1), SpreadsheetApp.CopyPasteType.PASTE_VALUES, true);
}
Note:
If you don't want to use this script at the sheet "Buisness Appraisal", please remove the function name from the button on the sheet "Buisness Appraisal".
Reference:
copyTo(destination, copyPasteType, transposed)

Related

Google Sheets - App Script (copyTo - cell content & format)

I have a tracker to count daily productivity.
This is appended to a weekly tracker, in which the sum of the two serves as a running total.
The weekly tracker is appended to a separate sheet to serve as historical data.
TRACKER
DATA
As you can see in the 'DATA' screenshot, the formula is being copied from K12:O12
see function copyTT / source.copyTo
I want to retain cell formatting, and copy only the cell data, not it's formula.
Script;
function mergeTT() {
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var source = ss.getRange("NEW_TTRACKER!J3:O3");
var destSheet = ss.getSheetByName("NEW_TTRACKER");
var lastRow = destSheet.getRange("J7:J11").getValues().filter(String).length;
var destRange = destSheet.getRange(lastRow+7,10,1,6);
source.copyTo(destRange, {contentsOnly: true});
var ws = ss.getSheetByName("NEW_TTRACKER")
ws.getRange('K3:O3').clearContent();
}
function copyTT() {
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var source = ss.getRange("NEW_TTRACKER!J5:O12");
var destSheet = ss.getSheetByName("NEW_TDATA");
var destRange = destSheet.getRange(destSheet.getLastRow()+1,1);
source.copyTo(destRange, {contentsOnly: false});
var sheet = SpreadsheetApp.getActive().getSheetByName("NEW_TTRACKER");
sheet.getRange('J7:O11').clearContent();
}
Thanks in advance.
I've been attempting to get around it playing with different CopyPasteType properties and I'm really not getting anywhere.
About I've been attempting to get around it playing with different CopyPasteType properties, I think that your approach is correct. In your script, how about modifying your script as follows?
From:
source.copyTo(destRange, {contentsOnly: true});
To:
source.copyTo(destRange, { contentsOnly: true });
source.copyTo(destRange, SpreadsheetApp.CopyPasteType.PASTE_FORMAT, false); // Added
By this modification, the format is also copied.
Reference:
copyTo(destination, copyPasteType, transposed)

Google script to copy and paste

I'm trying to work out if it's possible to write a script that will copy and paste special all the values in a tab with the same name across multiple workbooks in a file?
This is what I have so far but I just can't seem to get it to work properly? Any help would be most appreciated.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Copy and Paste')
.addItem('Copy and paste sheet with new name', 'copyAndPasteSheetWithNewName')
.addToUi();
}
function copyAndPasteSheetWithNewName() {
var sheetName = Browser.inputBox('Enter the name of the sheet to copy and paste:');
var folder = DriveApp.getFileById(SpreadsheetApp.getActive().getId()).getParents().next();
var files = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
while (files.hasNext()) {
var file = files.next();
var workbook = SpreadsheetApp.open(file);
var sheet = workbook.getSheetByName(sheetName);
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
}
}
From your following reply,
What I'm trying to do is just have the final part of the script hard code the worksheet. It's full of formulas and I want the results of those formulas not the formulas themselves.
In this case, how about the following modification?
From:
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
To:
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
range.copyTo(range, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false); // or range.copyTo(range, {contentsOnly: true});
By this modification, the last row of each sheet is converted to only the values without the formulas.

How do I fix this Macro to CONCATENATE and then paste values of two columns

I'm trying to write a macro in gsheets that will concatenate two columns and then copy the values back over to the first column. But everything I try the copy to column just gets blanked out.
function CopyandPasteValues() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('H2').activate();
spreadsheet.getCurrentCell().setFormula('=CONCATENATE(E2,"",G2)');
spreadsheet.getActiveRange().autoFill(spreadsheet.getRange('H2:H249'), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
spreadsheet.getRange('H2:H249').activate();
spreadsheet.getRange('E2').activate();
spreadsheet.getRange('H2:H249').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
SpreadsheetApp.flush();
};
If you only need the values, try the the following:
function CopyandPasteValues() {
var spreadsheet = SpreadsheetApp.getActive();
var values = spreadsheet.getRange('E2:G249').getDisplayValues();
var output = values.map(row => row[0] + row[2]);
spreadsheet.getRange('H2:H249').setValues(output);
};

Copy in new row every time run app script in google sheets

I try to create script to copy one specific row from one sheet to another sheet in new row.
But the script allways copy replace the last one.
I use this code:
function Test() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A9:O9').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Logs'), true);
spreadsheet.getRange('A24').activate();
spreadsheet.getRange('Log!A9:O9').copyTo(spreadsheet.getActiveRange(),
spreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Log'), true);
spreadsheet.getRange('D9:O9').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
};
Your script always copies the data to the activated range - which is always A24
Rewrite your funciton by specifying to where you want to copy your row. If you do not want to overwrite, probably you want to append your row at the bottom of the destination sheet.
You can do it as following:
function Test() {
var spreadsheet = SpreadsheetApp.getActive();
var originSheet = spreadsheet.getSheetByName("Log");
var destSheet = spreadsheet.getSheetByName("Logs");
var rowContents = originSheet.getRange('A9:O9').getValues().flat();
destSheet.appendRow(rowContents);
};
Alternatively, you can copy the data to the first empty row:
function Test() {
var spreadsheet = SpreadsheetApp.getActive();
var originSheet = spreadsheet.getSheetByName("Log");
var destSheet = spreadsheet.getSheetByName("Logs");
var firstEmtyRow = destSheet.getLastRow() + 1;
var destRange = destSheet.getRange('A' + firstEmtyRow + ':O' + firstEmtyRow);
originSheet.getRange('A9:O9').copyTo(destRange,
spreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
References:
getSheetByName()
appendRow()
flat()
getLastRow()
As pointed out by #Mike Steelson, activating sheets and ranges is not good practice. It is performed in the background if you record a macro, but it is prone to errors, so if you write a script yourself - avoid activate().

Copy and Past NamedRange/Whole Line

I've been using the script below to copy and paste all previous rows in an inserted row before on Google Sheets.
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('20:20').activate();
spreadsheet.getActiveSheet().insertRowsBefore(spreadsheet.getActiveRange().getRow(), 1);
spreadsheet.getActiveRange().offset(0, 0, 1, spreadsheet.getActiveRange().getNumColumns()).activate();
spreadsheet.getRange('21:21').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
spreadsheet.getRange('L20').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('H20').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
};
As I will have insertions below each other, whenever I use the top ones will change the line to be copied to the others. I would like to remove dependency on expression ('20:20'), and a think that NamedRange is the way.
Is it possible to copy the values of a whole row or named range in one sheet and paste them in the same sheet, just creating a line above?
Using the Porperties Service [1] you can fix your problem, I edited the code linked to your example Spreadsheet as follows:
function PlusMP() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('5:5').activate();
spreadsheet.getActiveSheet().insertRowsBefore(spreadsheet.getActiveRange().getRow(), 1);
spreadsheet.getActiveRange().offset(0, 0, 1, spreadsheet.getActiveRange().getNumColumns()).activate();
spreadsheet.getRange('6:6').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
spreadsheet.getRange('L5').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('H5').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
//Set offset property
var scriptProperties = PropertiesService.getScriptProperties();
var offset = Number(scriptProperties.getProperty('offset'));
if ( offset == null) {
scriptProperties.setProperty('offset', 1);
}
else {
scriptProperties.setProperty('offset', offset + 1);
}
};
function PlusCOMP() {
//Get offset property
var scriptProperties = PropertiesService.getScriptProperties();
var offset = Number(scriptProperties.getProperty('offset'));
if(offset == null) {
offset = 0;
}
var row = 10 + offset;
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange(row + ':' + row).activate();
spreadsheet.getActiveSheet().insertRowsBefore(spreadsheet.getActiveRange().getRow(), 1);
spreadsheet.getActiveRange().offset(0, 0, 1, spreadsheet.getActiveRange().getNumColumns()).activate();
spreadsheet.getRange(row + ':' + row).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
spreadsheet.getRange('L' + row).activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('H' + row).activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
};
function resetOffset() {
PropertiesService.getScriptProperties().setProperty('offset', 0);
}
When the PlusMP function is run it'll set or update the offset property, and when PlusCOMP function is run it'll use the same offset property to insert the rows accordingly.
[1] https://developers.google.com/apps-script/reference/properties/properties