I have MCC account which i'm using to administrate couple AdWords accounts.
I wrote Script which checking base budget of each account and then weekly check how many did they spend. Then the script subtracts these values and then every data is saved into Google Drive (spreadsheet).
Main idea behind this script was to track current budget and then warn me when some account have no more money. But then I figured out that actually i do not need to track it because AdWords script already have functions which gives possibility to stop campaign.
So i digged little bit but everything i tried is not working.
Here is extracted function (example) with i using:
function main() {
var Customer = GetAccountData("XXX-XXX-XXXX");
StopCampaigns(Customer);
if(isCampaignRuning(Customer)){
Logger.log("Campaign is runing !");
}else{
Logger.log("Campaign is STOPPED!");
}
}
/*Helper functions */
function isCampaignRuning(account){
MccApp.select(account);
var campaigns = AdWordsApp.campaigns().get();
var IsCampaignRuning = false;
while(campaigns.hasNext()) {
var campaign = campaigns.next();
if(!campaign.isPaused()){
IsCampaignRuning=true;
break;
}
}
return IsCampaignRuning;
}
function StopCampaigns(account){
MccApp.select(account);
var campaigns = AdWordsApp.campaigns().get();
while(campaigns.hasNext()) {
var campaign = campaigns.next();
if(!campaign.isPaused()){
campaign.pause();
}
}
}
function GetAccountData(id){
var childAccounts = MccApp.accounts().withIds([id]).get();
if(!childAccounts.hasNext()){
return false;
}
var childAccount = childAccounts.next();
return childAccount;
}
Here is what's happening in console:
13:08:20.974 Campaign is runing !
In changes tab:
Change for: (Here is campaign name)
New value (if run now): temporarily suspended
type of change: Update > Status
Current value: Active
How can i correctly pause campaign ?
Is there better way to track current budget of accounts ?
For anyone who will look for answer to the same problem.
There was no problem in script itself.
"if run now" - should speak itself. I was using "Preview" to run script.
In that "preview" mode script doesn't change anything in account and campaign.
It just needed to be "run" normally.
Related
I'm attempting to write a Google Script that accomplishes the idea contained in this pseudocode:
access a specific Google tasklist
for each task in that tasklist {
if the task is completed {
perform an operation
}
}
I've run up against a problem -- when my script accesses the specific tasklist, I can only get information for the incomplete tasks, and the completed tasks seem to have disappeared.
The idea seemed easy enough at first. I copied the code from Google's Tasks Service webpage that is supposed to "list the tasks within a given tasklist" (https://developers.google.com/apps-script/advanced/tasks) and added one if statement within the for loop:
function listTasks(taskListId) {
var tasks = Tasks.Tasks.list(taskListId);
if (tasks.items) {
for (var i = 0; i < tasks.items.length; i++) {
var task = tasks.items[i];
Logger.log('Task with title "%s" and ID "%s" was found.',
task.title, task.id);
if (task.status == "completed") {
//perform operation
}
}
} else {
Logger.log('No tasks found.');
}
}
When I checked the logs, however, I noticed that the all the incomplete tasks were listed, but none of my completed tasks were listed. I tried running the script on a tasklist with only completed tasks and the log output was "No tasks found."
Does anyone know how to find completed tasks in a given tasklist? It seems that this should be possible, based on the fact that Zapier performs operations for completed tasks, as described in this other post: How to trigger Google Script when a Google Task is marked "completed"
You need to tell the Task API that you want List Tasks to return the completed tasks as well.
I used PHP, and you have to tell the Google Service that you want 'hidden' tasks. It seems that completed == hidden. If you want deleted then you can also send that parameter.
$optParams = array(
'showHidden' => true,
'showDeleted' => true,
);
$GTresults = $service->tasks->listTasks($tasklist, $optParams);
Edited here:
Added an example of a loop based on completed:
$retrievedTask = $service->tasks->get($tasklist, $taskID);
if($retrievedTask->getStatus() == "completed") {
echo "GT uncompleted", "\n";
}
Just send optional params into function:
var optionalArgs = {
maxResults: 100,
showHidden: true,
showDeleted: true
};
var tasks = Tasks.Tasks.list(taskListId, optionalArgs);
I had same problem.
And I found that I can get completed tasks by the API if I complete the task by old google task UI (https://mail.google.com/tasks/canvas).
How ever I couldn't get those if I complete the task by new gmail UI.
As you pointed out at the comment, this problem may caused by new gmail UI.
I have a Google form where individuals are to enter in their employer preference and then a time for that employer. I currently have a script that is supposed to function where the form is updated to eliminate options after certain thresholds are reached. However, even when using the form with one option, it does not function correctly.
So, I have two questions here:
1) How do I get this type of action to occur in the form without utilizing the provided Google apps formLimiter and Choice Eliminator?
Here is the script code I was using:
function availableSlots()
{
var form = FormApp.openByUrl('https://docs.google.com/forms/d/e/1FAIpQLSdLRI6BmDXdCCygpHMr7o8MtnYLEVdrnumoHJfW-j_uTZCNiA/viewform?usp=sf_link');
var slots = SpreadsheetApp
.getActiveSpreadsheet()
.getRange("Sheet2!A7:C10")
.getValues();
var choice = [];
{
if (slots[s][0] != "" && slots[s][2] > 0) {
choice.push(slots[s][0]);
}
}
var formItems = form.getItems(FormApp.ItemType.LIST);
formItems[0].asListItem().setChoiceValues(choice);
}
2) Is there a way for the code to check for not only if the employer has been met by the max amount of respondents - because of all times being chosen already - and relay a message to the respondent that this employer is booked, but also behave in a way where if one time is taken for one employer, only that time is taken away if that employer was selected?
Extension of my previous post here, I just figured this was more specific and should be it's own post.
Add-ons have restrictions on triggers. One such is that it can only run once an hour. I cannot figure out how to make that work.
Running the below script will produce the error: "attempted to perform an action that is not allowed" when it is run as an add-on. So if the below is not the proper add-on method for a once an hour script, what is, or did I find a bug?
ScriptApp.newTrigger('updateDay').timeBased().everyHours(1).create();
I tried adding the authorization check as Spencer suggested, and outlined in the documentation here. It passes the authentication, but still produces the same error.
function installTrigger(e) {
var addonTitle = 'Lab Scheduler';
var props = PropertiesService.getDocumentProperties();
var authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL);
if (authInfo.getAuthorizationStatus() ==
ScriptApp.AuthorizationStatus.REQUIRED) {
var lastAuthEmailDate = props.getProperty('lastAuthEmailDate');
var today = new Date().toDateString();
if (lastAuthEmailDate != today) {
if (MailApp.getRemainingDailyQuota() > 0) {
var html = HtmlService.createTemplateFromFile('AuthorizationEmail');
html.url = authInfo.getAuthorizationUrl();
html.addonTitle = addonTitle;
var message = html.evaluate();
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),
'Authorization Required',
message.getContent(), {
name: addonTitle,
htmlBody: message.getContent()
}
);
}
props.setProperty('lastAuthEmailDate', today);
}
} else {
// Authorization has been granted, so continue to respond to the trigger.
try{
var as = SpreadsheetApp.getActiveSpreadsheet();
var userTriggers = ScriptApp.getUserTriggers(as);
var userTriggerL = userTriggers.length;
if (userTriggers.length == 0){
ScriptApp.newTrigger('updateDay').timeBased().everyHours(1).create();
}
} catch(err){
catchToString_(err);
} // End try catch
}
}
The issue you are running against is the scope of authorization your Add-on is running in when the trigger gets created or ran. Installed Triggers are run in AuthMode.FULL. You need to test for the current level of authorization before you can run the trigger. You use the ScriptApp.getAutorizationInfo(authMode) to get the status of the authMode the add-on is running in.
https://developers.google.com/apps-script/reference/script/script-app#getAuthorizationInfo(AuthMode)
Here is an example bit of code from the Apps Script documentation:
https://github.com/googlesamples/apps-script-form-notifications-addon/blob/master/Code.gs
var authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL);
// Check if the actions of the trigger require authorizations that have not
// been supplied yet -- if so, warn the active user via email (if possible).
// This check is required when using triggers with add-ons to maintain
// functional triggers.
if (authInfo.getAuthorizationStatus() ==
ScriptApp.AuthorizationStatus.REQUIRED) {
// Re-authorization is required. In this case, the user needs to be alerted
// that they need to reauthorize; the normal trigger action is not
// conducted, since it authorization needs to be provided first. Send at
// most one 'Authorization Required' email a day, to avoid spamming users
// of the add-on.
sendReauthorizationRequest();
} else {
// All required authorizations has been granted, so continue to respond to
// the trigger event.
}
I think you are using the trigger for specific days at specific hour, so in your example you would need to specify the day (e.g. Mondays) and atHour(1) would make the trigger to run every monday at 1.
For specifying how often it should be triggered you would need to write:
ScriptApp.newTrigger('myFunction').timeBased().everyHours(1).create();
I have come to the conclusion that this is a bug or .timebased() triggers are not supported as an add-on, (which I thought they were).
Please star this issue to help get this working again.
https://code.google.com/p/google-apps-script-issues/issues/detail?id=4524&q=.timeBased()%20add-on%20trigger&colspec=Stars%20Opened%20ID%20Type%20Status%20Summary%20Component%20Owner
I have made a simple Google Spreadsheet with some scripting behind to update colours depending on status, set update and creation dates for rows and a few other controls.
It all works when I am editing it with my own user, but now that set spreadsheet is set to public (access via link), anyone else accessing the spreadsheet gets an error you do not have permissions to do this action.
I am using onEdit() triggers and apparently guest users do not have permission to execute them. Do I have to configure something in order for it to work?
thanks
Not a real solution but somme observations:
I made a little script and tested it on the old ad the new spreadsheet type:
function imwatchingus(event) {
Logger.log(JSON.stringify(event));
try{
if(event.value=="faux"){
SpreadsheetApp.getActiveRange().setBackground("red");
}
else if(event.value=="vrai"){
SpreadsheetApp.getActiveRange().setBackground("green");
}
else{
SpreadsheetApp.getActiveRange().setBackground("blue");
}
}
catch(e){}
}
function spyonme(){
var trigs = ScriptApp.getProjectTriggers();
var func = [];
for (var i in trigs){
func.push(trigs[i].getHandlerFunction());
}
if(func.indexOf("imwatchingus")>-1){
return("already enrolled");
}
else{
ScriptApp.newTrigger("imwatchingus").forSpreadsheet(SpreadsheetApp.getActive().getId()).onEdit().create();
return("enrolling you");
}
}
the function imwatchingus is the one that will do the job (it colors the background of the cell in red / green / blue depending on his text).
to have this function working I added a trigger to it. You can do that with the menu or launching the function spyonme.
On the New spreadsheet there is an issue. Only the first cell (A1) will be modified, but you can use this script if you are anonymous.
On the old spreadsheet, the color is applyed on the changed cell, but it's not working in anonymous mode.
As a high school teacher, I record all of my grading in a Google spreadsheet. I have written custom functions within that spreadsheet that are accessed in the spreadsheet. That all works fine.
I also have a simple (but independent) web app written in google apps script that summarizes the grade information for each student that accesses it and returns it in a table. This has operated perfectly for about 8 months. However, students now get a "NaN" error when trying to check their grades. The "NaN" is only returned for cells that use custom functions. By simply opening the source spreadsheet, it fixes the problem temporarily. But soon after closing the spreadsheet the webapp begins returning "NaN" again.
I'm assuming that it has something to do with when/how these cells are recalculated but I can't figure out how to make the cells retain their value while the spreadsheet is closed. Any help would be much appreciated.
With Eric's advice, I implemented the following function (which runs early on in my app):
function refreshSheet(spreadsheet, sheet) {
var dataArrayRange = sheet.getRange(1,1,sheet.getLastRow(),sheet.getLastColumn());
var dataArray = dataArrayRange.getValues(); // necessary to refresh custom functions
var nanFound = true;
while(nanFound) {
for(var i = 0; i < dataArray.length; i++) {
if(dataArray[i].indexOf('#N/A') >= 0) {
nanFound = true;
dataArray = dataArrayRange.getValues();
break;
} // end if
else if(i == dataArray.length - 1) nanFound = false;
} // end for
} // end while
}
It basically keeps refreshing the sheet (using .getValues()) until all of the #N/A's disappear. It works fabulously but does add a small lag.