Different Timestamp captured in Google Form and App Script - google-apps-script

I have a use case where i need to get the timestamp for the form responses (and string it) and email to respondent.
Here is my code and i would like to ensure it's exactly the same as Timestamp in my sheet
Code
Logger.log("e.response.getTimestamp()" + e.response.getTimestamp()) ;
Screenshot of the respondent (sorry for couldn't post image yet)
Screenshot of the respondent
Questions
- How come the timing is 1 second different?
- How could i string it (in both form and app string) so i can get identical result

The problem is that Google Forms stores internally form responses using milliseconds but when writing the timestamp to Google Sheets the timestamps are rounded to seconds.

Related

Updating Google Sheet with WooCommerce Order

I need to be able to automatically update a google sheet file every time an order is placed through WooCommerce.
I've found the solution below, but using this each individual item ordered is listed as a new row. I'd like the order to be grouped under the order number and the item quantities separated into appropriate columns instead.
https://www.tychesoftwares.com/export-woocommerce-orders-to-google-sheets-in-realtime/
Below is a Google Sheet we are manually updating at present to show you what i mean.
Example
Is there a way to send the WooCommerce orders directly through to Google Sheets in this format?
Thanks so much in advance for any advice!
Yes it looks possible.
I know nothing about WooCommerce, but I believe you can sort out the received data in any way you want.
Look, the last line in their script appends the received data as a new row:
sheet.appendRow([timestamp,order_number,order_created,order_status]);
As far as I can see, the data contains the four elements:
timestamp
order_number
order_created
orders_status
Instead, you can put these elements into any cell on your table. Something like this, for example:
var ss = Spreadsheet.GetActiveSheet();
ss.getRange('A10').setValue(timestamp); // timestamp goes to A10
ss.getRange('B20').setValue(order_number); // order_number goes to B20
ss.getRange('C30').setValue(order_created + order_status); // created + status go to C30
The same way you can add any of these elements to some existing value in some cell, etc. For example:
var old_value = ss.getRange('A2').getValue(); // get value from the cell A2
var new_value = old_value + order_number; // add with order_number
ss.getRange('A2').setValue(new_value); // put the sum back into the cell A2
The main problem is up to you. You have to figure out:
what exactly the elements you're receiving (number, names)
how exactly you want to sort them out (what to add to what... what to put where... etc)
I can't understand it from the example picture.
Here is some reference documentation on Apps Script:
Main Page - Introducing Apps Script.
Sheets Guide - Introduction to Sheets with Apps Script.
Sheets Reference - Where you will find all the details of everything you can do with Sheets in Apps Script.
Remove Duplicate Rows - A good small tutorial that will teach you the basics of Sheets and Ranges and how to manipulate them.
To export all my WooCommerce orders on a scheduled basis, I used a ready-made solution.
I used a WooCommerce API and JSON client. It worked smoothly: I got the WooCommerce API, and the JSON client was implemented in the tool already.
You just need to choose endpoint in the JSON client to get the required data. I exported all orders once a month, so I used the base URL http:// mydomain /wp-json/wc/v3/orders and my endpoint was orders.
You can check this article to understand better how it works for your purpose.
And here is WooCommerce API documentation.
I assume that setting up an export through the Apps Script is more flexible (and based on the answer above, it's working indeed), but I'm not a code guy. So I searched for an easier solution, and the API + JSON client helped.
Hope you'll find it helpful.
I would like to suggest using WooCommerce Google Sheet Plugin

Generating hyperlinks to prepopulate Google form

Context:
I created a Google Sheets/Forms workflow using sequential stages of Google Forms.
Form 1 (public facing) Accepts some data submitted by a public user and saves to Sheet 1.
Internal staff then contacts the submitter by telephone and conduct a more in-depth interview.
Form 2 (internally facing) is used by the interviewer to document
answers to the phone interview.
This question concerns the generation of Form 2 because I am partially pre-populating it with information from Sheet 1 (Form 1 submissions.) The way I figured out was to formulaically generate a URL with appended pre-population arguments e.g. "&entry.NNNNNN=whatever". I copied-down this formula in the last column of Sheet 1. Clicking on the cell and then the generated hyperlink successfully pre-populates Form 2 with data from the respective row of Sheet 1 as intended.
Problem: As soon as a new Form 1 submission is received, a new row is inserted into the Sheet 1 that does NOT contain the desired hyperlink formula in the last column. I would like that to be automatic so the interviewer is not responsible for performing a copy-down before every request for a Form 2.
I have pursued a couple of approaches to automating this:
One thread advised instead of copy-down, to create an arrayformula in the top cell so that it applies to the entire column including newly inserted rows as well. I tried every way I could think of but was unable to get my formula to produce a column of results with arrayformula(). If there is a way to fix this, that would be a satisfactory solution.
=HYPERLINK(CONCATENATE("https://docs.google.com/forms/d/e/XXXXXXXXXXXXXXXX/viewform?usp=pp_url&entry.251357138=",C2,"&entry.966351469=",D2,"&entry.384696201=",E2,"&entry.1366694528=",F2,"&entry.463407115=",M2,"&entry.1557144679=",B2,if(P2,"&entry.1777888516=Email",""),if(O2,"&entry.1777888516=Phone",""),if(H2,"&entry.2110474669=Individual+(Adult)",""),if(I2,"&entry.2110474669=Individual+(Under+18,+Minor)",""),if(J2,"&entry.2110474669=Couple",""),if(K2,"&entry.2110474669=Family",""),if(L2,"&entry.2110474669=Group",""),if(R2,"&entry.1892971721=San+Jose",""),if(S2,"&entry.1892971721=Sunnyvale","")), "Complete Intake")
I tried to create a ModalDialogue and display a script generated hyperlink in it. I used this approach found in this forum. But this did not open any dialog at all and threw no errors (even after hyperlink was removed.) There was no indication of pop-up blocking. Other parts of my script use Browser.msgBox without any pop-up troubles, but I don't think that will pass a hyperlink.
var htmlOutput = HtmlService
.createHtmlOutput('Click to open and prefill intake interview form.')
.setWidth(250) //optional
.setHeight(50); //optional
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Ready to fill intake interview form:');
Using onFormSubmit() and scripting a copydown after a new row has been inserted. But I have been unable to figure out how to identify which row was inserted into Sheet 1. I see some people using lastRow(), but it isn't always inserted into the last row - typically it goes in the middle somewhere.
Request:
Help getting arrayformula to work in my case.
Or help getting ModalDialog to display a script generated hyperlink.
Or help on how to identify the row the Form submission inserted. Or do I just need to make sure the table remains sorted by TimeStamp and then I can use lastrow()?
Suggestion for a cleaner approach to get to the same place (generating a prepopulated Form from a row of data in Sheet 1.)
Thank you for illuminating a path forward.
You should consider using ArrayForumlas to automatically copy down the formula to other rows that have a value in the first column.
Put this formular in row 2 of the column that has the Google Form links.
=ARRAYFORMULA(
IF(ISTEXT(A2:A),
HYPERLINK(
CONCATENATE(
"https://docs.google.com/forms/d/e/XXXXXXXXXXXXXXXX/viewform?usp=pp_url&entry.251357138=",C2:C,"&entry.966351469=",D2:D
)),""))
I wrote a tutorial on copying formulas if you need more examples.
It turned out I was able to successfully employ approach 2, the modalDialog. For some reason no dialog was appearing when I first attempted so I didn't know if there was something fundamental wrong with this approach. I tried again and it worked as shown below so I suppose I just had some typos. Adding target="_blank" was helpful so as to open in a new tab.
var htmlOutput = HtmlService
.createHtmlOutput('Click to open and prefill intake interview form.')
.setWidth(250) //optional
.setHeight(50); //optional
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Ready to fill intake interview form:');

Issue with body.replaceText() in Google Docs

I am populating a Google Doc template based on a Google Form submission. Upon submit, the program copies the template Google Doc, captures the first item from the Google Form which is always the person's name (because this is a required field), and then replaces {{Name}} in the new file with the entered name using:
var name = itemResponses[0].getResponse();
body.replaceText('{{Name}}', name);
That works correctly. But then I iterate through the rest of the item response and not all the items are required, so I use a lookup table in a Google sheet. The loop takes the item id in the item response and then looks up the text that the response will replace. Then the program does:
var textToReplace //this value is from column B in the Google Sheet lookup table
var newText //this value is the entered response from the Google Form
body.replaceText(textToReplace, newText);
When I do this, I am getting a "Exception: Invalid argument: searchPattern" error. Why are these two body.replaceText() functions different? They are both finding a variable with in double brackets in the Google doc, but it only works in one case.
And to be clear, this was previously working correctly for the last couple of months and only recently started to not work (maybe Google changed something??). My hypothesis is that it has to do with a regex pattern in the first parameter of replaceText.
The "searchPattern" error is a good clue, in certain circumstances, it tells us the value of "textTopReplace" is not a valid search pattern. Since the code hasn't changed, the lookup table in your spreadsheet, or the fields on the form probably have.
One of your lookups is returning a value that isn't a valid search pattern. Perhaps it is returning Null, or an empty string?
You can get more information by using console.log to log debug info to the stackdriver log interface provided by Google, like so:
console.log('text to replace: "'+textToReplace+'"'); //this value is from column B in the Google Sheet lookup table
console.log('value: "'+newText+'"'); //this value is the entered response from the Google Form
body.replaceText(textToReplace, newText);
Then, to view the logs, select "stackdriver logging" from the View menu.

Is there a way to have google form responses to record in sheets depending on what section of the form is filled out?

I made a form with multiple conditional paths and my response sheet is ungodly I could really use some help.
The way I set up the form has a total of 19 sections
Location Dropdown (we have 3)> Machine dropdown (a total of 15)> A Machine Specific measurement section and Submit.
I split the Measurements sections by machine because, I was hoping I could have each section record numbers into separate sheets. This way I could keep each Machine's data on its own google sheet.
So logically I am trying to get MachineX measurements to record sheet X but, Get Machine Y to record In Sheet Y. Is what I'm looking for feasible/ even possible?
I know I can try and organize the form responses into the sheets manually, but I am trying my best to avoid that, cause its gonna take a lot of time out of the week.
Maybe there is a way to organize the form response sheet to filter the data into their appropriate sheets.
I am out of my depth and could really use some help.
You can set up a linked Sheet to the Form and then an Apps Script function that gets the data and prints it into the Sheet.
First you have to create an Installable trigger: On form submit so every time the form is submitted the Sheet will be updated
Once you have your trigger set up, you have to write the function.
I would suggest you to create variables for each sheet you want your data in.
You can select the sheet by name like: sheet.getSheetByName("MachineX")
I recommend setting up the questions in an order that allows you to say:
From question 1 to 6 -> go to "MachineX"
From question 7 to 19 -> go to "MachineY"
Now you have to iterate over the answers and get the latest responses:
- If you just want the latest response to the form you could use something like:
for (var i = formResponses.length - 1; i < formResponses.length; i++)

Strange results returning from Response.getId() in GAS

I am working with a script to pull the response ID from a form submission so that when users edit their response, I can match the edit to the initial response. My script creates a .pdf of the contents of each form submitted, but when users edit responses, it creates a new form containing only the edited data, without linking it to the initial response.
The edit response contains a timestamp and the edited information, and the timestamp is used with Response.getId(timestamp), iirc, and returns the ID of the form submission. However, I am sometimes getting a very strange return, and I don't know where it comes from. The response is much shorter than a typical response ID (10-12 alphanumeric instead of 30+). I will try to comeback and edit this question with the code, but I'm on a different log in at the moment, so I'll have to swap over and copy code and come back. Running unit tests hasn't really helped, as I get the expected result most of the time. It's just an occasional hiccup, but I have to find where the incorrect information is coming from.
function getResponseId(timestamp){
var form = FormApp.openById('<formID>');
if(typeof(timestamp) != 'number'){
timestamp = new Date(timestamp);
}
var responses = form.getResponses(timestamp);
var entryId = responses[0].getId();
return entryId;
}
That's is. I suppose the if(typeof... may be throwing things off if it's passing in a Date string instead of the actual timestamp of entry, but I don't think so. I'll double check it and debug it in the meantime, and if I answer my own question, I'll come back and fix it.
Hmm. Sounds like the same behavior. What I decided to do instead was to match the timestamps that are recorded, but you have to grab the stamps in the 3rd line of code, as the old stamp is overwritten quickly. I just subtracted oldTime from newTime, left a 5 sec window to match them, and that worked. I just haven't had a chance to post it yet, as I just got it working for new submissions, edits, and failed writes about an hour ago.