Some spreadsheet cells not updated before trigger function sends email - google-apps-script

I have a spreadsheet which extracts and accumulates all the required data from other 6 spreadsheets using Vmerge and Query formulas and all the consolidated data will be converted to pdf and emaild to mail ids using trigger event.
Here begins the problem every time the attachment mail posted consist all the headers and other format, but the data which is extracted does not appear. It seems to appear like - to open the same spreadsheet, after a while all the - (hyphens) are replaced by the data / Hope all the data updates after a while of opening the spreadsheet.
link for sheet
Can anyone direct me to make this issue sorted out.
For this solution should be -> all the data should be updated and then the email script should work; or either it should update before emailing script starts.
Or any other better ideas are appreciated.

Some spreadsheet formulas, like ImportRange and ImportXml (and also Apps Script custom formulas) are only evaluated when there's someone logged in the spreadsheet. It's like these functions need an account to be evaluated from, for example, in importRange the account logged in must have access to the range being imported, if you share this spreadsheet with someone but not the importRange source, when this person is viewing this spreadsheet, the importRange function will not work (well, unless you're also in the spreadsheet and the formulas have already been evaluated).
Bottom line is, you can't have this formulas and use a script triggered on time-driven (or other trigger that does not require someone logged in) and expect the script to be able to read this data.
The workaround though is quite simple. Do what the importRange function does inside your script! e.g.
var source = SpreadsheetApp.openById('source-spreadsheet-key');
var data = source.getSheetByName('List').getRange('I6:AT500').getValues();
//then save it somewhere
var s = Spreadsheet.getActive().getSheetByName('hidden-import');
s.getRange('I6:AT500').setValues(data);
SpreadsheetApp.flush(); //force the data to be written
//so all the other formulas on your spreadsheet get updated with the new data
All your "logic" formulas, like query and vmerge, which are difficult for the script to mimic, can be left on the spreadsheet, but reference this "hidden-import" sheet I just invented instead of nesting importRange directly.
[edit]
To copy only non-empty rows do like this:
var data = SpreadsheetApp.openById('source-spreadsheet-key').
getSheetByName('List').getDataRange().getValues();
Spreadsheet.getActive().getSheetByName('hidden-import').
getRange(1,1,data.length,data[0].length).setValues(data);

Related

How to protect the cell/range at the same time as appendrow

Im working on a website that stores data in a google spreadsheet and was wondering how I could use the appendrow() function and then protect that cell so no one can access it.
I'm new to google apps script and have been searching the internet for the last hour or so and can't find anything.
sheet.appendRow([text]);
But after that I would like it to get the value of that cell that was just written on so I could write:
var protection = the-row-just-written-on.protect()
I I am hoping for the result to be that no one can delete the text once it has been written on.

Google script: unprotect a sheet through function when user has no right to do so

I have a spreadsheet with different sheets in Google sheet, 3 users can edit each one a sheet (protections are set, each user can edit only one sheet). They all can execute a google script function that writes what they edited in a summary sheet. I don't want anyone to be abble to edit the summary sheet, so I set myself as the only available editor.
So my problem is to authorize the 3 users, only through the google script function, to write in the summary sheet. I tried to use the following function :
var unprotected = summarySheet.getRange('G3:G10');
protection.setUnprotectedRanges([unprotected]);
but since the users are not allowed to edit the summary sheet, and since the function is run with the active user, so they can't give themselves the right to unprotect a range in the summary sheet... Do you know how to workaround this problem?
Thanks a lot!
I see two script-based choices, one easy and one quite hard, and one sheet-based choice, that is easiest:
Easy:
You run the "summarize" script instead of them or, you set the summarize script run on a trigger out of your account. Then you actually leave protections alone. You could set the summarize script to run on open with error catching if the user doesn't have the necessary authority to unprotect the summary sheet and/or write to the summary sheet.
Hard:
When they run the "summarize" script it calls a published standalone script that has been given the authorization to make the necessary protection changes. I'll be honest, I wouldn't be able to code this but have seen/heard of similar implementations.
Easiest:
Finally, I want to make sure you've considered having the summary sheet itself contain the necessary formulas, parsing, etc. to summarize data from the other sheets without any need of scripts for this aspect of the sheet. The sheet could call custom functions as needed if the parsing or other summarization functionality is beyond built-in functions' capabilities. The sheet could stay fully protected and update itself in real time as users enter data (no need for users to trigger the summary creation, unless spreadsheet settings have auto-recalculate turned off).
Edited to add: put in A1 of Summary sheet something like:
=summarize()
And have that custom function return a 2-dimensional array of the summarized data.

Duplicate Form responses to two Google Sheets programmatically

I need to save my Google Form in two different sheets.
The first sheet will be the one for history and the other one will be exploited by the logistic services (who may delete some rows when the clients receive the shipped stuff).
I really need to keep all the responses on the first sheet whatever the logistic services do on the second.
The fact is; I was using formRat, but is not working anymore and I don't see any complementary module that does exactly the same thing. I'm not good enough in programming to write the script by myself.
I tried to write this in the second sheet:
=ArrayFormula('first_sheet_name'!A:W)
But when I try to delete a row on the second sheet, it reappears a few seconds later because Google Sheets recalculates it.
A form submission trigger script attached to the Form Response spreadsheet can easily copy responses to the second sheet, as they arrive. Any modifications made later on the second sheet will survive.
Here is a very simple example of such an Installable Trigger Function. You need to declare ss2ID with the Sheet ID of spreadsheet 2. The script assumes that the responses are to be copied to the first sheet in spreadsheet 2, and that all form answers are populated.
function copyResponse( event ) {
fixFormEvent( event ); // From https://stackoverflow.com/a/26975968/1677912
var ss2Id = "---sheet-id---";
var sheet2 = SpreadsheetApp.openById( secondSheetId ).getSheets()[0];
sheet2.appendRow( [event.values] );
}
This function uses fixFormEvent( event ) from e.values in google forms skips empty answers, is there a workaround? to ensure the columns in the new sheet align with the original questions.

IMPORTRANGE function not refreshing new entries in linked Google sheet

My IMPORTRANGE function is not refreshing with new data once the linked spreadsheet is added to. Instead, I am having to cut and paste all of the formulae again whenever I want to view the new information.
I'm using the new version of Google Sheets and I know there were some issues around the release of this with the IMPORTRANGE function.
I currently have 24 columns of data that I'm importing and the original spreadsheet will just keep growing as it is linked to a form. This is the main reason I'm using IMPORTRANGE, as it will help to keep the original spreadsheet working at maximum speed.
What I'd like to know is, has anyone else had a problem such as this, and if so is there any work around (in apps script/another function)? In worst case scenario, is there an apps script about which would clear the spreadsheet and re-enter all of the formulae on open/on a menu click as it really is a pain updating every column every time a new entry is made.
EDIT - Almost all of the cells I'm trying to import are formulated within the original spreadsheet if that changes anything - EDIT
In the spreadsheet settings under "File", go into the Calculations tab and change the Calculation Setting to "On Change and every minute". I had to do this on another importrange sheet and it did the trick for me.
What solves the problem? Setting the same owner for both spreadsheets: the one that you import data from and the one where you use importrange formula. I had the same problem. I updated the source and no response on final spreadsheet. After setting same owner for both spreadsheets refreshing takes few seconds
I've worked out an ultimate (and very simple) solution to any importrange problems. Let's say you have your data in Sheet1 and it's being collected from a google form. You'd like to importange it somewhere else but newly received rows don't trigger importrange refresh. The solution is to move the data using QUERY to Sheet2 (in the same file) and then importrange the data from Sheet2 to another file; it's easy to force refresh of the QUERY function using simple macro, below I pasted simplified version of my function:
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet2'), true);
spreadsheet.getRange('A1').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getCurrentCell().setFormula('=QUERY(\'Sheet2\'!A:Z;"SELECT *";1)');
};
So basically I clear the A1 cell that contains the QUERY formula and then I fill it with the same QUERY formula. I set this macro to trigger every 1 minute. Works like a charm.
A trick that seems to work
Instead of
=importrange("Relevant_Sheet_ID","Archive!a1:p259")
Use the below just adding => &"?"&now()
=importrange("Relevant_Sheet_ID"&"?"&now(),"Archive!a1:p259")
Basically, it fools GoogleSheets to think the data set referred is ever changing by adding a timestamp through a now() function.
Feedback welcomed, seems to work for me, but might not be consistent.
Click File > Spreadsheet Setting... and check both sheets are in the same Locale and if responces are comming from Jotforms, set the same Locale there too.
Make a copy of your master sheet and change url of your importrange function. it's work for me..
=importrange(new_master_sheet_copy_url,string_range)

