Skip to content
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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

rafaeelaudibert
Copy link
Member

Let's now actually use the currencyConvert function when computing Revenue on the Web Analytics panel. We make a lot of effort to only actually try converting it if there's something to convert.

Does this work well for both Cloud and self-hosted?

Yes

How did you test this code?

Unit tests, gotta test it in prod

@rafaeelaudibert rafaeelaudibert force-pushed the use-new-currency-convert-function-to-compute-revenue branch from 733ecf1 to 040440e Compare March 8, 2025 02:04
Copy link
Member Author

@rafaeelaudibert rafaeelaudibert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Gotta add some tests to web_overview as well, but you can see on revenue_example_events how this is working, just need to add some tests + add the original rate/currency to the UI on the revenue debugging table

@rafaeelaudibert rafaeelaudibert force-pushed the fix-loading-bar-on-small-dashboards branch from 5f6795b to 230c7a2 Compare March 10, 2025 14:45
@rafaeelaudibert rafaeelaudibert force-pushed the use-new-currency-convert-function-to-compute-revenue branch from e837dfd to 5e97500 Compare March 10, 2025 14:52
@rafaeelaudibert rafaeelaudibert changed the base branch from fix-loading-bar-on-small-dashboards to master March 10, 2025 14:52
@rafaeelaudibert rafaeelaudibert force-pushed the use-new-currency-convert-function-to-compute-revenue branch from 5db74e6 to 8cd2ca8 Compare March 10, 2025 15:33
@rafaeelaudibert rafaeelaudibert marked this pull request as ready for review March 10, 2025 15:33
@rafaeelaudibert
Copy link
Member Author

@robbie-c @lricoy tests and FF have been added, this is ready to review now!

Let's now actually use the `currencyConvert` function when computing Revenue on the Web Analytics panel. We make a lot of effort to only actually try converting it if there's something to convert.
@rafaeelaudibert rafaeelaudibert force-pushed the use-new-currency-convert-function-to-compute-revenue branch from 8cd2ca8 to 111361f Compare March 10, 2025 15:34
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR adds currency conversion functionality to the Web Analytics revenue tracking system, leveraging the new currencyConvert function for accurate multi-currency revenue calculations.

  • Added feature flag web-analytics-revenue-tracking-conversion to control currency conversion functionality across cloud and self-hosted environments
  • Implemented comprehensive currency conversion tests in test_web_overview.py covering various scenarios like USD/BRL to EUR conversions
  • Added original_revenue and original_currency fields to preserve pre-conversion values in revenue calculations
  • Removed revenue.py in favor of new currency conversion implementation in exchange_rate.py
  • Updated revenue sum expressions to handle currency conversion while maintaining backward compatibility

6 file(s) reviewed, 2 comment(s)
Edit PR Review Bot Settings | Greptile

Copy link
Member

@lricoy lricoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a while to be able to test it locally because it was out of my usual context, but LGTM. Only one nit comment.

One thing that is not related to this PR is: what happens when someone uses a invalid currency code? Maybe it was discussed when adding the hogql function, I just missed it.

convert_currency_call(
ast.Field(chain=["events", "properties", event.revenueProperty]),
ast.Field(chain=["events", "properties", event.revenueCurrencyProperty]),
ast.Constant(value=(config.baseCurrency or CurrencyCode.USD).value),
Copy link
Member

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 on posthog/models/schema.py so maybe you'll know how to approach this if you think it's valid :)

Copy link
Member Author

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 to RevenueConfig

Copy link
Member

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?

Copy link
Member Author

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

@rafaeelaudibert
Copy link
Member Author

Took me a while to be able to test it locally because it was out of my usual context, but LGTM. Only one nit comment.

One thing that is not related to this PR is: what happens when someone uses a invalid currency code? Maybe it was discussed when adding the hogql function, I just missed it.

@lricoy It won't exist in the dictionary, and we'll return 0 by default. This means that we'll just ignore events with invalid currencies. One thing I'm worried of is people using lowercase currencies (I think Stripe might be doing that) so I'll need to change that function to capitalize the currencies - I'll cross that bridge once we get there :)

else:
value_expr = ast.Call(
name="toDecimal",
args=[ast.Field(chain=["events", "properties", event.revenueProperty]), ast.Constant(value=10)],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 is the scale? As we use Decimal64 everywhere?

Can this go in a helpfully named constant please :D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 is the amount of decimal points we have (after the comma). And yeah, this can go to a helpfully named constant :)

convert_currency_call(
ast.Field(chain=["events", "properties", event.revenueProperty]),
ast.Field(chain=["events", "properties", event.revenueCurrencyProperty]),
ast.Constant(value=(config.baseCurrency or CurrencyCode.USD).value),
Copy link
Member

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?

name="toDecimal",
args=[
ast.Field(chain=["events", "properties", event.revenueProperty]),
ast.Constant(value=10),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10

@@ -1,95 +0,0 @@
from typing import Union
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a shame that git didn't notice that this was a moved file rather than deleted :(


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(
Copy link
Member

Choose a reason for hiding this comment

The 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

Copy link
Member Author

Choose a reason for hiding this comment

The 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 :)

This makes the hogql generation much more understandable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants