How can is set Target CPA for adGroup via setCpa() of adgroup bidding? - google-ads-script

By default adGroup is showing Target CPA value $80 which is Target CPA of its respective campaign. Now I want to manually set Target CPA of specific adGroups having CPC greater than 0 via script. Below is my code.
var adGroupSelector = AdsApp
.adGroups()
.withCondition("ad_group.status = ENABLED")
.forDateRange(date_range);
while (adGroupIterator.hasNext()) {
var adGroup = adGroupIterator.next();
var tcpa = adGroup.bidding().getCpa(); // getting $80 here
var cost_value = adGroup.getStatsFor(date_range).getCost();
var conversions_value = adGroup.getStatsFor(date_range).getConversions();
var cpc_value = parseFloat(cost_value/conversions_value);
if(Number.isFinite(cpc_value)){
var new_target_cpa = Math.floor((cpc_value+tcpa)/2); //For example i get $126
adGroup.bidding().setCpa(Math.floor((cpc_value+tcpa)/2)); // setting $126 to this adgroup via setCpa() from adgroup bidding
var get_target_cpa = adGroup.bidding().getCpa(); // again getting the target with getCpa() to check whether it is set or not. Here i am getting value of get_target_cpa as $126 but it is not reflected in adGroup UI.
}
}
Is my method to set Target CPA to adgroup is correct ? Why it the Target CPA set via setCpa() is not getting reflected in AdGroup UI ?

Related

Send an invitation to attendees' email through Spreadsheet and Google Calendar API

First of all, I don't have any coding knowledge/background, so I don't know if it is appropriate to ask for advices here, and also this is my first post here. I usually look for some codes on the internet that could find my needs, update it to fit my data and done.
So, right now I am setting a shared platform in my organization to allow people to register as either a presenter or participant of sharing sessions.
The session are all pre-created, and they have to pick in the list. After registering, the data are available in a spreadsheet and I have the code to add these registered person for the sessions.
However my issue is, they are added as guests of the event, but don't receive an invitation for this event. Here is the script:
function Presenterscalendar() {
var cal,i,iCalId,row,sheet,thisEvent,presenter,title,email;
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Presenters");
var dataRange = sheet.getRange("A2:G1000");
var data = dataRange.getValues();
cal = CalendarApp.getDefaultCalendar();
for (i in data) {
row = data[i];
presenter = row[1];
title = row[3];
tstart = row[2];
iCalId = row[4];
email = row[6];
thisEvent = cal.getEventSeriesById(iCalId);
if (thisEvent) {
thisEvent.setTitle(title);
thisEvent.setDescription('A session presented by '+presenter);
thisEvent.addGuest(email)
}
}
}
I looked for other script in order to send the invitations to all attendees of each session in the calendar:
function sendInvite(calendarId, eventId, email) {
var calendarId = 'test#test.com';
var vss = SpreadsheetApp.getActive();
var vS = vss.getSheetByName('Presenters');
var dataRange = vS.getRange("A2:H1000");
var data = dataRange.getValues();
for (i in data) {
row = data[i];
presenter = row[1];
title = row[3];
tstart = row[1];
iCalId = row[4];
mail = row[6];
var eventId = vS.getRange("e2:e1000").getValue();
var eid = eventId.split("#")[0]; // Added;
var event = Calendar.Events.get(calendarId, eid);
var attendees = event.attendees;
if(event.attendees) {
event.attendees.push({
email: email
});
} else {
event.attendees = new Array({email:email});
}
event = Calendar.Events.patch(event, calendarId, eid, {
sendupdates: "all"
});
}
}
This works if I just put a static email for ex ({email:"test#google.com"}), but when kept as is it says "missing attendees mail". Eventually, what I would like to is either:
The script to get all the events in the calendar and send the notifications to new attendees registered (update)
The script to get the data from the spreadsheet (where I have in 1 column the email of the attendee -1 row = 1 attendee-) and send the notification to new attendees
I did allow Calendar API for the script and the Google Cloud platform already.
I wonder if you could help me on this, I tried to replicate what I found on the internet, but my limited knowledge on coding doesn't allow me to go further...
Thanks a lot !
The optional query parameters for an event patch are case sensitive
Thus, you need to modify
sendupdates: "all"
to
sendUpdates: "all"

Planning dashboard for sales in google sheets

Sheet for testing:
https://docs.google.com/spreadsheets/d/1t_hjD6Yx7iv_a9tcgETf82cZbl2cdV8vd0PuTQXZP6Y/edit?usp=sharing
Objective:
I'm trying to create an automated planning sheet for one of my clients. The idea is for the sheet is to:
Take manual input of the total sales goal in cell B1
Return cost, leads, and sales broken down by advertising platform
Current Sheet Setup:
Cell B1 is the only manual input in the sheet. For the table between A4:G10, the columns highlighted in green are fixed values. The cost column B4:B10 and the sales column G4:G10 are calculated fields. The goal is to calculate the values of the leads column such that the total of the sales column in cell G10 is equal to the sales target in cell B1.
Constraints of calculating the leads from each channel:
Each advertising platform has a maximum number of leads that it can generate shown in column E4:E10. So, in this test sheet, the maximum number of leads that can be generated by Facebook is 500 and by Bing is 1000 and so on.
The advertising platforms are listed in order of increasing cost per lead shown in column C4:C10. So the channel on top is the cheapest, while the one at the bottom is the most expensive. The goal is to maximize leads from the cheapest channel first and then move on to the next channel until the sales goal is achieved. In the test sheet, we need to get 500 leads from Facebook first, then 500 leads from Google Ads, then 1000 leads from Bing, and so on till the total of sales in cell G10 is equal to the sales target in cell B1.
I'm kind of lost on this and I would appreciate any help that you can share with me!
I figured out how to do what I needed. I added a button that would trigger the script function calculate() to do the calculation. Its a very basic script and I'll post another question to figure out if it can be optimized - my actual sheet has a dynamic number of advertising platforms and I still need the script to adapt to that.
Script:
function calculate() {
// Get the planning sheet
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet = spreadsheet.getSheetByName('Planner')
// Get contract target as the input
var target = sheet.getRange('B1').getValue()
// Clear the pin cards list
sheet.getRange('D11:D15').clearContent()
// Set the value of the first channel
firstChannelValue(sheet, target)
// Set the value of the second channel
secondChannelValue(sheet, target)
// Set the value of the third channel
thirdChannelValue(sheet, target)
// Set the value of the fourth channel
fourthChannelValue(sheet, target)
// Set the value of the fifth channel
fifthChannelValue(sheet, target)
}
function firstChannelValue(sheet, target) {
// Max number of pin cards
var pcLimit = sheet.getRange('E11').getValue()
// Conversion rate
var convRate = sheet.getRange('F11').getValue()
// Cell that needs to be filled
var pinCard = sheet.getRange('D11')
// Max possible value
var maxValue = pcLimit*convRate
// Set value of cell
if (maxValue <= target) {
pinCard.setValue(pcLimit)
}
else {
pinCard.setValue(target/convRate)
}
}
function secondChannelValue(sheet, target) {
// Max number of pin cards
var pcLimit = sheet.getRange('E12').getValue()
// Conversion rate
var convRate = sheet.getRange('F12').getValue()
// Cell that needs to be filled
var pinCard = sheet.getRange('D12')
// Max possible value
var maxValue = (pcLimit*convRate)
// Value of first channel contracts
var firstChannel = sheet.getRange('G11').getValue()
// Revised target
var revisedTarget = target - firstChannel
// Set value of cell
if (maxValue <= revisedTarget) {
pinCard.setValue(pcLimit)
}
else {
pinCard.setValue(revisedTarget/convRate)
}
}
function thirdChannelValue(sheet, target) {
// Max number of pin cards
var pcLimit = sheet.getRange('E13').getValue()
// Conversion rate
var convRate = sheet.getRange('F13').getValue()
// Cell that needs to be filled
var pinCard = sheet.getRange('D13')
// Max possible value
var maxValue = (pcLimit*convRate)
// Value of previous channel contracts
var firstChannel = sheet.getRange('G11').getValue()
var secondChannel = sheet.getRange('G12').getValue()
// Revised target
var revisedTarget = target - firstChannel - secondChannel
// Set value of cell
if (maxValue <= revisedTarget) {
pinCard.setValue(pcLimit)
}
else {
pinCard.setValue(revisedTarget/convRate)
}
}
function fourthChannelValue(sheet, target) {
// Max number of pin cards
var pcLimit = sheet.getRange('E14').getValue()
// Conversion rate
var convRate = sheet.getRange('F14').getValue()
// Cell that needs to be filled
var pinCard = sheet.getRange('D14')
// Max possible value
var maxValue = (pcLimit*convRate)
// Value of previous channel contracts
var firstChannel = sheet.getRange('G11').getValue()
var secondChannel = sheet.getRange('G12').getValue()
var thirdChannel = sheet.getRange('G13').getValue()
// Revised target
var revisedTarget = target - firstChannel - secondChannel - thirdChannel
// Set value of cell
if (maxValue <= revisedTarget) {
pinCard.setValue(pcLimit)
}
else {
pinCard.setValue(revisedTarget/convRate)
}
}
function fifthChannelValue(sheet, target) {
// Max number of pin cards
var pcLimit = sheet.getRange('E15').getValue()
// Conversion rate
var convRate = sheet.getRange('F15').getValue()
// Cell that needs to be filled
var pinCard = sheet.getRange('D15')
// Max possible value
var maxValue = (pcLimit*convRate)
// Value of previous channel contracts
var firstChannel = sheet.getRange('G11').getValue()
var secondChannel = sheet.getRange('G12').getValue()
var thirdChannel = sheet.getRange('G13').getValue()
var fourthChannel = sheet.getRange('G14').getValue()
// Revised target
var revisedTarget = target - firstChannel - secondChannel - thirdChannel - fourthChannel
// Set value of cell
if (maxValue <= revisedTarget) {
pinCard.setValue(pcLimit)
}
else {
pinCard.setValue(revisedTarget/convRate)
}
}
From what I understand reading your question is you just need help with how to calculate the leads, which is column D5:D9. And you want the total sales to be equal of the value in the cell B1. Apologies if I misunderstood your question.
Here's what you can try if I got your question right-
salesLimit = int(input())
#These are the values from the column E
leadLimit = [500,500,1000,1000,1000]
for x in range(0,len(leadLimit)):
#Multiplying with 3/100 because it's the conv rate found in column F
if(leadLimit[x]*3/100)<salesLimit:
salesLimit -= leadLimit[x]*3/100
print("D"+str(5+x)," = ",leadLimit[x]*3/100)
else:
print("D"+str(5+x)," = ",salesLimit)
salesLimit = 0
Sample input for B1:
100
Output for the given input:
D5 = 15.0
D6 = 15.0
D7 = 30.0
D8 = 30.0
D9 = 10.0
Since the lead limit is already sorted in your sheet, you'll get your expected answer by doing this.

Downcast from Any to Specific type

I have firestore DB "sales", which has one column called saleapproveddate. There are 2 levels of people, one who logs sale and other approves the sale logs. While logging sale, I save the saleapproveddate as NSNull() (which saves as nil in firestore DB field). Approver can update the saleapproveddate as TimeStamp, but if the approver never approves the sale log, it remains as nil in firestore DB field. So it can have either nil or TimeStamp type.
I have model Sales
class Sale {
var saleapprovedate : Any?
}
When I load the data from firestore, I tried to downcast the saleapprovedate as Any
let approvedDate = document[SaleProperties.paidDate.rawValue] as Any
But the real challenge is, saleapprovedate can have either nil or Timestamp. How do I check for type condition, convert to specific type and display in label?
Below is what I tried:
While loading data:
sale.saleapprovedate = document[SaleProperties.saleapprovedate.rawValue] as Any
while displaying data:
let saleItem = sales[indexPath.row]
let paidDate = saleItem.saleapprovedate
if paidDate == nil {
cell.paidDateLabelContainer.text = "Yet to pay"
cell.paidStatusImageView.isHidden = true
}
else {
let paidDateTimeStamp = saleItem.saleapprovedate as! Timestamp
let convertedPaidDate = self.convertTimestampToDate(timeStamp: paidDateTimeStamp)
cell.paidDateLabelContainer.text = convertDateToString(date: convertedPaidDate)
cell.paidStatusImageView.isHidden = false
}
But the above code is not updating the cell label properly. I have two data, one has saleapprovedate as Timestamp and other as nil. Both the cell label is displaying as "Yet to pay". What is wrong?
Modal :
var incentivepaiddate : Any?
Array :
var sales : [Sale] = [Sale]()
Loading data from firestore :
for document in querySnapshot!.documents {
let sale = Sale()
sale.incentivepaiddate = document[SaleProperties.incentivepaiddate.rawValue]
self.sales.append(sale)
}
Checking for nil, downcasting to a specific type and display data in cell
let saleItem = sales[indexPath.row]
let paidDate = saleItem.incentivepaiddate
if let paid = paidDate {
let paidDateTimeStamp = paid as? Timestamp
let convertedPaidDate = self.convertTimestampToDate(timeStamp: paidDateTimeStamp!)
cell.paidDateLabelContainer.text = convertDateToString(date: convertedPaidDate)
}
else {
cell.paidDateLabelContainer.text = "Yet to pay"
cell.paidStatusImageView.isHidden = true
}
Hope this helps someone!

