Why do two users sometimes see different values from importrange? - google-apps-script

I have a very strange problem, the description can be a bit chaotic.
I have two spreadsheets A and B. One sheet inside A is importing data with importrange from the B. The problem is that sometimes two user see different values in that sheet.
Details:
I have two scripts inside A:
one that copies the values from the imported range to another sheet
one that calls that WebApp that changes data in B.
When two users have the A open and one of them makes changes to the B via script and then uses the other script which copies the values, everything is fine. But if one user closes the A, the other makes changes in the B with the script and when the first user reopens the spreadsheet, he will see new values, but if he uses the values copying script, the range containing the values from importrange will show old values. Oddly enough, the script that copies values from that range will copy the new correct values even if we don't see them.
The problem goes away when I manually make some changes to spreadsheet B. I don't know, it's like spreadsheet B doesn't refresh when I make changes via script or something
Do you have any ideas what is the reason for this and maybe how to solve it. I think that I can get round this problem but I would not.

Two Google Sheets users might see diffent values on the same spreasheet because formula calculation (including those that make API calls like IMPORTRANGE) are triggered by user actions like opening or edited the spreadsheet.
Some function also might recalculated by changes made by scripts so it's actually possible that an script could "see" different values than those that are seeing by the users.
If you need that the users see the same values, should consider to periodically "freeze" them i.e. make a copy of the spreadsheet then replace the formulas by their results.
Another option is to share the screen rather than relaing on the "real time" collaboration feature of Google Sheets.

Related

Is it possible for a GAS script to lock a Google Sheet so nobody else can alter it until the script is done

I am familiar with the Lock Service but that is only for locking scripts.
I have some code that will "process" a large Google Sheet. My script needs to re-order the rows. I need/want to make it so while the script is running nobody else can change the order. However, I still need another script to be able to append rows.
We use a Google Form for our team's intake. It appends rows to a sheet. I have an hourly job that will go through all the rows/records and "process them". I have a column that stores the last time a record/row was "processed". I want to sort on that column such that the "oldest" records are on top and then start processing from the top down. If the script fails or times out then the next iteration will just start over...
I know I could use getValues or getDisplayValues to get an array and then write the array back but I worry what would happen if someone sorted the rows as it would muck things up when writing the array back.
Is there some way to accomplish my goal? I want to be able to process the records, and maintain row order to avoid breaking my processing.
The way to block a spreadsheet "completely" is by changing the spreadsheet sharing settings. Remove all editors or change them to viewers, once your script finish, change them back as editors. In a extreme case, usa a second account to act as the owner of the critical files / spreadsheets and only use it for this purpose,so you could block your regular account for doing changes to the spreadsheet.
NOTE: A Google Form editResponseUrl could be used to edit the linked spreadsheet.
I'm facing a similar situation but I took a different approach, I'm using an index/key column (you could use the timestamp column) and using the index/key to save each edited row to the right position, then write the whole resulting array in a single operation (by using setValues()). In my case this is simple because I only require values, I'm not worried about notes, data validation, conditional formatting, comments, etc. and there isn't a Google Form linked to my spreadsheet.
Related
Google Spreadsheet -- get sharing permissions by script
Any way to share google docs programmatically?

Bad writing in GoogleSheets

I've one sheet that works as database which gets the data from too many different sheets. It works in that logic, I've multiple sheets that everyone is filling the data in and then click on a button to trigger a script that takes the data and paste it in the database sheet, and sends an email with the data to the relevant stakeholder.
The issue I'm facing is that, if two sheets triggered the script at the same time one sheet will overwrite the other one because both were triggered at the same time and both were targeting the same row in the database.
I've tried the lock methods as well but it will not work because those are multiple sheets and multiple scripts, and tried to assign a ticket number property but it will not work as well because every script is operating on different sheet. thought of library but it will not be as fast as the normal script.

How to roll-back change events to a Google sheet or disallow only change events but allow edit rights to users?

