Show revenue data in all breakdowns (#5767)
* Include revenue data for all detailed API responses except entry/exit pages * Expose revenue data in all breakdown modals except entry/exit pages * Add revenue metrics to breakdown response only on EE * Change query builder to enable querying event metrics \w session dimension * Add revenue metrics to entry and exit pages breakdowns * Expose revenue data in entry and exit pages breakdowns * Use `argMax` for `exit_page` and `exit_page_hostname` dimensions (h/t @ukutaht) * Don't handle event-only dimensions with session-only metrics for now * Add tests for all breakdowns * Add clarifying comments in code * Mark revenue tests as EE-only
This commit is contained in:
parent
35f1cea344
commit
a2ba1256d2
|
|
@ -52,7 +52,7 @@ function BrowserVersionsModal() {
|
|||
<Modal>
|
||||
<BreakdownModal
|
||||
reportInfo={reportInfo}
|
||||
metrics={chooseMetrics(query)}
|
||||
metrics={chooseMetrics(query, site)}
|
||||
getFilterInfo={getFilterInfo}
|
||||
addSearchFilter={addSearchFilter}
|
||||
renderIcon={renderIcon}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function BrowsersModal() {
|
|||
<Modal>
|
||||
<BreakdownModal
|
||||
reportInfo={reportInfo}
|
||||
metrics={chooseMetrics(query)}
|
||||
metrics={chooseMetrics(query, site)}
|
||||
getFilterInfo={getFilterInfo}
|
||||
addSearchFilter={addSearchFilter}
|
||||
renderIcon={renderIcon}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@ import {
|
|||
hasConversionGoalFilter,
|
||||
isRealTimeDashboard
|
||||
} from '../../../util/filters'
|
||||
import { revenueAvailable } from '../../../query'
|
||||
import * as metrics from '../../reports/metrics'
|
||||
|
||||
export default function chooseMetrics(query) {
|
||||
export default function chooseMetrics(query, site) {
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
if (hasConversionGoalFilter(query)) {
|
||||
return [
|
||||
metrics.createTotalVisitors(),
|
||||
|
|
@ -12,8 +16,10 @@ export default function chooseMetrics(query) {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (isRealTimeDashboard(query)) {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ function OperatingSystemVersionsModal() {
|
|||
<Modal>
|
||||
<BreakdownModal
|
||||
reportInfo={reportInfo}
|
||||
metrics={chooseMetrics(query)}
|
||||
metrics={chooseMetrics(query, site)}
|
||||
getFilterInfo={getFilterInfo}
|
||||
addSearchFilter={addSearchFilter}
|
||||
renderIcon={renderIcon}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ function OperatingSystemsModal() {
|
|||
<Modal>
|
||||
<BreakdownModal
|
||||
reportInfo={reportInfo}
|
||||
metrics={chooseMetrics(query)}
|
||||
metrics={chooseMetrics(query, site)}
|
||||
getFilterInfo={getFilterInfo}
|
||||
addSearchFilter={addSearchFilter}
|
||||
renderIcon={renderIcon}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ function ScreenSizesModal() {
|
|||
<Modal>
|
||||
<BreakdownModal
|
||||
reportInfo={reportInfo}
|
||||
metrics={chooseMetrics(query)}
|
||||
metrics={chooseMetrics(query, site)}
|
||||
getFilterInfo={getFilterInfo}
|
||||
searchEnabled={false}
|
||||
renderIcon={renderIcon}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
hasConversionGoalFilter,
|
||||
isRealTimeDashboard
|
||||
} from '../../util/filters'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import BreakdownModal from './breakdown-modal'
|
||||
import * as metrics from '../reports/metrics'
|
||||
import * as url from '../../util/url'
|
||||
|
|
@ -16,6 +16,9 @@ function EntryPagesModal() {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
const reportInfo = {
|
||||
title: 'Entry Pages',
|
||||
dimension: 'entry_page',
|
||||
|
|
@ -54,8 +57,10 @@ function EntryPagesModal() {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (isRealTimeDashboard(query)) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useCallback } from 'react'
|
||||
import Modal from './modal'
|
||||
import { hasConversionGoalFilter } from '../../util/filters'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import BreakdownModal from './breakdown-modal'
|
||||
import * as metrics from '../reports/metrics'
|
||||
import * as url from '../../util/url'
|
||||
|
|
@ -13,6 +13,9 @@ function ExitPagesModal() {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
const reportInfo = {
|
||||
title: 'Exit Pages',
|
||||
dimension: 'exit_page',
|
||||
|
|
@ -51,8 +54,10 @@ function ExitPagesModal() {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (query.period === 'realtime') {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import * as metrics from '../reports/metrics'
|
|||
import * as url from '../../util/url'
|
||||
import { useQueryContext } from '../../query-context'
|
||||
import { useSiteContext } from '../../site-context'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import { SortDirection } from '../../hooks/use-order-by'
|
||||
|
||||
const VIEWS = {
|
||||
|
|
@ -38,6 +38,9 @@ function LocationsModal({ currentView }) {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
let reportInfo = VIEWS[currentView]
|
||||
reportInfo = {
|
||||
...reportInfo,
|
||||
|
|
@ -75,8 +78,10 @@ function LocationsModal({ currentView }) {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (query.period === 'realtime') {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
hasConversionGoalFilter,
|
||||
isRealTimeDashboard
|
||||
} from '../../util/filters'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import BreakdownModal from './breakdown-modal'
|
||||
import * as metrics from '../reports/metrics'
|
||||
import * as url from '../../util/url'
|
||||
|
|
@ -16,6 +16,9 @@ function PagesModal() {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
const reportInfo = {
|
||||
title: 'Top Pages',
|
||||
dimension: 'page',
|
||||
|
|
@ -54,8 +57,10 @@ function PagesModal() {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (isRealTimeDashboard(query)) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
import BreakdownModal from './breakdown-modal'
|
||||
import * as metrics from '../reports/metrics'
|
||||
import * as url from '../../util/url'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import { useQueryContext } from '../../query-context'
|
||||
import { useSiteContext } from '../../site-context'
|
||||
import { SortDirection } from '../../hooks/use-order-by'
|
||||
|
|
@ -20,6 +20,9 @@ function ReferrerDrilldownModal() {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
const reportInfo = {
|
||||
title: 'Referrer Drilldown',
|
||||
dimension: 'referrer',
|
||||
|
|
@ -61,8 +64,10 @@ function ReferrerDrilldownModal() {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (isRealTimeDashboard(query)) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
import BreakdownModal from './breakdown-modal'
|
||||
import * as metrics from '../reports/metrics'
|
||||
import * as url from '../../util/url'
|
||||
import { addFilter } from '../../query'
|
||||
import { addFilter, revenueAvailable } from '../../query'
|
||||
import { useQueryContext } from '../../query-context'
|
||||
import { useSiteContext } from '../../site-context'
|
||||
import { SortDirection } from '../../hooks/use-order-by'
|
||||
|
|
@ -91,6 +91,9 @@ function SourcesModal({ currentView }) {
|
|||
const { query } = useQueryContext()
|
||||
const site = useSiteContext()
|
||||
|
||||
/*global BUILD_EXTRA*/
|
||||
const showRevenueMetrics = BUILD_EXTRA && revenueAvailable(query, site)
|
||||
|
||||
let reportInfo = VIEWS[currentView].info
|
||||
reportInfo = {
|
||||
...reportInfo,
|
||||
|
|
@ -127,8 +130,10 @@ function SourcesModal({ currentView }) {
|
|||
renderLabel: (_query) => 'Conversions',
|
||||
width: 'w-28'
|
||||
}),
|
||||
metrics.createConversionRate()
|
||||
]
|
||||
metrics.createConversionRate(),
|
||||
showRevenueMetrics && metrics.createTotalRevenue(),
|
||||
showRevenueMetrics && metrics.createAverageRevenue()
|
||||
].filter((metric) => !!metric)
|
||||
}
|
||||
|
||||
if (isRealTimeDashboard(query)) {
|
||||
|
|
|
|||
|
|
@ -190,6 +190,49 @@ defmodule Plausible.Stats.SQL.Expression do
|
|||
def select_dimension(q, key, "visit:city_name", _table, _query),
|
||||
do: select_merge_as(q, [t], %{key => t.city_name})
|
||||
|
||||
def select_dimension_internal(q, "visit:entry_page") do
|
||||
select_merge_as(q, [t], %{
|
||||
entry_page: fragment("any(?)", field(t, :entry_page))
|
||||
})
|
||||
end
|
||||
|
||||
def select_dimension_internal(q, "visit:entry_page_hostname") do
|
||||
select_merge_as(q, [t], %{
|
||||
entry_page_hostname: fragment("any(?)", field(t, :entry_page_hostname))
|
||||
})
|
||||
end
|
||||
|
||||
def select_dimension_internal(q, "visit:exit_page") do
|
||||
# As exit page changes with every pageview event over the lifetime
|
||||
# of a session, only the most recent value must be considered.
|
||||
select_merge_as(q, [t], %{
|
||||
exit_page: fragment("argMax(?, ?)", field(t, :exit_page), field(t, :events))
|
||||
})
|
||||
end
|
||||
|
||||
def select_dimension_internal(q, "visit:exit_page_hostname") do
|
||||
select_merge_as(q, [t], %{
|
||||
exit_page_hostname:
|
||||
fragment("argMax(?, ?)", field(t, :exit_page_hostname), field(t, :events))
|
||||
})
|
||||
end
|
||||
|
||||
def select_dimension_internal(q, _dimension), do: q
|
||||
|
||||
def select_dimension_from_join(q, key, "visit:entry_page"),
|
||||
do: select_merge_as(q, [..., t], %{key => t.entry_page})
|
||||
|
||||
def select_dimension_from_join(q, key, "visit:entry_page_hostname"),
|
||||
do: select_merge_as(q, [..., t], %{key => t.entry_page_hostaname})
|
||||
|
||||
def select_dimension_from_join(q, key, "visit:exit_page"),
|
||||
do: select_merge_as(q, [..., t], %{key => t.exit_page})
|
||||
|
||||
def select_dimension_from_join(q, key, "visit:exit_page_hostname"),
|
||||
do: select_merge_as(q, [..., t], %{key => t.exit_page_hostname})
|
||||
|
||||
def select_dimension_from_join(q, _key, _dimension), do: q
|
||||
|
||||
def event_metric(:pageviews, _query) do
|
||||
wrap_alias([e], %{
|
||||
pageviews: scale_sample(fragment("countIf(? = 'pageview')", e.name))
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ defmodule Plausible.Stats.SQL.QueryBuilder do
|
|||
|
||||
defp join_sessions_if_needed(q, query) do
|
||||
if TableDecider.events_join_sessions?(query) do
|
||||
%{session: dimensions} = TableDecider.partition_dimensions(query)
|
||||
|
||||
sessions_q =
|
||||
from(
|
||||
s in "sessions_v2",
|
||||
|
|
@ -81,6 +83,14 @@ defmodule Plausible.Stats.SQL.QueryBuilder do
|
|||
group_by: s.session_id
|
||||
)
|
||||
|
||||
# The session-only dimension columns are explicitly selected in joined
|
||||
# sessions table. This enables combining session-only dimensions (entry
|
||||
# and exit pages) with event-only metrics, like revenue.
|
||||
sessions_q =
|
||||
Enum.reduce(dimensions, sessions_q, fn dimension, acc ->
|
||||
Plausible.Stats.SQL.Expression.select_dimension_internal(acc, dimension)
|
||||
end)
|
||||
|
||||
on_ee do
|
||||
sessions_q = Plausible.Stats.Sampling.add_query_hint(sessions_q, query)
|
||||
end
|
||||
|
|
@ -131,8 +141,31 @@ defmodule Plausible.Stats.SQL.QueryBuilder do
|
|||
|> Enum.reduce(%{}, &Map.merge/2)
|
||||
end
|
||||
|
||||
def build_group_by(q, table, query) do
|
||||
Enum.reduce(query.dimensions, q, &dimension_group_by(&2, table, query, &1))
|
||||
def build_group_by(q, :events, query) do
|
||||
# Session-only dimensions are extracted from joined sessions table
|
||||
%{session: session_only_dimensions} = TableDecider.partition_dimensions(query)
|
||||
event_dimensions = query.dimensions -- session_only_dimensions
|
||||
|
||||
q =
|
||||
Enum.reduce(event_dimensions, q, &dimension_group_by(&2, :events, query, &1))
|
||||
|
||||
Enum.reduce(
|
||||
session_only_dimensions,
|
||||
q,
|
||||
&dimension_group_by_join(&2, query, &1)
|
||||
)
|
||||
end
|
||||
|
||||
def build_group_by(q, :sessions, query) do
|
||||
Enum.reduce(query.dimensions, q, &dimension_group_by(&2, :sessions, query, &1))
|
||||
end
|
||||
|
||||
defp dimension_group_by_join(q, query, dimension) do
|
||||
key = shortname(query, dimension)
|
||||
|
||||
q
|
||||
|> Expression.select_dimension_from_join(key, dimension)
|
||||
|> group_by([], selected_as(^key))
|
||||
end
|
||||
|
||||
defp dimension_group_by(q, :events, query, "event:goal" = dimension) do
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ defmodule Plausible.Stats.TableDecider do
|
|||
end
|
||||
end
|
||||
|
||||
def partition_dimensions(query) do
|
||||
partition(query.dimensions, query, &dimension_partitioner/2)
|
||||
end
|
||||
|
||||
@type table_type() :: :events | :sessions
|
||||
@type metric() :: String.t()
|
||||
|
||||
|
|
|
|||
|
|
@ -477,7 +477,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics)
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics,
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -511,7 +515,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics)
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics,
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -595,7 +603,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:utm_medium")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -625,7 +638,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:utm_campaign")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -655,7 +673,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:utm_content")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -685,7 +708,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:utm_term")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -715,7 +743,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:utm_source")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -745,7 +778,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:referrer")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:bounce_rate, :visit_duration])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:bounce_rate, :visit_duration],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -837,7 +875,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics)
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics,
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -865,7 +907,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
[]
|
||||
end
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics)
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics,
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
pagination = parse_pagination(params)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
|
@ -897,7 +944,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:entry_page")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:visits, :visit_duration, :bounce_rate])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:visits, :visit_duration, :bounce_rate],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -943,7 +995,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
[:visits, :exit_rate]
|
||||
end
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics)
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics,
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, {limit, page})
|
||||
|
||||
|
|
@ -980,7 +1036,12 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:country")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query, [:percentage])
|
||||
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1038,7 +1099,7 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:region")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query)
|
||||
metrics = breakdown_metrics(query, include_revenue?: !!params["detailed"])
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1079,7 +1140,7 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
params = Map.put(params, "property", "visit:city")
|
||||
query = Query.from(site, params, debug_metadata(conn))
|
||||
pagination = parse_pagination(params)
|
||||
metrics = breakdown_metrics(query)
|
||||
metrics = breakdown_metrics(query, include_revenue?: !!params["detailed"])
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1129,7 +1190,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics ++ [:percentage])
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics ++ [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1163,7 +1228,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics ++ [:percentage])
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics ++ [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1206,7 +1275,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics ++ [:percentage])
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics ++ [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1240,7 +1313,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics ++ [:percentage])
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics ++ [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1283,7 +1360,11 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
extra_metrics =
|
||||
if params["detailed"], do: [:bounce_rate, :visit_duration], else: []
|
||||
|
||||
metrics = breakdown_metrics(query, extra_metrics ++ [:percentage])
|
||||
metrics =
|
||||
breakdown_metrics(query,
|
||||
extra_metrics: extra_metrics ++ [:percentage],
|
||||
include_revenue?: !!params["detailed"]
|
||||
)
|
||||
|
||||
%{results: results, meta: meta} = Stats.breakdown(site, query, metrics, pagination)
|
||||
|
||||
|
|
@ -1614,9 +1695,18 @@ defmodule PlausibleWeb.Api.StatsController do
|
|||
end
|
||||
end
|
||||
|
||||
defp breakdown_metrics(query, extra_metrics \\ []) do
|
||||
defp breakdown_metrics(query, opts) do
|
||||
extra_metrics = Keyword.get(opts, :extra_metrics, [])
|
||||
include_revenue? = Keyword.get(opts, :include_revenue?, false)
|
||||
|
||||
if toplevel_goal_filter?(query) do
|
||||
[:visitors, :conversion_rate, :total_visitors]
|
||||
metrics = [:visitors, :conversion_rate, :total_visitors]
|
||||
|
||||
if ee?() and include_revenue? do
|
||||
metrics ++ [:average_revenue, :total_revenue]
|
||||
else
|
||||
metrics
|
||||
end
|
||||
else
|
||||
[:visitors] ++ extra_metrics
|
||||
end
|
||||
|
|
|
|||
|
|
@ -271,6 +271,114 @@ defmodule PlausibleWeb.Api.StatsController.BrowsersTest do
|
|||
"comparison_date_range_label" => "30 Dec 2020 - 5 Jan 2021"
|
||||
}
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for browsers breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, browser: "Firefox"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, browser: "Firefox"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, browser: "Firefox"),
|
||||
build(:pageview, user_id: 4, browser: "Safari"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 5, browser: "Safari"),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/browsers#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "(not set)",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "Firefox",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "Safari",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/browser-versions" do
|
||||
|
|
|
|||
|
|
@ -66,5 +66,124 @@ defmodule PlausibleWeb.Api.StatsController.CitiesTest do
|
|||
%{"code" => 591_632, "country_flag" => "🇪🇪", "name" => "Kärdla", "visitors" => 2}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for cities breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-39",
|
||||
city_geoname_id: 591_632
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-39",
|
||||
city_geoname_id: 591_632
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/cities#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 33.33,
|
||||
"name" => "Tallinn",
|
||||
"code" => 588_409,
|
||||
"country_flag" => "🇪🇪",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 6,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 25.0,
|
||||
"name" => "Kärdla",
|
||||
"code" => 591_632,
|
||||
"country_flag" => "🇪🇪",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 4,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -412,5 +412,116 @@ defmodule PlausibleWeb.Api.StatsController.CountriesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for countries breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
country_code: "EE"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
country_code: "EE"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
country_code: "EE"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
country_code: "GB"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
country_code: "GB"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/countries#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "Estonia",
|
||||
"alpha_3" => "EST",
|
||||
"code" => "EE",
|
||||
"flag" => "🇪🇪",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "United Kingdom",
|
||||
"alpha_3" => "GBR",
|
||||
"code" => "GB",
|
||||
"flag" => "🇬🇧",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -212,6 +212,114 @@ defmodule PlausibleWeb.Api.StatsController.OperatingSystemsTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for operating systems breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, operating_system: "Mac"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, operating_system: "Mac"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, operating_system: "Mac"),
|
||||
build(:pageview, user_id: 4, operating_system: "Android"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 5, operating_system: "Android"),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/operating-systems#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "(not set)",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "Mac",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "Android",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/operating-system-versions" do
|
||||
|
|
|
|||
|
|
@ -3009,5 +3009,371 @@ defmodule PlausibleWeb.Api.StatsController.PagesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for entry pages breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, pathname: "/second"),
|
||||
build(:event,
|
||||
user_id: 2,
|
||||
name: "Payment",
|
||||
revenue_reporting_amount: Decimal.new("3000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("4000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 3,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 4, pathname: "/third"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("2500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event, name: "Payment", revenue_reporting_amount: nil),
|
||||
build(:event, name: "Payment", revenue_reporting_amount: nil)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn =
|
||||
get(
|
||||
conn,
|
||||
"/api/stats/#{site.domain}/entry-pages#{q}"
|
||||
)
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/first",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,500.00",
|
||||
"short" => "$3.5K",
|
||||
"value" => 3500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/second",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$7,000.00",
|
||||
"short" => "$7.0K",
|
||||
"value" => 7000.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/third",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for exit pages breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 1, pathname: "/exit_first"),
|
||||
build(:pageview, user_id: 2, pathname: "/second"),
|
||||
build(:event,
|
||||
user_id: 2,
|
||||
name: "Payment",
|
||||
revenue_reporting_amount: Decimal.new("3000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("4000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, pathname: "/exit_second"),
|
||||
build(:pageview, user_id: 3, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 3,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, pathname: "/exit_first"),
|
||||
build(:pageview, user_id: 4, pathname: "/third"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("2500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event, name: "Payment", revenue_reporting_amount: nil),
|
||||
build(:event, name: "Payment", revenue_reporting_amount: nil)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn =
|
||||
get(
|
||||
conn,
|
||||
"/api/stats/#{site.domain}/exit-pages#{q}"
|
||||
)
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/exit_first",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,500.00",
|
||||
"short" => "$3.5K",
|
||||
"value" => 3500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/exit_second",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$7,000.00",
|
||||
"short" => "$7.0K",
|
||||
"value" => 7000.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/third",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for pages breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
pathname: "/purchase/first",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 1, pathname: "/exit_first"),
|
||||
build(:pageview, user_id: 2, pathname: "/second"),
|
||||
build(:event,
|
||||
user_id: 2,
|
||||
name: "Payment",
|
||||
pathname: "/purchase/second",
|
||||
revenue_reporting_amount: Decimal.new("3000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
pathname: "/purchase/second",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("4000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, pathname: "/exit_second"),
|
||||
build(:pageview, user_id: 3, pathname: "/first"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
pathname: "/purchase/first",
|
||||
user_id: 3,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, pathname: "/exit_first"),
|
||||
build(:pageview, user_id: 4, pathname: "/third"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
pathname: "/purchase/third",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("2500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:event, name: "Payment", pathname: "/nopay", revenue_reporting_amount: nil),
|
||||
build(:event, name: "Payment", pathname: "/nopay", revenue_reporting_amount: nil),
|
||||
build(:event, name: "Payment", pathname: "/nopay", revenue_reporting_amount: nil)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn =
|
||||
get(
|
||||
conn,
|
||||
"/api/stats/#{site.domain}/pages#{q}"
|
||||
)
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$0.00",
|
||||
"short" => "$0.0",
|
||||
"value" => 0.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/nopay",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$0.00",
|
||||
"short" => "$0.0",
|
||||
"value" => 0.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 3
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/purchase/first",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,500.00",
|
||||
"short" => "$3.5K",
|
||||
"value" => 3500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/purchase/second",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$7,000.00",
|
||||
"short" => "$7.0K",
|
||||
"value" => 7000.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "/purchase/third",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$2,500.00",
|
||||
"short" => "$2.5K",
|
||||
"value" => 2500.0
|
||||
},
|
||||
"total_visitors" => 1,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -94,5 +94,124 @@ defmodule PlausibleWeb.Api.StatsController.RegionsTest do
|
|||
assert resp = response(conn, 400)
|
||||
assert resp =~ "Failed to parse 'to' argument."
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for regions breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-37",
|
||||
city_geoname_id: 588_409
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-39",
|
||||
city_geoname_id: 591_632
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
country_code: "EE",
|
||||
subdivision1_code: "EE-39",
|
||||
city_geoname_id: 591_632
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/regions#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 33.33,
|
||||
"name" => "Harjumaa",
|
||||
"code" => "EE-37",
|
||||
"country_flag" => "🇪🇪",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 6,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 25.0,
|
||||
"name" => "Hiiumaa",
|
||||
"code" => "EE-39",
|
||||
"country_flag" => "🇪🇪",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 4,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -316,5 +316,113 @@ defmodule PlausibleWeb.Api.StatsController.ScreenSizesTest do
|
|||
%{"name" => "Mobile", "visitors" => 1, "percentage" => 33.3}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for screen sizes breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview, user_id: 1, screen_size: "Mobile"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 2, screen_size: "Mobile"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 3, screen_size: "Mobile"),
|
||||
build(:pageview, user_id: 4, screen_size: "Desktop"),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 5, screen_size: "Desktop"),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/screen-sizes#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"name" => "(not set)",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "Mobile",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "Desktop",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -678,6 +678,139 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
"comparison_date_range_label" => "1 Jan 2021"
|
||||
}
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for sources breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
referrer_source: "DuckDuckGo",
|
||||
referrer: "duckduckgo.com"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
referrer_source: "DuckDuckGo",
|
||||
referrer: "duckduckgo.com"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 8,
|
||||
referrer_source: "Bing",
|
||||
referrer: "bing.com"
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/sources#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"name" => "Direct / None",
|
||||
"visitors" => 2,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"total_visitors" => 2
|
||||
},
|
||||
%{
|
||||
"name" => "Google",
|
||||
"visitors" => 2,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3
|
||||
},
|
||||
%{
|
||||
"name" => "DuckDuckGo",
|
||||
"visitors" => 1,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "UTM parameters with hostname filter" do
|
||||
|
|
@ -774,6 +907,134 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for channels breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
referrer_source: "Google",
|
||||
referrer: "google.com"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
referrer_source: "Facebook",
|
||||
utm_source: "fb-ads"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
referrer_source: "Facebook",
|
||||
utm_source: "fb-ads"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/channels#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"name" => "Direct",
|
||||
"visitors" => 2,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"conversion_rate" => 100.0,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$600.00",
|
||||
"short" => "$600.0",
|
||||
"value" => 600.0
|
||||
},
|
||||
"total_visitors" => 2
|
||||
},
|
||||
%{
|
||||
"name" => "Organic Search",
|
||||
"visitors" => 2,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3
|
||||
},
|
||||
%{
|
||||
"name" => "Paid Social",
|
||||
"visitors" => 1,
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/utm_mediums" do
|
||||
|
|
@ -926,6 +1187,111 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for UTM mediums breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
utm_medium: "social"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
utm_medium: "social"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
utm_medium: "social"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
utm_medium: "email"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
utm_medium: "email"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/utm_mediums#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "social",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "email",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/utm_campaigns" do
|
||||
|
|
@ -1086,6 +1452,111 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for UTM campaigns breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
utm_campaign: "profile"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
utm_campaign: "profile"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
utm_campaign: "profile"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
utm_campaign: "august"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
utm_campaign: "august"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/utm_campaigns#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "profile",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "august",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/utm_sources" do
|
||||
|
|
@ -1134,6 +1605,111 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for UTM sources breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
utm_source: "Twitter"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
utm_source: "Twitter"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
utm_source: "Twitter"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
utm_source: "newsletter"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
utm_source: "newsletter"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/utm_sources#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "Twitter",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "newsletter",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/utm_terms" do
|
||||
|
|
@ -1294,6 +1870,111 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for UTM terms breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
utm_term: "oat milk"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
utm_term: "oat milk"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
utm_term: "oat milk"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
utm_term: "Sweden"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
utm_term: "Sweden"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/utm_terms#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "oat milk",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "Sweden",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/utm_contents" do
|
||||
|
|
@ -1454,6 +2135,111 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
@tag :ee_only
|
||||
test "return revenue metrics for UTM contents breakdown", %{conn: conn, site: site} do
|
||||
populate_stats(site, [
|
||||
build(:pageview,
|
||||
user_id: 1,
|
||||
utm_content: "ad"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 1,
|
||||
revenue_reporting_amount: Decimal.new("1000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 2,
|
||||
utm_content: "ad"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 2,
|
||||
revenue_reporting_amount: Decimal.new("2000"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 3,
|
||||
utm_content: "ad"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 4,
|
||||
utm_content: "blog"
|
||||
),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 4,
|
||||
revenue_reporting_amount: Decimal.new("500"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview,
|
||||
user_id: 5,
|
||||
utm_content: "blog"
|
||||
),
|
||||
build(:pageview, user_id: 6),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 6,
|
||||
revenue_reporting_amount: Decimal.new("600"),
|
||||
revenue_reporting_currency: "USD"
|
||||
),
|
||||
build(:pageview, user_id: 7),
|
||||
build(:event,
|
||||
name: "Payment",
|
||||
user_id: 7,
|
||||
revenue_reporting_amount: nil
|
||||
)
|
||||
])
|
||||
|
||||
insert(:goal, %{site: site, event_name: "Payment", currency: :USD})
|
||||
|
||||
filters = Jason.encode!([[:is, "event:goal", ["Payment"]]])
|
||||
order_by = Jason.encode!([["visitors", "desc"]])
|
||||
|
||||
q = "?filters=#{filters}&order_by=#{order_by}&detailed=true&period=day&page=1&limit=100"
|
||||
|
||||
conn = get(conn, "/api/stats/#{site.domain}/utm_contents#{q}")
|
||||
|
||||
assert json_response(conn, 200)["results"] == [
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$1,500.00",
|
||||
"short" => "$1.5K",
|
||||
"value" => 1500.0
|
||||
},
|
||||
"conversion_rate" => 66.67,
|
||||
"name" => "ad",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$3,000.00",
|
||||
"short" => "$3.0K",
|
||||
"value" => 3000.0
|
||||
},
|
||||
"total_visitors" => 3,
|
||||
"visitors" => 2
|
||||
},
|
||||
%{
|
||||
"average_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"conversion_rate" => 50.0,
|
||||
"name" => "blog",
|
||||
"total_revenue" => %{
|
||||
"currency" => "USD",
|
||||
"long" => "$500.00",
|
||||
"short" => "$500.0",
|
||||
"value" => 500.0
|
||||
},
|
||||
"total_visitors" => 2,
|
||||
"visitors" => 1
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/stats/:domain/sources - with goal filter" do
|
||||
|
|
|
|||
Loading…
Reference in New Issue