I'm trying to multiply the event value of a certain Event Action (A) by ($x.xx) and the event value of a different type of Event Action (B) by a different amount ($x.xx).
Ex: Event Action A * 1.37
Ex: Event Action B * 2.22
I have Google Tag Manager firing events per click, where the Action is the type of click and Label is the URL. In Google Data Studio, I understand I can use a Calculated Field to multiply [Event Value] by [x amount]. But I'm not sure how to separate this based on the event action.
Is it also possible to do this in one field? Such as:
If (Event Action contains "A" then multiply [event value] by [x], else if Event Action contains "B" then multiply [event value] by [y])
Thanks!
I don't think you can do it in one step in one field but if you do one field (multiplier) as
CASE
WHEN REGEXP_MATCH("Event Action","A") THEN [yourmultipliervalueX]
WHEN REGEXP_MATCH("Event Action","B") THEN [yourmultipliervalueY]
ELSE 0
END
And then a second field as
multiplier*[event value]
EDIT: To take into account [event value] being an aggregate
AVG(CASE
WHEN REGEXP_MATCH("Event Action","A") THEN [yourmultipliervalueX]
WHEN REGEXP_MATCH("Event Action","B") THEN [yourmultipliervalueY]
ELSE 0
END)
Related
I've been trying to update a randomly selected row in my Sqlite database using Flask and the Flask-Sqlalchemy. I have just a few rows in the database with columns called "word", "yes", and "no", where word is a string and yes and no are integers. There are two buttons on the "vote" view, yes and no. When a button is pressed, the appropriate code executes, should increment the yes or no column, and the view is updated with a new random word from the Word table.
#app.route("/vote", methods=["GET", "POST"])
def vote():
#Get random row from database
query = db.session.query(Word)
rowCount = int(query.count())
row = query.offset(int(rowCount*random.random())).first()
#POST
# If "yes" button is pressed, increment yes column in database
if request.method == "POST":
if request.form.get("yes"):
row.yes += 1
db.session.commit()
return render_template("vote.html", row=row)
# otherwise increment no column
elif request.form.get("no"):
row.no += 1
db.session.commit()
return redirect(url_for("vote"))
#GET
# on get request, render vote.html
return render_template("vote.html", row=row)
This code is working, but the yes and no columns are only updated when the view comes back around to the random word the next time. If I close the browser right after clicking a button, the database is not incremented. I think this has something to do with db.session.commit(), or something about the session. It seems like:
row.yes += 1
is saved in the session object, but only committed when that database row is queried the next time. This code DID work when I replaced the query at the top of the method with:
row = Word.query.get(4)
which returns the row with id of 4. With this query, the yes or no column are updated immediately.
Any thoughts?
Thanks
Thanks all. I figured out the problem. The database incrementing was actually working fine, but I wasn't incrementing the correct rows. The problem was that I generated a random row from the database on each call of the vote() method, which meant that I got a random value for the GET request, and a different random value for the POST request, and ended up incrementing that different random value in the POST request.
I separated the logic out into two methods for the "/vote" route, getWord() and vote(), and created a randRow() method for the row generation. I needed to store the random row that gets generated when getWord() is called, so I used session variables so I could access the random row from the vote() method. It's a bit verbose, but seems to work.
Anyone have a better idea about how to achieve this?
#app.route('/vote', methods=["GET"])
def getWord():
wordObj = randRow()
session['word'] = wordObj.word
session['yesVotes'] = wordObj.yes
session['noVotes'] = wordObj.no
return render_template("vote.html", word=session['word'], yesVotes=session['yesVotes'], noVotes=session['noVotes'])
#app.route('/vote', methods=["POST"])
def vote():
# store session 'word' in word variable
# look up word in database and store object in wordObj
word = session['word']
wordObj = Word.query.filter_by(word=word).first()
# check button press on vote view, increment yes or no column
# depending on which button was pressed
if request.form.get("yes"):
wordObj.yes = wordObj.yes + 1
elif request.form.get("no"):
wordObj.no = wordObj.no + 1
db.session.commit()
return redirect(url_for("getWord"))
###### HELPERS ######
# returns a random row from the database
def randRow():
rowId = Word.query.order_by(func.random()).first().id
row = Word.query.get(rowId)
return row
I think you need to add the update into the session before the commit, using code like this:
[...]
row.yes += 1
db.session.add(row)
db.session.commit()
[...]
That's the pattern that I use for a basic update in Flask-SQLAlchemy.
I have a dexterity content type (my.product.myobject) that uses the IEventBasic behavior (implemented in the xml file with other behaviors) and I'm trying to make the end field be set within the same week of the start field. I attempt to correct the end date in an IObjectAddedEvent (zope.lifecycleevent.interfaces.IObjectAddedEvent).
I first get the week range from the start field:
def getWeekRangeFromDate(a_date,offset=1):
start = (a_date - timedelta(days=(a_date.weekday() + offset) % 7)).replace(hour=0,minute=0)
end = (start + timedelta(days=6)).replace(hour=23,minute=59)
return {'start':start,
'end':end,
}
def myObjectAdded(myObject, event):
week_range = getWeekRangeFromDate(myObject.start)
if myObject.end > week_range['end']:
myObject.end = week_range['end']
I have the end field printed in the browserview and I use IEventAccessor to extract the end date from the myObject:
class View(BrowserView):
def __init__(self,context,request):
...
self.context = self.context
def getFormattedEnd(self):
if self.context.whole_day == False:
return IEventAccessor(self.context).end.strftime('%m/%d %I:%M %p')
...
When it doesn't need to be programmatically corrected, the end field displays correctly, but when it does, it appears 5 hours off.
In my myObjectAdded event, I tried:
if myObject.end > week_range['end']:
myObject.end = week_range['end'] - timedelta(hours = IEventAccessor(myObject).end.offset().total_seconds()/3600)
This does appear right actually, but when I go to the edit form and change the start field, the end field ends up changing itself seemingly random. Changing the starting hour field to 16 changed the end's month about two weeks ahead.
How can I set it without it acting up? Am I misundertanding how to use IEventBasic?
Edit: I'm coming across something really interesting. In the edit form, the Start End Validator is failing.
Event Starts - 25/November/2016 9:00
Event Ends - 25/Novermber/2016 20:00
I click submit and the status message says End date must be after the start date.
Edit: The version of Plone I am using is 4.3.
I've been searching for similar solutions out there but am coming up short so far. Here is what I want to accomplish:
I need to come up with a basic solution to sync inventory quantities at the end of each day. We take physical counts of inventory sold throughout the day but need something to log these changes and share between users. I would like to utilize two buttons (click one to subtract amount of items sold at the end of the day and click one button to add newly received inventory).
This is how my sheet is set up:
Col A: Product Tag
Col B: Product sku
Col C: Amount Sold Today
Col D: Total Inventory Quantity
Col E: Add New Inventory
Column D will be pre-populated with initial inventory counts. At the end of each day, I would like to go down my product list and fill in the amount of each item sold that day in Column C. Once Column C is fully populated, I would like to click the "subtract" button and have Column C subtracted from Column D.
On the other side, once we receive new stock of an item I would like to enter these counts into Column E. Once this column is fully populated, I would like to click the "Add" button and have Column E added to Column D. Ideally once the add or subtract function has been completed, columns C or E will be cleared and ready for the next days entry.
I already have designed my buttons, I just need help coming up with the scripts to accomplish this.
You can use Google Apps Script for this.
If you are unfamiliar, in your particular spreadsheet, go to Tools → Script Editor and then select the Blank Project option.
Then you can write functions like this to achieve what you want!
function subtractSold() {
var sheet = SpreadsheetApp.getActiveSheet();
var c1 = sheet.getRange("C2");
var c2 = sheet.getRange("D2");
while (!c1.isBlank() && !c2.isBlank()){
c2.setValue(c2.getValue() - c1.getValue());
c1.clear();
c1 = c1.offset(1, 0);
c2 = c2.offset(1, 0);
}
}
Basically what the function does is:
Get a reference to the active spreadsheet
Get references to the cells C2 and D2, for the first row of data.
Use a while loop to repeated go through the rows. Terminate when either cell is empty.
In the loop, we get the appropriate values, subtract and set the value back into the cell. Then we clear the cell in column C. We then move both cell references down by one row (the offset method returns a reference to the original cell, but offset by row, column).
Then assign the script to the button image by entering the name of the function (subtractSold in this case) in the "Assign script" option for the button.
I have made an example sheet here (go to File → Make a Copy to try the scripts and see the code): https://docs.google.com/spreadsheets/d/1qIJdTvG0d7ttWAUEov23HY5aLhq5wgv9Tdzk531yhfU/edit?usp=sharing
A bit faster
If you try the sheet above you can see it processes one row at a time, which might get pretty slow when you have a lot of rows. It is probably faster to process the entire column in bulk, but it may be a bit more complicated to understand:
function subtractSoldBulk() {
var sheet = SpreadsheetApp.getActiveSheet();
var maxRows = sheet.getMaxRows();
var soldRange = sheet.getRange(2, 3, maxRows); // row, column, number of rows
var totalRange = sheet.getRange(2, 4, maxRows);
var soldValues = soldRange.getValues();
var totalValues = totalRange.getValues();
for (var row in soldValues) {
var soldCellData = soldValues[row][0];
var totalCellData = totalValues[row][0];
if (soldCellData != "" && totalCellData != "") {
totalValues[row][0] = totalCellData - soldCellData;
soldValues[row][0] = "";
}
}
soldRange.setValues(soldValues);
totalRange.setValues(totalValues);
}
The difference here is that instead of getting one cell, we get one range of cells. The getValues() method then gives us a 2D array of the data in that range. We do the calculations on the two arrays, update the data in the arrays, and then set the values of the ranges based on the array data.
You can find documentation for the methods used above from Google's documentation: https://developers.google.com/apps-script/reference/spreadsheet/sheet
I'm need to count user input length in simple form.
I'm tried this:
Template.index.created ->
#symbols = new ReactiveVar
#symbols.set($('#whatsnew').val().length)
return
And in template(jade):
//index.jade
.small-9.columns
input(type='text', placeholder='whats new?', name='whatsnew', id='whatsnew')
...
#{sybmols}
...
But this not working
I'm need to count characters of user input. How to make it?
Your code isn't reactive. There's no reason for your ReactiveVar to rerun. You can try adding an event for every onkeyup event in your input field. When this happens you can get the length of the entered text and set it in your symbols ReactiveVar.
Then every reatice context dependent on symbols will rerun.
I am working on a report in AX 2009. I want to filter data of InventSiteID on the basis of ExpDate.
I have 2 datasource in the query which is attached to report. Both the data source are same InventExpired. I have to show 4 fields in dialog i.e. SiteID, Exp Date for datasource1 and same for datasource 2 and then filter it out.
In your report, you can use
SysQuery::findOrCreateRange(this.queryRun().query().dataSourceNo(1),
fieldNum(InventExpired, ExpDate)
).value(SysQuery::value(yourFilterDate));
That will filter the first datasource with the date entered.
If you need to filter by dates greater than or less than the filter date, you can use
SysQuery::findOrCreateRange(...).value('>' + SysQuery::value(yourFilterDate));
or
SysQuery::findOrCreateRange(...).value('<' + SysQuery::value(yourFilterDate));
Do you know how to add the fields to the dialog?
If you don't, you should override the dialog() method, and in the dialog() method, after the call to super(), you should use:
Dialog d = ret;
expDateField = d.addField(typeid(yourDateEDT), "Expiry Date");
To get the values from the fields and use them in your report, you should use
expDateField.value()
I haven't tested this, but I've done similar things on numerous occasions so I'm fairly confident this will work. Let me know if you have any problems with this
If you want to specify a range here is how I accomplished it. Hope this helps somebody...
Method1:
qbds3 = qry.dataSourceTable(tableNum(DMxVehicleTable));
SysQuery::findOrCreateRange(qbds, fieldNum(DMxVehicleTable,VehicleMSRPRetails)).value(strFmt('(VehicleMSRPRetails >= %1) && (VehicleMSRPRetails <= %2)', queryValue(VehicleMinPrice), queryValue(VehicleMaxPrice)));
Method2:
qbds4 = qry.dataSourceTable(tableNum(DMxSysYearTable));
SysQuery::findOrCreateRange(qbds4, fieldNum(DMxSysYearTable,Year), 1, 1).value('>' + SysQuery::value(VehicleModelYearStart));
qbds4.addRange(fieldNum(DMxSysYearTable, Year)).value(strFmt('< %1', queryValue(VehicleModelYearEnd)));