Trying to build a dashboard wherein, in certain sheets users need to be able to add rows, but shouldn't be able to change values of the preset cells. If I protect those cells, they cant add rows, if I dont protect the sheet, and revert changes to preset cells using a Google Apps Script onEdit trigger, they are able to insert rows, and cant change values, but that leaves my sheet open to unforseen modifications, like inserting columns, inserting more rows than required, changing formatting, etc.
Is there a way to let them add rows but not do anything else to the sheet except the limited cells they need to edit?
I see this issue/request often, you are trying to use Google Sheets in a form-like manner where users should only be permitted to do X actions (some people use Google Forms to feed into the spreadsheet for similar problems).
One idea here is to create a button to add a row. By default you can make everything protected. When the button is pressed, Google Apps Script can unprotect and create a row at that location. One issue with this solution is that buttons in Google Apps Script are like floating images - so you would need to create function names like "addRowAtSheet4". Here is what that button could look like, where ADD CITATION would create a new row on click:
Another issue is that a user that wants to damage your spreadsheet will be able to since the protections are done from the user's bound script and run from the user's account, which brings me to the second solution:
If you need true cell protection (assuming you are the spreadsheet owner), you can create a standalone webapp to do all of the admin stuff and lock everything down on the user side as desired. When the user clicks the button, a web request is issued from the GAS bound script of the spreadsheet to the published webapp, and in the webapp you add the row on behalf of the user from your own account (i.e., "Execute the app as: Me"). Something like this, where the parameters sent are the row to be added, for example:
Note that if there can be multiple simultaneous users adding rows on the same place, you may like to use LockService.

How to hide certain columns for a user?

On a shared Google spreadsheet:
I don't want a specific user in my domain to view columns with sensitive data, but this person should still be able to edit the rest of the spreadsheet.
I tried creating a 'master' spreadsheet and using importrange to bring the data into a 'shared' sheet, but once I edit any cell in the shared spreadsheet, importrange no longer works as the sheet is emptied out.
Is there a quick way to do this, maybe using scripting?
After some research and trying various different options, I was finally able to achieve what I want using the importrange function.
At first, I tried using a combination of hide columns & protect range, but this wouldn't work because a simple copy & paste would reveal the contents of the hidden columns.
Solution: The 'master' spreadsheet does not have any sensitive column data and can be shared with everyone in the organization... I then ADD the sensitive data to a new spreadsheet and use importrange to grab contents from the 'master'. (Previously I had the roles reversed, but this didn't work)
You may want to add unique keys per row entry so that sorting etc won't mess things up when you zip-up the sensitive data and the 'master' data.
I came here looking for a way to share only certain columns of a spreadsheet with a customer, but not all.
As noted in the other answer, using =IMPORTRANGE works well, but a clever customer could simply edit the function and see the other columns.
My solution was to first create a 'proxy' spreadsheet that imported only the columns I want the customer to see. This proxy spreadsheet is not shared.
Then, I created another spreadsheet that imported the columns from the proxy, and shared that spreadsheet with the customer. This way, even with edit privileges, it's impossible for him to see anything that isn't on the proxy spreadsheet.
A bit clunky to be sure, but it worked perfectly for my situation.

Insert a date, Highlight/move a row when date is added and highlight in another sheet

Can anyone help with these Google Apps Script questions? I've never used scripts before, but I think they could solve my issues...
How do I most easily insert the current date?
Is there a way to highlight a row when the current date is added, and then move that row to the bottom of the current rows?
Is there a way to highlight a name field when it is a duplicate in another sheet?
Is there a way to highlight a row when it is highlighted in another sheet?
I would like to develop a spreadsheet to track the progress of magazine advertisers. I need to track when we receive an advertiser's information and when the ads are proofed out. (Lots of dates to insert!) Then when the ad is approved, I need to highlight that row and move it to the bottom of the other rows. (The number of current rows will be constantly changing.) Then once I receive the layout, I need to know what ads we have and of those, which are approved.
I hope someone can help me out with these questions--thank you in advance!!
Cortny!
A few places to start at regarding Events, Triggers and Spreadsheet handling:
https://developers.google.com/apps-script/understanding_events
https://developers.google.com/apps-script/understanding_triggers
https://developers.google.com/apps-script/reference/spreadsheet/
I have scripts that upon editing a row record in a particular column of that row the time it was edited and in another column the username (email address) of the user editing. This script was originally in a couple of different libraries and I tried to paste the relevant portions into a single script and generalize it to the extent possible. I have not tested as it appears here -- I hope I copied everything:
https://script.google.com/d/1qVLXiKZA8SAgOoW2BAcOCtQ2bXeCNz6oRed8bN9YOOPpvdI0HzAdxeC0/edit?usp=sharing
Since this script also accesses the user's email address it must be explicitly authorized by each user before it works properly. It is for this reason that the main functions is called onEditDelegate() that must be added manually to the onEdit trigger instead of being called onEdit(). If you don't need the username, you can remove that part and it will be easier to install the script.
You can also extend this script so that when all the necessary info is entered the script copies the content of the row, deletes it from the spreadsheet and pastes it at the bottom of the sheet.
Similarly the other points you mentioned can be achieved using triggers/events.
Good luck!