script to force republish of google spreadsheet

I have created a form that pushes data to a Google Spreadsheet. The data is latitude, longitude, location, and other identifying data. The spreadsheet is then published as a .CSV file and imported into ARC GIS to be displayed on an interactive map. It works exactly as I wanted and I set it to republish after each change.
The problem is that when the spreadsheet has rows appended by the script, it is not seeing it as a change and republishing. In order to get the updated data imported to the map, I need to go in and manually republish. Is there anyway through the Google Apps Script that I could make a few lines of code to force a republish? I could then add that to the "on form submit" script I have or another time based one that already runs at 3 am everyday.
I have looked through the Google Apps Script documents and not found anything. When searching for help on the web, the overwhelming majority of responses are for how to publish your script as a template for other.
My testing sheet was republished after the following function was executed by either a menu entry or a time-based trigger.
function ChangeIt() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var t = new Date()
var x = 'upd: ' + t
var range = sheet.getRange('a3')
range.setValue(x)
}
If I were in your shoes, I'd add an extra column to the end of the sheet with some benign constant data that a script can change without affecting the systems consuming the data. If an extra column isn't an option, try modifying my sample to read in a current value, change it, and immediately change it back.
Also, I'd see if the spreadsheet onEdit() trigger fires when the form submit adds a new row. If so, tie your GAS function to it to force the republish. If not, setup a timed trigger to execute the GAS function.
A quick workaround for this issue that doesn't require scripting is to simply make an array copy of the data.
For example, I made a new tab and in A1 put this: =ArrayFormula('Form Responses 1'!A1:Z1000)
While the main Form responses tab will insert rows and not play nice with formulas this new tab stay nice and constant and updates automatically when new data is added.