-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Use currencyConvert
function when calculating WA revenue
#29680
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
rafaeelaudibert marked this conversation as resolved.
Show resolved
Hide resolved
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,18 @@ | ||
import json | ||
import posthoganalytics | ||
|
||
from posthog.hogql import ast | ||
from posthog.hogql.ast import CompareOperationOp | ||
from posthog.hogql.constants import LimitContext | ||
from posthog.hogql_queries.insights.paginators import HogQLHasMorePaginator | ||
from posthog.hogql_queries.query_runner import QueryRunner | ||
from posthog.hogql_queries.utils.revenue import revenue_expression, revenue_events_expr | ||
from posthog.hogql.database.schema.exchange_rate import ( | ||
revenue_expression, | ||
revenue_events_where_expr, | ||
revenue_currency_expression, | ||
) | ||
from posthog.schema import ( | ||
CurrencyCode, | ||
RevenueExampleEventsQuery, | ||
RevenueExampleEventsQueryResponse, | ||
CachedRevenueExampleEventsQueryResponse, | ||
|
@@ -18,13 +24,21 @@ class RevenueExampleEventsQueryRunner(QueryRunner): | |
response: RevenueExampleEventsQueryResponse | ||
cached_response: CachedRevenueExampleEventsQueryResponse | ||
paginator: HogQLHasMorePaginator | ||
do_currency_conversion: bool = False | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.paginator = HogQLHasMorePaginator.from_limit_context( | ||
limit_context=LimitContext.QUERY, limit=self.query.limit if self.query.limit else None | ||
) | ||
|
||
self.do_currency_conversion = posthoganalytics.feature_enabled( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might be easier to just include this with the request and do it as a front end feature flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this will go away soon, so I'd rather keep it here for now. Some places need to do currency conversion, some don't, so this might be easier :) |
||
"web-analytics-revenue-tracking-conversion", | ||
str(self.team.organization_id), | ||
groups={"organization": str(self.team.organization_id)}, | ||
group_properties={"organization": {"id": str(self.team.organization_id)}}, | ||
) | ||
|
||
def to_query(self) -> ast.SelectQuery: | ||
tracking_config = self.query.revenueTrackingConfig | ||
|
||
|
@@ -40,7 +54,14 @@ def to_query(self) -> ast.SelectQuery: | |
], | ||
), | ||
ast.Field(chain=["event"]), | ||
ast.Alias(alias="revenue", expr=revenue_expression(tracking_config)), | ||
ast.Alias( | ||
alias="original_revenue", expr=revenue_expression(tracking_config, do_currency_conversion=False) | ||
), | ||
ast.Alias(alias="revenue", expr=revenue_expression(tracking_config, self.do_currency_conversion)), | ||
ast.Alias(alias="original_currency", expr=revenue_currency_expression(tracking_config)), | ||
ast.Alias( | ||
alias="currency", expr=ast.Constant(value=(tracking_config.baseCurrency or CurrencyCode.USD).value) | ||
), | ||
ast.Call( | ||
name="tuple", | ||
args=[ | ||
|
@@ -56,7 +77,7 @@ def to_query(self) -> ast.SelectQuery: | |
select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), | ||
where=ast.And( | ||
exprs=[ | ||
revenue_events_expr(tracking_config), | ||
revenue_events_where_expr(tracking_config), | ||
ast.CompareOperation( | ||
op=CompareOperationOp.NotEq, | ||
left=ast.Field(chain=["revenue"]), # refers to the Alias above | ||
|
@@ -88,14 +109,17 @@ def calculate(self): | |
}, | ||
row[1], | ||
row[2], | ||
{ | ||
"id": row[3][0], | ||
"created_at": row[3][1], | ||
"distinct_id": row[3][2], | ||
"properties": json.loads(row[3][3]), | ||
}, | ||
row[3], | ||
row[4], | ||
row[5], | ||
{ | ||
"id": row[6][0], | ||
"created_at": row[6][1], | ||
"distinct_id": row[6][2], | ||
"properties": json.loads(row[6][3]), | ||
}, | ||
row[7], | ||
row[8], | ||
) | ||
for row in response.results | ||
] | ||
|
@@ -104,7 +128,10 @@ def calculate(self): | |
columns=[ | ||
"*", | ||
"event", | ||
"original_revenue", | ||
"revenue", | ||
"original_revenue_currency", | ||
"revenue_currency", | ||
"person", | ||
"session_id", | ||
"timestamp", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We have this fallback in two places here, it is not much yet, but I wonder if it will happen more. What I would usually do is create a
@property
to centralize the fallback handler, I see there are places in the codebase where we do that but I don't see it being done onposthog/models/schema.py
so maybe you'll know how to approach this if you think it's valid :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome question. There's also a slightly better way where we make this non-optional, and add a
@default
to our pydantic models and it will handle that for us. I'm considering changing that, I'm checking with @robbie-c in a separate PR if that's the best way to do it actually - it'll also help with the new config I'm adding toRevenueConfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah that's cool, I didn't know that you could set
@default
in pydantic. How does this work with creating an object in JS, I'm guessing it just doesn't know about the default there?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it just doesn't exist in JS, you have to satisfy the types yourself. I think this is only working when sending data from the backend to the frontend, though, not the opposite, and it's not doing what I want. I'm testing this in a separate PR and will report back in our Slack channel with what I found out