what is effective approach to set default values using NSUserDefaults.standardUserDefaults().registerDefaults(Dictionary<String, AnyObject>)?

I have 4 user settings in the app which are independent of each other. I want to check value for each setting using appropriate method of NSUserDefaults.standardUserDefaults() for each key and if any of the key is not found in user defaults then register the default predefined value.
I do not want to call NSUserDefaults.standardUserDefaults.registerDefaults(Dictionary<String, AnyObject>) every time with app launch , so i am not registering defaults using this method in AppDelegate.Swift- didFinishLaunchingWithOptions with every app launch but i call a method in root view controller's viewDidLoad() which runs a custom logic to check each user settings. if all 4 settings already saved by user no call toregisterDefaults() at all and if any one of settings not saved, call registerDefaults().
Can anyone suggest is there any effective way of doing this or comment on the way i am trying to achieve it ? Will Apple review team approve my logic?
I want to get rid of too many IF's. Below is the logic i have written :-
let userDefaults = NSUserDefaults.standardUserDefaults() as NSUserDefaults
rate = AVSpeechUtteranceDefaultSpeechRate
speech = true
language = AVSpeechSynthesisVoice.currentLanguageCode()
defaultLanguageName = NSLocale.currentLocale().displayNameForKey(NSLocaleIdentifier, value: language)
bttnEffect = "Pop"
var defaultSpeechSettings: Dictionary<String, AnyObject> = ["speechRate": rate, "speech": speech, "languageCode": language, "defLanguageLabel": defaultLanguageName, "gender": bttnEffect ]
var isSpeechRateSettingLoaded = false
var isSpeechSettingLoaded = false
var isLangSettingLoaded = false
var isBttnEffectSettingLoaded = false
if let theRate: Float = userDefaults.valueForKey("speechRate") as? Float {
rate = theRate
defaultSpeechSettings.removeValueForKey("speechRate")
isSpeechRateSettingLoaded = true
}
if let toggleVal: Bool = userDefaults.valueForKey("speech") as? Bool {
speech = toggleVal
defaultSpeechSettings.removeValueForKey("speech")
isSpeechSettingLoaded = true
}
if let langCode = userDefaults.stringForKey("languageCode") {
language = langCode
defaultSpeechSettings.removeValueForKey("languageCode")
defaultSpeechSettings.removeValueForKey("defLanguageLabel")
isLangSettingLoaded = true
}
if let effectStyle = userDefaults.stringForKey("bttnEffect") {
bttnEffect = effectStyle
defaultSpeechSettings.removeValueForKey("bttnEffect")
isBttnEffectSettingLoaded = true
}
if !(isSpeechRateSettingLoaded && isSpeechSettingLoaded && isLangSettingLoaded && isBttnEffectSettingLoaded) {
NSUserDefaults.standardUserDefaults().registerDefaults(defaultSpeechSettings)
}
Apple's review team doesn't care if you write sloppy code.
Note Ken's comment about how registerDefaults() only affects return values if no value is set for the given key.
Aside from that, however, extensions are a nice way to tame NSUserDefaults.
extension NSUserDefaults {
private static let speechRateKey = "speechRate"
var speechRate: Float {
get {
return valueForKey(NSUserDefaults.speechRateKey) as? Float ?? AVSpeechUtteranceDefaultSpeechRate
}
set {
setObject(newValue, forKey: NSUserDefaults.speechRateKey)
synchronize()
}
}
}
// somewhere else:
let speechRate = NSUserDefaults.standardUserDefaults().speechRate
doSomethingWith(speechRate)
NSUserDefaults.standardUserDefaults().speechRate = getNewSpeechRate()

AdWords Countdown Script for AdGroups Error

I'm trying to implement the countdown script from https://developers.google.com/adwords/scripts/docs/tutorials/countdown-sale
The script works for single Ad Group but when trying to Multiple ad groups part of I keep getting following error:
TypeError: Cannot call method "setAdParam" of undefined. (line 9)
My full script is:
// Date to use to find out how many days are remaining.
var END_DATE = new Date('February 24, 2013');
// Change this to the Ad Group you set up with text ads with AdParams.
var AD_GROUP_NAMES = ['AdGroup1', AdGroup2'];
function main() {
var timeLeft = calculateTimeLeftUntil(END_DATE);
var adGroups = getAdGroups(AD_GROUP_NAMES);
while (adGroups.hasNext()) {
var adGroup = adGroups.next();
var keywords = adGroup.keywords().get();
// We want to update {param1} to use our calculated days and {param2} for hours.
keywords.setAdParam(1, timeLeft['days']); // HERE COMES THE ERROR
keywords.setAdParam(2, timeLeft['hours']);
}
}
var DAY_IN_MILLISECONDS = 1000*60*60*24;
function calculateTimeLeftUntil(end) {
var current = new Date();
var timeLeft = {};
var daysFloat = (end - current) / (DAY_IN_MILLISECONDS);
timeLeft['days'] = Math.floor(daysFloat);
timeLeft['hours'] = Math.floor(24 * (daysFloat - timeLeft['days']));
return timeLeft;
}
function getAdGroups(names) {
var predicateValues = "['" + names.join("','") + "']";
Logger.log(predicateValues);
return AdWordsApp.adGroups()
.withCondition('Name IN ' + predicateValues)
.withLimit(names.length)
.get();
}
The issue is that you're trying to set the ad param to a keyword iterator, not individual keywords.
Instead of this
var keywords = adGroup.keywords().get();
// We want to update {param1} to use our calculated days and {param2} for hours.
keywords.setAdParam(1, timeLeft['days']); // HERE COMES THE ERROR
Try this:
var keywords = adGroup.keywords().get();
while (keywords.hasNext()) {
var keyword = keywords.next();
// and now
keyword.setAdParam(...);
}

Resources