diff --git a/lib/mix/tasks/create_paddle_prod_plans.ex b/lib/mix/tasks/create_paddle_prod_plans.ex new file mode 100644 index 0000000000..3375f48276 --- /dev/null +++ b/lib/mix/tasks/create_paddle_prod_plans.ex @@ -0,0 +1,342 @@ +defmodule Mix.Tasks.CreatePaddleProdPlans do + @moduledoc """ + ## Utility for creating Paddle plans for production use. + + Takes a single `filename` argument which should be of format + `input_plans_v*.json`. That file should live in the `/priv` directory next + to all other plans and it should contain the necessary information about + the production plans to be created. + + In order to create the input file: + + * Copy an existing `plans_v*.json` (latest recommended) into the new + `input_plans_v*.json` file. + * For every plan object: + * Adjust the generation, limits, features, etc as desired + * Replace `monthly_product_id` with a `monthly_price` (integer) + * Replace `yearly_product_id` with a `yearly_price` (integer) + + After this task is finished successfully, the plans will be created in Paddle + with the prices given in the input file. With the creation, every plan gets an + autoincremented ID in Paddle. We will then fetch those exact plans from Paddle + in an API call and use their monthly and yearly product_id's to write + `plans_v*.json`. It will be written taking the input file as the "template" + and replacing the monthly/yearly prices with monthly/yearly product_id's. + + The prices will be written into `/priv/plan_prices.json` (instead of the + prod plans output file). Note that this separation is intentional - we only + store prices locally to not rely on Paddle in the dev environment. Otherwise, + Paddle is considered the "source of truth" of plan prices. + + ## Usage example: + + ``` + mix create_paddle_prod_plans input_plans_v5.json + ``` + + ## Requirement 1: Replace the curl command + + Unfortunately, there's no API in Paddle that would allow "bulk creating" + plans - it has to be done through the UI. As a hack though, we can automate + the process by copying the curl request with the help of browser devtools. + + Therefore, this Mix.Task **does not work out of the box** and the actual curl + command that it executes must be replaced by the developer. Here's how: + + 0) Access required to the production Paddle account + 1) Navigate to https://vendors.paddle.com/subscriptions/plans. Chrome or + Firefox recommended (need to copy a POST request as cURL in a later step) + 2) Click the "+ New Plan" button (top right of the screen) to open the form + 3) Open browser devtools, fill in the required fields and submit the form. + No need to worry about the form fields since they're provided in this task + (except `_token`) and they *should work* as long as nothing has changed. + 4) Find the POST request from the "Network" tab and copy it as cURL + 5) Come back here and paste it into the `create_paddle_plan` function + 6) Replace the params within the string with the real params (these should + be available in the function already) + + ## Requirement 2: Paddle production credentials + + You also need to obtain the Paddle credentials from prod environment and + replace them into the module attributes. See `@paddle_vendor_id` and + `@paddle_vendor_auth_code`. Those are needed to fetch the plans via an + actual API call after the plans have been created in Paddle. + """ + + use Mix.Task + + @requirements ["app.config"] + + @paddle_vendor_id "REPLACE ME" + @paddle_vendor_auth_code "REPLACE ME" + + def run([filename]) do + {:ok, _} = Application.ensure_all_started(:telemetry) + Finch.start_link(name: MyFinch) + + if not Regex.match?(~r/^input_plans_v(\d+)\.json$/, filename) do + raise ArgumentError, + "Invalid filename argument. Note the strict format - e.g.: \"input_plans_v5.json\"" + end + + input_plans = + Application.app_dir(:plausible, ["priv", filename]) + |> File.read!() + |> JSON.decode!() + + to_be_created_in_paddle = + input_plans + |> Enum.flat_map(fn plan -> + [ + create_paddle_plan_attrs(plan, "monthly"), + create_paddle_plan_attrs(plan, "yearly") + ] + end) + + user_input = + """ + \n + ########################################################################## + # # + # !WARNING! # + # # + # You're about to create production plans in Paddle. Multiple # + # consecutive executions will create the same plans again. # + # Please make sure to not leave duplicates behind! # + # # + ########################################################################## + + * 'y' - proceed and create all plans + * 't' - test only with two plans + * 'h' - halt + + What would you like to do? + """ + |> IO.gets() + |> String.trim() + |> String.upcase() + + test_run? = + case user_input do + "Y" -> + IO.puts("Creating all plans...") + false + + "T" -> + IO.puts("Creating 2 plans just for testing. Make sure to delete them manually!") + true + + _ -> + IO.puts("Halting execution per user request.") + System.halt() + end + + {paddle_create_count, create_count} = + if test_run? do + {2, 1} + else + {length(to_be_created_in_paddle), length(input_plans)} + end + + to_be_created_in_paddle + |> Enum.take(paddle_create_count) + |> Enum.each(&create_paddle_plan/1) + + IO.puts("⏳ waiting 3s before fetching the newly created plans...") + Process.sleep(3000) + IO.puts("Fetching the #{create_count} plans created a moment ago...") + + created_paddle_plans = + fetch_all_prod_plans() + |> Enum.sort_by(& &1["id"]) + |> Enum.take(-paddle_create_count) + + file_path_to_write = Path.join("priv", String.replace(filename, "input_", "")) + + prod_plans_with_ids_and_prices = + input_plans + |> Enum.take(create_count) + |> write_prod_plans_json_file(file_path_to_write, created_paddle_plans) + + IO.puts("✅ Wrote #{create_count} new plans into #{file_path_to_write}!") + + if not test_run? do + write_prices(prod_plans_with_ids_and_prices) + IO.puts("✅ Updated `plan_prices.json`.") + end + + IO.puts("✅ All done!") + end + + defp create_paddle_plan(%{name: name, price: price, type: type, interval_index: interval_index}) do + your_unique_token = "abc" + + # Replace this curl command. You should be able to reuse + # the request body after replacing your unique token. + curl_command = """ + ... REPLACE ME + --data-raw '_token=#{your_unique_token}&plan-id=&default-curr=USD&tmpicon=false&name=#{name}&checkout_custom_message=&taxable_type=standard&interval=#{interval_index}&period=1&type=#{type}&trial_length=&price_USD=#{price}&active_EUR=on&price_EUR=#{price}&active_GBP=on&price_GBP=#{price}' + """ + + case curl_quietly(curl_command) do + :ok -> + IO.puts("✅ Created #{name}") + + {:error, reason} -> + IO.puts("❌ Halting. The plan #{name} could not be created. Error: #{reason}") + System.halt(1) + end + end + + @paddle_interval_indexes %{"monthly" => 2, "yearly" => 5} + + defp create_paddle_plan_attrs(plan_with_price, type) do + %{ + name: plan_name(plan_with_price, type), + price: plan_with_price["#{type}_price"], + type: type, + interval_index: @paddle_interval_indexes[type] + } + end + + defp fetch_all_prod_plans() do + "https://vendors.paddle.com/api/2.0/subscription/plans" + |> fetch_all_paddle_plans(%{ + vendor_id: @paddle_vendor_id, + vendor_auth_code: @paddle_vendor_auth_code + }) + end + + @paddle_plans_api_pagination_limit 500 + def fetch_all_paddle_plans(url, paddle_credentials, page \\ 0, fetched \\ 0) do + body = + paddle_credentials + |> Map.merge(%{ + limit: @paddle_plans_api_pagination_limit, + offset: page * @paddle_plans_api_pagination_limit + }) + |> JSON.encode!() + + headers = [ + {"Content-type", "application/json"}, + {"Accept", "application/json"} + ] + + request = Finch.build(:post, url, headers, body) + + with {:ok, response} <- Finch.request(request, MyFinch), + {:ok, %{"success" => true, "response" => plans} = body} <- JSON.decode(response.body) do + fetched = body["count"] + fetched + total = body["total"] + + IO.puts("✅ Successfully fetched #{fetched}/#{body["total"]} plans") + + if fetched == total do + plans + else + plans ++ fetch_all_paddle_plans(url, paddle_credentials, page + 1, fetched) + end + else + error -> + IO.puts("❌ Failed to fetch plans from Paddle - #{inspect(error)}") + System.halt(1) + end + end + + defp write_prod_plans_json_file(input_plans, filepath, paddle_plans) do + prod_plans_with_prices = + input_plans + |> Enum.map(fn input_plan -> + monthly_plan_name = plan_name(input_plan, "monthly") + yearly_plan_name = plan_name(input_plan, "yearly") + + %{"id" => monthly_product_id} = + Enum.find(paddle_plans, &(&1["name"] == monthly_plan_name)) + + %{"id" => yearly_product_id} = + Enum.find(paddle_plans, &(&1["name"] == yearly_plan_name)) + + input_plan + |> Map.merge(%{ + "monthly_product_id" => to_string(monthly_product_id), + "yearly_product_id" => to_string(yearly_product_id) + }) + end) + + content = + prod_plans_with_prices + |> Enum.map(fn plan -> + plan + |> Map.drop(["monthly_price", "yearly_price"]) + |> order_keys() + end) + |> Jason.encode!(pretty: true) + + File.write!(filepath, content) + + prod_plans_with_prices + end + + @plan_prices_filepath Application.app_dir(:plausible, ["priv", "plan_prices.json"]) + defp write_prices(prod_plans_with_ids_and_prices) do + current_prices = File.read!(@plan_prices_filepath) |> JSON.decode!() + + new_prices = + prod_plans_with_ids_and_prices + |> Enum.reduce(current_prices, fn plan, prices -> + prices + |> Map.put_new(plan["monthly_product_id"], plan["monthly_price"]) + |> Map.put_new(plan["yearly_product_id"], plan["yearly_price"]) + end) + |> Enum.sort() + |> Jason.OrderedObject.new() + |> Jason.encode!(pretty: true) + + File.write(@plan_prices_filepath, new_prices) + end + + @plan_key_order [ + "kind", + "generation", + "monthly_pageview_limit", + "monthly_product_id", + "yearly_product_id", + "site_limit", + "team_member_limit", + "features" + ] + def order_keys(plan) do + plan + |> Map.to_list() + |> Enum.sort_by(fn {key, _value} -> + Enum.find_index(@plan_key_order, fn ordered_key -> ordered_key == key end) || 99 + end) + |> Jason.OrderedObject.new() + end + + defp plan_name(plan, type) do + kind = plan["kind"] |> String.capitalize() + type = type |> String.capitalize() + + volume = + plan["monthly_pageview_limit"] + |> PlausibleWeb.StatsView.large_number_format(capitalize_k?: true) + + "Plausible #{kind} #{type} Plan (#{volume})" + end + + def curl_quietly(cmd) do + cmd = String.replace(cmd, "curl", ~s|curl -s -o /dev/null -w "%{http_code}"|) + + case System.cmd("sh", ["-c", cmd], stderr_to_stdout: true) do + {"302", 0} -> + :ok + + {http_status, 0} -> + {:error, "unexpected HTTP response status (#{http_status}). Expected 302."} + + {_, exit_code} -> + {:error, "curl command exited with exit code #{exit_code}"} + end + end +end diff --git a/lib/mix/tasks/create_paddle_sandbox_plans.ex b/lib/mix/tasks/create_paddle_sandbox_plans.ex index db341df49f..cc2fb2dcd5 100644 --- a/lib/mix/tasks/create_paddle_sandbox_plans.ex +++ b/lib/mix/tasks/create_paddle_sandbox_plans.ex @@ -1,31 +1,35 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do @moduledoc """ - Utility for creating Sandbox plans that are used on staging. The `filename` - argument should be the name of the JSON file containing the production plans. - E.g.: `plans_v4.json`. + Utility for creating Sandbox plans that are used on staging. The product of + this task is a `sandbox_plans_v*.json` file matching with the production + plans, just with the monthly/yearly product_id's of the sandbox plans. - Unfortunately, there's no API in Paddle that would allow "bulk creating" - plans - it has to be done through the UI. As a hack though, we can automate - the process by copying the curl request with the help of browser devtools. + In principle, this task works like `Mix.Tasks.CreatePaddleProdPlans`, with + the following differences: - Therefore, this Mix.Task **does not work out of the box** and the actual curl - command that it executes must be replaced by the developer. Here's how: + * The `filename` argument should be the name of the JSON file containing the + production plans (meaning that those should be created as the first step). + No special "input file" required. - 0) Obtain access to the Sandbox Paddle account and log in - 1) Navigate to https://sandbox-vendors.paddle.com/subscriptions/plans - 2) Click the "+ New Plan" button to open the form - 3) Open browser devtools, fill in the required fields and submit the form - 4) Find the POST request from the "Network" tab and copy it as cURL - 5) Come back here and paste it into the `create_paddle_plan` function - 6) Replace the params within the string with the real params (these should - be available in the function already) + * To copy the curl command from the browser, you need to add a plan from + https://sandbox-vendors.paddle.com/subscriptions/plans. Everything else is + the same - please see `create_paddle_prod_plans.ex` for instructions. - Once the plans are created successfully, the task will also fetch the IDs - (i.e. paddle_plan_id's) and write the `sandbox_plans_v*.json` file (which is - basically the same set of production plans but with `monthly_product_id` and - `yearly_product_id` replaced with the sandbox ones). + * This task can be executed multiple times in a row - it will not create + duplicates in Sandbox Paddle. On staging we can use a specific plan-naming + structure to determine whether a plan has been created already. On prod we + cannot do that since the plan names need to look nice. + + * No need to copy paddle API credentials. + + ## Usage example: + + ``` + mix create_paddle_sandbox_plans plans_v5.json + ``` """ + alias Mix.Tasks.CreatePaddleProdPlans use Mix.Task @requirements ["app.config"] @@ -76,7 +80,7 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do file_path_to_write = Path.join("priv", "sandbox_" <> filename) - create_local_sandbox_plans_json_file(prod_plans, file_path_to_write, paddle_plans_after) + write_sandbox_plans_json_file(prod_plans, file_path_to_write, paddle_plans_after) IO.puts("✅ All done! Wrote #{length(prod_plans)} new plans into #{file_path_to_write}!") end @@ -91,7 +95,7 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do --data-raw '_token=#{your_unique_token}&plan-id=&default-curr=USD&tmpicon=false&name=#{name}&checkout_custom_message=&taxable_type=standard&interval=#{interval_index}&period=1&type=#{type}&trial_length=&price_USD=#{price}&active_EUR=on&price_EUR=#{price}&active_GBP=on&price_GBP=#{price}' """ - case curl_quietly(curl_command) do + case CreatePaddleProdPlans.curl_quietly(curl_command) do :ok -> IO.puts("✅ Created #{name}") @@ -101,6 +105,19 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do end end + defp fetch_all_sandbox_plans() do + url = "https://sandbox-vendors.paddle.com/api/2.0/subscription/plans" + + paddle_config = Application.get_env(:plausible, :paddle) + + paddle_credentials = %{ + vendor_id: paddle_config[:vendor_id], + vendor_auth_code: paddle_config[:vendor_auth_code] + } + + CreatePaddleProdPlans.fetch_all_paddle_plans(url, paddle_credentials) + end + @paddle_interval_indexes %{"monthly" => 2, "yearly" => 5} defp create_paddle_plan_attrs(plan_with_price, type) do @@ -112,36 +129,15 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do } end - defp fetch_all_sandbox_plans() do - paddle_config = Application.get_env(:plausible, :paddle) + defp plan_name(plan, type) do + generation = "v#{plan["generation"]}" + kind = plan["kind"] + volume = plan["monthly_pageview_limit"] |> PlausibleWeb.StatsView.large_number_format() - url = "https://sandbox-vendors.paddle.com/api/2.0/subscription/plans" - - body = - JSON.encode!(%{ - vendor_id: paddle_config[:vendor_id], - vendor_auth_code: paddle_config[:vendor_auth_code] - }) - - headers = [ - {"Content-type", "application/json"}, - {"Accept", "application/json"} - ] - - request = Finch.build(:post, url, headers, body) - - with {:ok, response} <- Finch.request(request, MyFinch), - {:ok, %{"success" => true, "response" => plans} = body} <- JSON.decode(response.body) do - IO.puts("✅ Successfully fetched #{body["count"]}/#{body["total"]} sandbox plans") - plans - else - error -> - IO.puts("❌ Failed to fetch plans from Paddle - #{inspect(error)}") - System.halt(1) - end + [generation, type, kind, volume] |> Enum.join("_") end - defp create_local_sandbox_plans_json_file(prod_plans, filepath, paddle_plans) do + defp write_sandbox_plans_json_file(prod_plans, filepath, paddle_plans) do sandbox_plans = prod_plans |> Enum.map(fn prod_plan -> @@ -158,9 +154,11 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do "monthly_product_id" => to_string(sandbox_monthly_product_id), "yearly_product_id" => to_string(sandbox_yearly_product_id) }) + |> CreatePaddleProdPlans.order_keys() end) - File.write!(filepath, JSON.encode!(sandbox_plans)) + content = Jason.encode!(sandbox_plans, pretty: true) + File.write!(filepath, content) end defp put_prices(plans) do @@ -177,27 +175,4 @@ defmodule Mix.Tasks.CreatePaddleSandboxPlans do }) end) end - - defp plan_name(plan, type) do - generation = "v#{plan["generation"]}" - kind = plan["kind"] - volume = plan["monthly_pageview_limit"] |> PlausibleWeb.StatsView.large_number_format() - - [generation, type, kind, volume] |> Enum.join("_") - end - - defp curl_quietly(cmd) do - cmd = String.replace(cmd, "curl", ~s|curl -s -o /dev/null -w "%{http_code}"|) - - case System.cmd("sh", ["-c", cmd], stderr_to_stdout: true) do - {"302", 0} -> - :ok - - {http_status, 0} -> - {:error, "unexpected HTTP response status (#{http_status}). Expected 302."} - - {_, exit_code} -> - {:error, "curl command exited with exit code #{exit_code}"} - end - end end diff --git a/lib/plausible/billing/feature.ex b/lib/plausible/billing/feature.ex index f60ab21d3d..6e94ff25fb 100644 --- a/lib/plausible/billing/feature.ex +++ b/lib/plausible/billing/feature.ex @@ -72,6 +72,8 @@ defmodule Plausible.Billing.Feature do @features [ Plausible.Billing.Feature.Props, + Plausible.Billing.Feature.Teams, + Plausible.Billing.Feature.SharedLinks, Plausible.Billing.Feature.Funnels, Plausible.Billing.Feature.Goals, Plausible.Billing.Feature.RevenueGoals, @@ -198,6 +200,20 @@ defmodule Plausible.Billing.Feature.Props do toggle_field: :props_enabled end +defmodule Plausible.Billing.Feature.Teams do + @moduledoc false + use Plausible.Billing.Feature, + name: :teams, + display_name: "Team Accounts" +end + +defmodule Plausible.Billing.Feature.SharedLinks do + @moduledoc false + use Plausible.Billing.Feature, + name: :shared_links, + display_name: "Shared Links" +end + defmodule Plausible.Billing.Feature.SiteSegments do @moduledoc false use Plausible.Billing.Feature, diff --git a/lib/plausible_web/components/billing/plan_benefits.ex b/lib/plausible_web/components/billing/plan_benefits.ex index 3a2822d6ab..eedd191a29 100644 --- a/lib/plausible_web/components/billing/plan_benefits.ex +++ b/lib/plausible_web/components/billing/plan_benefits.ex @@ -114,6 +114,8 @@ defmodule PlausibleWeb.Components.Billing.PlanBenefits do Enum.flat_map(plan.features, fn feature_mod -> case feature_mod.name() do :goals -> ["Goals and custom events"] + :teams -> [] + :shared_links -> [] :stats_api -> ["Stats API (600 requests per hour)", "Looker Studio Connector"] :revenue_goals -> ["Ecommerce revenue attribution"] _ -> [feature_mod.display_name()] diff --git a/lib/plausible_web/plugins/api/schemas/capabilities.ex b/lib/plausible_web/plugins/api/schemas/capabilities.ex index 3b3c19c38a..527b817c7b 100644 --- a/lib/plausible_web/plugins/api/schemas/capabilities.ex +++ b/lib/plausible_web/plugins/api/schemas/capabilities.ex @@ -34,7 +34,9 @@ defmodule PlausibleWeb.Plugins.API.Schemas.Capabilities do RevenueGoals: false, StatsAPI: false, SitesAPI: false, - SiteSegments: false + SiteSegments: false, + Teams: false, + SharedLinks: false } } }) diff --git a/lib/plausible_web/views/stats_view.ex b/lib/plausible_web/views/stats_view.ex index f85c805cbe..bb24b1b6be 100644 --- a/lib/plausible_web/views/stats_view.ex +++ b/lib/plausible_web/views/stats_view.ex @@ -6,15 +6,17 @@ defmodule PlausibleWeb.StatsView do PlausibleWeb.Endpoint.url() end - def large_number_format(n) do + def large_number_format(n, opts \\ []) do + k = if Keyword.get(opts, :capitalize_k?, false), do: "K", else: "k" + cond do n >= 1_000 && n < 1_000_000 -> thousands = trunc(n / 100) / 10 if thousands == trunc(thousands) || n >= 100_000 do - "#{trunc(thousands)}k" + "#{trunc(thousands)}" <> k else - "#{thousands}k" + "#{thousands}" <> k end n >= 1_000_000 && n < 1_000_000_000 -> diff --git a/priv/plan_prices.json b/priv/plan_prices.json index 1427c8153b..505ee4fb6c 100644 --- a/priv/plan_prices.json +++ b/priv/plan_prices.json @@ -1,33 +1,31 @@ { - "558746": 36, - "590753": 288, - "648089": 4800, "558018": 6, - "572810": 48, "558745": 12, + "558746": 36, + "572810": 48, "590752": 96, + "590753": 288, + "597309": 69, + "597310": 552, + "597311": 99, + "597312": 792, "597485": 18, "597486": 144, "597487": 27, "597488": 216, "597642": 48, "597643": 384, - "597309": 69, - "597310": 552, - "597311": 99, - "597312": 792, "642352": 150, "642354": 1200, "642355": 225, "642356": 1800, + "648089": 4800, "650652": 330, "650653": 2640, - "654177": 6, "653232": 60, - "654178": 12, "653234": 120, - "653237": 20, "653236": 200, + "653237": 20, "653238": 30, "653239": 300, "653240": 50, @@ -36,12 +34,14 @@ "653254": 700, "653255": 100, "653256": 1000, - "654181": 150, "653257": 1500, - "654182": 225, "653258": 2250, - "654183": 330, "653259": 3300, + "654177": 6, + "654178": 12, + "654181": 150, + "654182": 225, + "654183": 330, "749342": 9, "749343": 90, "749344": 19, @@ -58,6 +58,38 @@ "749357": 1290, "749358": 169, "749359": 1690, + "857079": 90, + "857080": 190, + "857081": 290, + "857082": 490, + "857083": 690, + "857084": 890, + "857085": 1290, + "857086": 1690, + "857087": 190, + "857088": 390, + "857089": 590, + "857090": 990, + "857091": 1390, + "857092": 1790, + "857093": 2590, + "857094": 3390, + "857097": 9, + "857098": 19, + "857099": 29, + "857100": 49, + "857101": 69, + "857102": 89, + "857103": 129, + "857104": 169, + "857105": 19, + "857106": 39, + "857107": 59, + "857108": 99, + "857109": 139, + "857110": 179, + "857111": 259, + "857112": 339, "857481": 19, "857482": 190, "857483": 39, @@ -74,36 +106,52 @@ "857500": 2590, "857501": 339, "857502": 3390, - "857097": 9, - "857079": 90, - "857098": 19, - "857080": 190, - "857099": 29, - "857081": 290, - "857100": 49, - "857082": 490, - "857101": 69, - "857083": 690, - "857102": 89, - "857084": 890, - "857103": 129, - "857085": 1290, - "857104": 169, - "857086": 1690, - "857105": 19, - "857087": 190, - "857106": 39, - "857088": 390, - "857107": 59, - "857089": 590, - "857108": 99, - "857090": 990, - "857109": 139, - "857091": 1390, - "857110": 179, - "857092": 1790, - "857111": 259, - "857093": 2590, - "857112": 339, - "857094": 3390 + "910413": 9, + "910414": 90, + "910415": 19, + "910416": 190, + "910417": 29, + "910418": 290, + "910419": 49, + "910420": 490, + "910421": 69, + "910422": 690, + "910423": 89, + "910424": 890, + "910425": 129, + "910426": 1290, + "910427": 169, + "910428": 1690, + "910429": 14, + "910430": 140, + "910431": 29, + "910432": 290, + "910433": 44, + "910434": 440, + "910435": 74, + "910436": 740, + "910437": 104, + "910438": 1040, + "910439": 134, + "910440": 1340, + "910441": 194, + "910442": 1940, + "910443": 254, + "910444": 2540, + "910445": 19, + "910446": 190, + "910447": 39, + "910448": 390, + "910449": 59, + "910450": 590, + "910451": 99, + "910452": 990, + "910453": 139, + "910454": 1390, + "910455": 179, + "910456": 1790, + "910457": 259, + "910458": 2590, + "910459": 339, + "910460": 3390 } \ No newline at end of file diff --git a/priv/plans_v1.json b/priv/plans_v1.json index 0f38a2ee03..d55bbc60f5 100644 --- a/priv/plans_v1.json +++ b/priv/plans_v1.json @@ -1,102 +1,162 @@ [ { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":10000, - "monthly_product_id":"558018", - "yearly_product_id":"572810", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 10000, + "monthly_product_id": "558018", + "yearly_product_id": "572810", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":100000, - "monthly_product_id":"558745", - "yearly_product_id":"590752", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 100000, + "monthly_product_id": "558745", + "yearly_product_id": "590752", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":200000, - "monthly_product_id":"597485", - "yearly_product_id":"597486", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 200000, + "monthly_product_id": "597485", + "yearly_product_id": "597486", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":500000, - "monthly_product_id":"597487", - "yearly_product_id":"597488", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 500000, + "monthly_product_id": "597487", + "yearly_product_id": "597488", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":1000000, - "monthly_product_id":"597642", - "yearly_product_id":"597643", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "597642", + "yearly_product_id": "597643", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":2000000, - "monthly_product_id":"597309", - "yearly_product_id":"597310", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "597309", + "yearly_product_id": "597310", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":5000000, - "monthly_product_id":"597311", - "yearly_product_id":"597312", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "597311", + "yearly_product_id": "597312", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":10000000, - "monthly_product_id":"642352", - "yearly_product_id":"642354", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "642352", + "yearly_product_id": "642354", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":20000000, - "monthly_product_id":"642355", - "yearly_product_id":"642356", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 20000000, + "monthly_product_id": "642355", + "yearly_product_id": "642356", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":1, - "monthly_pageview_limit":50000000, - "monthly_product_id":"650652", - "yearly_product_id":"650653", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 1, + "monthly_pageview_limit": 50000000, + "monthly_product_id": "650652", + "yearly_product_id": "650653", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] } -] +] \ No newline at end of file diff --git a/priv/plans_v2.json b/priv/plans_v2.json index c1f8d4729f..61107f95e1 100644 --- a/priv/plans_v2.json +++ b/priv/plans_v2.json @@ -1,102 +1,162 @@ [ { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":10000, - "monthly_product_id":"654177", - "yearly_product_id":"653232", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 10000, + "monthly_product_id": "654177", + "yearly_product_id": "653232", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":100000, - "monthly_product_id":"654178", - "yearly_product_id":"653234", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 100000, + "monthly_product_id": "654178", + "yearly_product_id": "653234", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":200000, - "monthly_product_id":"653237", - "yearly_product_id":"653236", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 200000, + "monthly_product_id": "653237", + "yearly_product_id": "653236", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":500000, - "monthly_product_id":"653238", - "yearly_product_id":"653239", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 500000, + "monthly_product_id": "653238", + "yearly_product_id": "653239", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":1000000, - "monthly_product_id":"653240", - "yearly_product_id":"653242", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "653240", + "yearly_product_id": "653242", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":2000000, - "monthly_product_id":"653253", - "yearly_product_id":"653254", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "653253", + "yearly_product_id": "653254", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":5000000, - "monthly_product_id":"653255", - "yearly_product_id":"653256", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "653255", + "yearly_product_id": "653256", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":10000000, - "monthly_product_id":"654181", - "yearly_product_id":"653257", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "654181", + "yearly_product_id": "653257", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":20000000, - "monthly_product_id":"654182", - "yearly_product_id":"653258", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 20000000, + "monthly_product_id": "654182", + "yearly_product_id": "653258", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":2, - "monthly_pageview_limit":50000000, - "monthly_product_id":"654183", - "yearly_product_id":"653259", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 2, + "monthly_pageview_limit": 50000000, + "monthly_product_id": "654183", + "yearly_product_id": "653259", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] } -] +] \ No newline at end of file diff --git a/priv/plans_v3.json b/priv/plans_v3.json index 8e5618aea6..63a6a67103 100644 --- a/priv/plans_v3.json +++ b/priv/plans_v3.json @@ -1,162 +1,282 @@ [ { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":10000, - "monthly_product_id":"749342", - "yearly_product_id":"749343", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 10000, + "monthly_product_id": "749342", + "yearly_product_id": "749343", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":100000, - "monthly_product_id":"749344", - "yearly_product_id":"749345", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 100000, + "monthly_product_id": "749344", + "yearly_product_id": "749345", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":200000, - "monthly_product_id":"749346", - "yearly_product_id":"749347", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 200000, + "monthly_product_id": "749346", + "yearly_product_id": "749347", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":500000, - "monthly_product_id":"749348", - "yearly_product_id":"749349", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 500000, + "monthly_product_id": "749348", + "yearly_product_id": "749349", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":1000000, - "monthly_product_id":"749350", - "yearly_product_id":"749352", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "749350", + "yearly_product_id": "749352", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":2000000, - "monthly_product_id":"749353", - "yearly_product_id":"749355", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "749353", + "yearly_product_id": "749355", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":5000000, - "monthly_product_id":"749356", - "yearly_product_id":"749357", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "749356", + "yearly_product_id": "749357", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"growth", - "generation":3, - "monthly_pageview_limit":10000000, - "monthly_product_id":"749358", - "yearly_product_id":"749359", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","stats_api"] + "kind": "growth", + "generation": 3, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "749358", + "yearly_product_id": "749359", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":10000, - "monthly_product_id":"857481", - "yearly_product_id":"857482", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 10000, + "monthly_product_id": "857481", + "yearly_product_id": "857482", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":100000, - "monthly_product_id":"857483", - "yearly_product_id":"857484", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 100000, + "monthly_product_id": "857483", + "yearly_product_id": "857484", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":200000, - "monthly_product_id":"857486", - "yearly_product_id":"857487", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 200000, + "monthly_product_id": "857486", + "yearly_product_id": "857487", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":500000, - "monthly_product_id":"857490", - "yearly_product_id":"857491", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 500000, + "monthly_product_id": "857490", + "yearly_product_id": "857491", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":1000000, - "monthly_product_id":"857493", - "yearly_product_id":"857494", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "857493", + "yearly_product_id": "857494", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":2000000, - "monthly_product_id":"857495", - "yearly_product_id":"857496", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "857495", + "yearly_product_id": "857496", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":5000000, - "monthly_product_id":"857498", - "yearly_product_id":"857500", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "857498", + "yearly_product_id": "857500", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] }, { - "kind":"business", - "generation":3, - "monthly_pageview_limit":10000000, - "monthly_product_id":"857501", - "yearly_product_id":"857502", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"] + "kind": "business", + "generation": 3, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "857501", + "yearly_product_id": "857502", + "site_limit": 50, + "team_member_limit": "unlimited", + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] } -] +] \ No newline at end of file diff --git a/priv/plans_v4.json b/priv/plans_v4.json index ce6acde7ef..6a8f2f52d5 100644 --- a/priv/plans_v4.json +++ b/priv/plans_v4.json @@ -1,178 +1,282 @@ [ { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":10000, - "monthly_product_id":"857097", - "yearly_product_id":"857079", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 10000, + "monthly_product_id": "857097", + "yearly_product_id": "857079", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":100000, - "monthly_product_id":"857098", - "yearly_product_id":"857080", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 100000, + "monthly_product_id": "857098", + "yearly_product_id": "857080", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":200000, - "monthly_product_id":"857099", - "yearly_product_id":"857081", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 200000, + "monthly_product_id": "857099", + "yearly_product_id": "857081", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":500000, - "monthly_product_id":"857100", - "yearly_product_id":"857082", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 500000, + "monthly_product_id": "857100", + "yearly_product_id": "857082", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":1000000, - "monthly_product_id":"857101", - "yearly_product_id":"857083", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "857101", + "yearly_product_id": "857083", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":2000000, - "monthly_product_id":"857102", - "yearly_product_id":"857084", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "857102", + "yearly_product_id": "857084", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":5000000, - "monthly_product_id":"857103", - "yearly_product_id":"857085", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "857103", + "yearly_product_id": "857085", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":10000000, - "monthly_product_id":"857104", - "yearly_product_id":"857086", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "857104", + "yearly_product_id": "857086", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":10000, - "monthly_product_id":"857105", - "yearly_product_id":"857087", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 10000, + "monthly_product_id": "857105", + "yearly_product_id": "857087", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":100000, - "monthly_product_id":"857106", - "yearly_product_id":"857088", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 100000, + "monthly_product_id": "857106", + "yearly_product_id": "857088", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":200000, - "monthly_product_id":"857107", - "yearly_product_id":"857089", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 200000, + "monthly_product_id": "857107", + "yearly_product_id": "857089", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":500000, - "monthly_product_id":"857108", - "yearly_product_id":"857090", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 500000, + "monthly_product_id": "857108", + "yearly_product_id": "857090", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":1000000, - "monthly_product_id":"857109", - "yearly_product_id":"857091", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "857109", + "yearly_product_id": "857091", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":2000000, - "monthly_product_id":"857110", - "yearly_product_id":"857092", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "857110", + "yearly_product_id": "857092", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":5000000, - "monthly_product_id":"857111", - "yearly_product_id":"857093", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "857111", + "yearly_product_id": "857093", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":10000000, - "monthly_product_id":"857112", - "yearly_product_id":"857094", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "857112", + "yearly_product_id": "857094", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 } -] +] \ No newline at end of file diff --git a/priv/plans_v5.json b/priv/plans_v5.json new file mode 100644 index 0000000000..04c0b3da7f --- /dev/null +++ b/priv/plans_v5.json @@ -0,0 +1,394 @@ +[ + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "910413", + "yearly_product_id": "910414", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "910415", + "yearly_product_id": "910416", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "910417", + "yearly_product_id": "910418", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "910419", + "yearly_product_id": "910420", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "910421", + "yearly_product_id": "910422", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "910423", + "yearly_product_id": "910424", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "910425", + "yearly_product_id": "910426", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "910427", + "yearly_product_id": "910428", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "910429", + "yearly_product_id": "910430", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "910431", + "yearly_product_id": "910432", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "910433", + "yearly_product_id": "910434", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "910435", + "yearly_product_id": "910436", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "910437", + "yearly_product_id": "910438", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "910439", + "yearly_product_id": "910440", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "910441", + "yearly_product_id": "910442", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "910443", + "yearly_product_id": "910444", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "910445", + "yearly_product_id": "910446", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "910447", + "yearly_product_id": "910448", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "910449", + "yearly_product_id": "910450", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "910451", + "yearly_product_id": "910452", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "910453", + "yearly_product_id": "910454", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "910455", + "yearly_product_id": "910456", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "910457", + "yearly_product_id": "910458", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "910459", + "yearly_product_id": "910460", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + } +] \ No newline at end of file diff --git a/priv/sandbox_plans_v1.json b/priv/sandbox_plans_v1.json index f6de5b342d..c3d471442c 100644 --- a/priv/sandbox_plans_v1.json +++ b/priv/sandbox_plans_v1.json @@ -1,142 +1,162 @@ [ { - "features": [ - "goals", - "props", - "stats_api" - ], - "generation": 1, "kind": "growth", + "generation": 1, "monthly_pageview_limit": 10000, "monthly_product_id": "78008", + "yearly_product_id": "78009", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78009" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 100000, "monthly_product_id": "78010", + "yearly_product_id": "78011", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78011" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 200000, "monthly_product_id": "78012", + "yearly_product_id": "78013", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78013" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 500000, "monthly_product_id": "78014", + "yearly_product_id": "78015", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78015" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 1000000, "monthly_product_id": "78016", + "yearly_product_id": "78017", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78017" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 2000000, "monthly_product_id": "78018", + "yearly_product_id": "78019", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78019" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 5000000, "monthly_product_id": "78020", + "yearly_product_id": "78021", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78021" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 10000000, "monthly_product_id": "78022", + "yearly_product_id": "78023", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78023" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 20000000, "monthly_product_id": "78024", + "yearly_product_id": "78025", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78025" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 1, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 1, "monthly_pageview_limit": 50000000, "monthly_product_id": "78026", + "yearly_product_id": "78027", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78027" + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] } ] \ No newline at end of file diff --git a/priv/sandbox_plans_v2.json b/priv/sandbox_plans_v2.json index 38aaecb43b..c48ea0bf6d 100644 --- a/priv/sandbox_plans_v2.json +++ b/priv/sandbox_plans_v2.json @@ -1,142 +1,162 @@ [ { - "features": [ - "goals", - "props", - "stats_api" - ], - "generation": 2, "kind": "growth", + "generation": 2, "monthly_pageview_limit": 10000, "monthly_product_id": "78053", + "yearly_product_id": "78054", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78054" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 100000, "monthly_product_id": "78055", + "yearly_product_id": "78056", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78056" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 200000, "monthly_product_id": "78057", + "yearly_product_id": "78058", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78058" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 500000, "monthly_product_id": "78059", + "yearly_product_id": "78060", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78060" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 1000000, "monthly_product_id": "78061", + "yearly_product_id": "78062", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78062" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 2000000, "monthly_product_id": "78063", + "yearly_product_id": "78064", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78064" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 5000000, "monthly_product_id": "78065", + "yearly_product_id": "78066", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78066" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 10000000, "monthly_product_id": "78067", + "yearly_product_id": "78068", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78068" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 20000000, "monthly_product_id": "78069", + "yearly_product_id": "78070", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78070" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 2, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 2, "monthly_pageview_limit": 50000000, "monthly_product_id": "78071", + "yearly_product_id": "78072", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78072" + "features": [ + "goals", + "props", + "stats_api", + "teams", + "shared_links" + ] } ] \ No newline at end of file diff --git a/priv/sandbox_plans_v3.json b/priv/sandbox_plans_v3.json index c57cb2600e..6f83ef8f12 100644 --- a/priv/sandbox_plans_v3.json +++ b/priv/sandbox_plans_v3.json @@ -1,250 +1,282 @@ [ { - "features": [ - "goals", - "props", - "stats_api" - ], - "generation": 3, "kind": "growth", + "generation": 3, "monthly_pageview_limit": 10000, "monthly_product_id": "78073", + "yearly_product_id": "78074", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78074" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 100000, "monthly_product_id": "78075", + "yearly_product_id": "78076", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78076" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 200000, "monthly_product_id": "78077", + "yearly_product_id": "78078", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78078" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 500000, "monthly_product_id": "78079", + "yearly_product_id": "78080", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78080" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 1000000, "monthly_product_id": "78081", + "yearly_product_id": "78082", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78082" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 2000000, "monthly_product_id": "78083", + "yearly_product_id": "78084", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78084" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 5000000, "monthly_product_id": "78085", + "yearly_product_id": "78086", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78086" - }, - { "features": [ "goals", "props", - "stats_api" - ], - "generation": 3, + "stats_api", + "teams", + "shared_links" + ] + }, + { "kind": "growth", + "generation": 3, "monthly_pageview_limit": 10000000, "monthly_product_id": "78087", + "yearly_product_id": "78088", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78088" - }, - { "features": [ "goals", "props", - "revenue_goals", - "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 10000, "monthly_product_id": "78089", + "yearly_product_id": "78090", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78090" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 100000, "monthly_product_id": "78091", + "yearly_product_id": "78092", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78092" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 200000, "monthly_product_id": "78093", + "yearly_product_id": "78094", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78094" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 500000, "monthly_product_id": "78095", + "yearly_product_id": "78096", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78096" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 1000000, "monthly_product_id": "78097", + "yearly_product_id": "78098", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78098" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 2000000, "monthly_product_id": "78099", + "yearly_product_id": "78100", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78100" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 5000000, "monthly_product_id": "78101", + "yearly_product_id": "78102", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78102" - }, - { "features": [ "goals", "props", "revenue_goals", "funnels", "stats_api", - "site_segments" - ], - "generation": 3, + "site_segments", + "teams", + "shared_links" + ] + }, + { "kind": "business", + "generation": 3, "monthly_pageview_limit": 10000000, "monthly_product_id": "78107", + "yearly_product_id": "78109", "site_limit": 50, "team_member_limit": "unlimited", - "yearly_product_id": "78109" + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ] } ] \ No newline at end of file diff --git a/priv/sandbox_plans_v4.json b/priv/sandbox_plans_v4.json index 3126190f42..fe4ae130e8 100644 --- a/priv/sandbox_plans_v4.json +++ b/priv/sandbox_plans_v4.json @@ -1,178 +1,282 @@ [ { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":10000, - "monthly_product_id":"63842", - "yearly_product_id":"63859", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 10000, + "monthly_product_id": "63842", + "yearly_product_id": "63859", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":100000, - "monthly_product_id":"63843", - "yearly_product_id":"63860", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 100000, + "monthly_product_id": "63843", + "yearly_product_id": "63860", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":200000, - "monthly_product_id":"63844", - "yearly_product_id":"63861", - "site_limit":50, - "team_member_limit":"unlimited", - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 200000, + "monthly_product_id": "63844", + "yearly_product_id": "63861", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":500000, - "monthly_product_id":"63845", - "yearly_product_id":"63862", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 500000, + "monthly_product_id": "63845", + "yearly_product_id": "63862", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":1000000, - "monthly_product_id":"63846", - "yearly_product_id":"63863", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "63846", + "yearly_product_id": "63863", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":2000000, - "monthly_product_id":"63847", - "yearly_product_id":"63864", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "63847", + "yearly_product_id": "63864", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":5000000, - "monthly_product_id":"63848", - "yearly_product_id":"63865", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "63848", + "yearly_product_id": "63865", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"growth", - "generation":4, - "monthly_pageview_limit":10000000, - "monthly_product_id":"63849", - "yearly_product_id":"63866", - "site_limit":10, - "team_member_limit":3, - "features":["goals"], + "kind": "growth", + "generation": 4, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "63849", + "yearly_product_id": "63866", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "teams", + "shared_links" + ], "data_retention_in_years": 3 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":10000, - "monthly_product_id":"63850", - "yearly_product_id":"63867", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 10000, + "monthly_product_id": "63850", + "yearly_product_id": "63867", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":100000, - "monthly_product_id":"63851", - "yearly_product_id":"63868", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 100000, + "monthly_product_id": "63851", + "yearly_product_id": "63868", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":200000, - "monthly_product_id":"63852", - "yearly_product_id":"63869", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 200000, + "monthly_product_id": "63852", + "yearly_product_id": "63869", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":500000, - "monthly_product_id":"63853", - "yearly_product_id":"63870", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 500000, + "monthly_product_id": "63853", + "yearly_product_id": "63870", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":1000000, - "monthly_product_id":"63854", - "yearly_product_id":"63871", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "63854", + "yearly_product_id": "63871", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":2000000, - "monthly_product_id":"63855", - "yearly_product_id":"63872", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "63855", + "yearly_product_id": "63872", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":5000000, - "monthly_product_id":"63856", - "yearly_product_id":"63873", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "63856", + "yearly_product_id": "63873", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 }, { - "kind":"business", - "generation":4, - "monthly_pageview_limit":10000000, - "monthly_product_id":"63857", - "yearly_product_id":"63874", - "site_limit":50, - "team_member_limit":10, - "features":["goals","props","revenue_goals","funnels","stats_api","site_segments"], + "kind": "business", + "generation": 4, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "63857", + "yearly_product_id": "63874", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "revenue_goals", + "funnels", + "stats_api", + "site_segments", + "teams", + "shared_links" + ], "data_retention_in_years": 5 } -] +] \ No newline at end of file diff --git a/priv/sandbox_plans_v5.json b/priv/sandbox_plans_v5.json new file mode 100644 index 0000000000..4cfc02be18 --- /dev/null +++ b/priv/sandbox_plans_v5.json @@ -0,0 +1,394 @@ +[ + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "78943", + "yearly_product_id": "78944", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "78945", + "yearly_product_id": "78946", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "78947", + "yearly_product_id": "78948", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "78949", + "yearly_product_id": "78950", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "78951", + "yearly_product_id": "78952", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "78953", + "yearly_product_id": "78954", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "78955", + "yearly_product_id": "78956", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "starter", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "78957", + "yearly_product_id": "78958", + "site_limit": 3, + "team_member_limit": 1, + "features": [ + "goals" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "78959", + "yearly_product_id": "78960", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "78961", + "yearly_product_id": "78962", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "78963", + "yearly_product_id": "78964", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "78965", + "yearly_product_id": "78966", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "78967", + "yearly_product_id": "78968", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "78969", + "yearly_product_id": "78970", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "78971", + "yearly_product_id": "78972", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "growth", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "78973", + "yearly_product_id": "78974", + "site_limit": 10, + "team_member_limit": 3, + "features": [ + "goals", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 3 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 10000, + "monthly_product_id": "78975", + "yearly_product_id": "78976", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 100000, + "monthly_product_id": "78977", + "yearly_product_id": "78978", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 200000, + "monthly_product_id": "78979", + "yearly_product_id": "78980", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 500000, + "monthly_product_id": "78981", + "yearly_product_id": "78982", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 1000000, + "monthly_product_id": "78983", + "yearly_product_id": "78984", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 2000000, + "monthly_product_id": "78985", + "yearly_product_id": "78986", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 5000000, + "monthly_product_id": "78987", + "yearly_product_id": "78988", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + }, + { + "kind": "business", + "generation": 5, + "monthly_pageview_limit": 10000000, + "monthly_product_id": "78989", + "yearly_product_id": "78990", + "site_limit": 50, + "team_member_limit": 10, + "features": [ + "goals", + "props", + "stats_api", + "revenue_goals", + "funnels", + "site_segments", + "teams", + "shared_links" + ], + "data_retention_in_years": 5 + } +] \ No newline at end of file diff --git a/test/plausible/billing/quota_test.exs b/test/plausible/billing/quota_test.exs index 7020f13b1f..5667632fc1 100644 --- a/test/plausible/billing/quota_test.exs +++ b/test/plausible/billing/quota_test.exs @@ -3,7 +3,7 @@ defmodule Plausible.Billing.QuotaTest do use Plausible.DataCase, async: true use Plausible alias Plausible.Billing.{Quota, Plans} - alias Plausible.Billing.Feature.{Goals, Props, SitesAPI, StatsAPI} + alias Plausible.Billing.Feature.{Goals, Props, SitesAPI, StatsAPI, Teams, SharedLinks} use Plausible.Teams.Test @@ -581,9 +581,14 @@ defmodule Plausible.Billing.QuotaTest do team_on_v2 = new_user() |> subscribe_to_plan(@v2_plan_id) |> team_of() team_on_v3 = new_user() |> subscribe_to_plan(@v3_plan_id) |> team_of() - assert [Goals, Props, StatsAPI] == Plausible.Teams.Billing.allowed_features_for(team_on_v1) - assert [Goals, Props, StatsAPI] == Plausible.Teams.Billing.allowed_features_for(team_on_v2) - assert [Goals, Props, StatsAPI] == Plausible.Teams.Billing.allowed_features_for(team_on_v3) + assert [Goals, Props, StatsAPI, Teams, SharedLinks] == + Plausible.Teams.Billing.allowed_features_for(team_on_v1) + + assert [Goals, Props, StatsAPI, Teams, SharedLinks] == + Plausible.Teams.Billing.allowed_features_for(team_on_v2) + + assert [Goals, Props, StatsAPI, Teams, SharedLinks] == + Plausible.Teams.Billing.allowed_features_for(team_on_v3) end test "returns [Goals, Props, StatsAPI] when user is on free_10k plan" do @@ -625,7 +630,8 @@ defmodule Plausible.Billing.QuotaTest do team = team_of(user) - assert [Goals, Props, StatsAPI] == Plausible.Teams.Billing.allowed_features_for(team) + assert [Goals, Props, StatsAPI, Teams, SharedLinks] == + Plausible.Teams.Billing.allowed_features_for(team) end test "returns all features for enterprise users who have not upgraded yet and are on trial" do diff --git a/test/plausible_web/controllers/admin_controller_test.exs b/test/plausible_web/controllers/admin_controller_test.exs index 2e16f5955e..7a4c56d0b9 100644 --- a/test/plausible_web/controllers/admin_controller_test.exs +++ b/test/plausible_web/controllers/admin_controller_test.exs @@ -263,7 +263,7 @@ defmodule PlausibleWeb.AdminControllerTest do conn = get(conn, "/crm/billing/team/#{team.id}/current_plan") assert json_response(conn, 200) == %{ - "features" => ["goals"], + "features" => ["goals", "teams", "shared_links"], "monthly_pageview_limit" => 10_000_000, "site_limit" => 10, "team_member_limit" => 3 diff --git a/test/plausible_web/plugins/api/controllers/capabilities_test.exs b/test/plausible_web/plugins/api/controllers/capabilities_test.exs index 59a2804100..3fb87b6796 100644 --- a/test/plausible_web/plugins/api/controllers/capabilities_test.exs +++ b/test/plausible_web/plugins/api/controllers/capabilities_test.exs @@ -31,7 +31,9 @@ defmodule PlausibleWeb.Plugins.API.Controllers.CapabilitiesTest do "RevenueGoals" => false, "StatsAPI" => false, "SitesAPI" => false, - "SiteSegments" => false + "SiteSegments" => false, + "Teams" => false, + "SharedLinks" => false } } @@ -57,7 +59,9 @@ defmodule PlausibleWeb.Plugins.API.Controllers.CapabilitiesTest do "RevenueGoals" => false, "StatsAPI" => false, "SitesAPI" => false, - "SiteSegments" => false + "SiteSegments" => false, + "Teams" => false, + "SharedLinks" => false } } @@ -85,7 +89,9 @@ defmodule PlausibleWeb.Plugins.API.Controllers.CapabilitiesTest do "RevenueGoals" => true, "StatsAPI" => true, "SitesAPI" => false, - "SiteSegments" => true + "SiteSegments" => true, + "Teams" => true, + "SharedLinks" => true } } @@ -115,7 +121,9 @@ defmodule PlausibleWeb.Plugins.API.Controllers.CapabilitiesTest do "RevenueGoals" => false, "StatsAPI" => false, "SitesAPI" => false, - "SiteSegments" => false + "SiteSegments" => false, + "Teams" => true, + "SharedLinks" => true } } @@ -148,7 +156,9 @@ defmodule PlausibleWeb.Plugins.API.Controllers.CapabilitiesTest do "RevenueGoals" => false, "StatsAPI" => true, "SitesAPI" => true, - "SiteSegments" => false + "SiteSegments" => false, + "Teams" => false, + "SharedLinks" => false } }