mirror of
https://github.com/plausible/analytics.git
synced 2024-12-22 17:11:36 +03:00
Refactor current plan data format to make changing it easier
This commit is contained in:
parent
09df65d5ec
commit
885b1d271a
@ -7,6 +7,8 @@
|
||||
@import "tooltip.css";
|
||||
@import "flatpickr.css";
|
||||
|
||||
[x-cloak] { display: none; }
|
||||
|
||||
.button {
|
||||
@apply inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md leading-5 transition hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500;
|
||||
}
|
||||
|
@ -1,80 +1,93 @@
|
||||
defmodule Plausible.Billing.Plans do
|
||||
@monthly_plans [
|
||||
%{product_id: "558018", cost: "$6", limit: 10_000, cycle: "monthly"},
|
||||
%{product_id: "558745", cost: "$12", limit: 100_000, cycle: "monthly"},
|
||||
%{product_id: "597485", cost: "$18", limit: 200_000, cycle: "monthly"},
|
||||
%{product_id: "597487", cost: "$27", limit: 500_000, cycle: "monthly"},
|
||||
%{product_id: "597642", cost: "$48", limit: 1_000_000, cycle: "monthly"},
|
||||
%{product_id: "597309", cost: "$69", limit: 2_000_000, cycle: "monthly"},
|
||||
%{product_id: "597311", cost: "$99", limit: 5_000_000, cycle: "monthly"},
|
||||
%{product_id: "642352", cost: "$150", limit: 10_000_000, cycle: "monthly"},
|
||||
%{product_id: "642355", cost: "$225", limit: 20_000_000, cycle: "monthly"},
|
||||
%{product_id: "650652", cost: "$330", limit: 50_000_000, cycle: "monthly"}
|
||||
]
|
||||
|
||||
@yearly_plans [
|
||||
%{product_id: "572810", cost: "$48", monthly_cost: "$4", limit: 10_000, cycle: "yearly"},
|
||||
%{product_id: "590752", cost: "$96", monthly_cost: "$8", limit: 100_000, cycle: "yearly"},
|
||||
%{product_id: "597486", cost: "$144", monthly_cost: "$12", limit: 200_000, cycle: "yearly"},
|
||||
%{product_id: "597488", cost: "$216", monthly_cost: "$18", limit: 500_000, cycle: "yearly"},
|
||||
%{product_id: "597643", cost: "$384", monthly_cost: "$32", limit: 1_000_000, cycle: "yearly"},
|
||||
%{product_id: "597310", cost: "$552", monthly_cost: "$46", limit: 2_000_000, cycle: "yearly"},
|
||||
%{product_id: "597312", cost: "$792", monthly_cost: "$66", limit: 5_000_000, cycle: "yearly"},
|
||||
@plans_v1 [
|
||||
%{
|
||||
limit: 10_000,
|
||||
monthly_product_id: "558018",
|
||||
monthly_cost: "$6",
|
||||
yearly_product_id: "572810",
|
||||
yearly_cost: "$48"
|
||||
},
|
||||
%{
|
||||
limit: 100_000,
|
||||
monthly_product_id: "558745",
|
||||
monthly_cost: "$12",
|
||||
yearly_product_id: "590752",
|
||||
yearly_cost: "$96"
|
||||
},
|
||||
%{
|
||||
limit: 200_000,
|
||||
monthly_product_id: "597485",
|
||||
monthly_cost: "$18",
|
||||
yearly_product_id: "597486",
|
||||
yearly_cost: "$144"
|
||||
},
|
||||
%{
|
||||
limit: 500_000,
|
||||
monthly_product_id: "597487",
|
||||
monthly_cost: "$27",
|
||||
yearly_product_id: "597488",
|
||||
yearly_cost: "$216"
|
||||
},
|
||||
%{
|
||||
limit: 1_000_000,
|
||||
monthly_product_id: "597642",
|
||||
monthly_cost: "$48",
|
||||
yearly_product_id: "597643",
|
||||
yearly_cost: "$384"
|
||||
},
|
||||
%{
|
||||
limit: 2_000_000,
|
||||
monthly_product_id: "597309",
|
||||
monthly_cost: "$69",
|
||||
yearly_product_id: "597310",
|
||||
yearly_cost: "$552"
|
||||
},
|
||||
%{
|
||||
limit: 5_000_000,
|
||||
monthly_product_id: "597311",
|
||||
monthly_cost: "$99",
|
||||
yearly_product_id: "597312",
|
||||
yearly_cost: "$792"
|
||||
},
|
||||
%{
|
||||
product_id: "642354",
|
||||
cost: "$1200",
|
||||
monthly_cost: "$100",
|
||||
limit: 10_000_000,
|
||||
cycle: "yearly"
|
||||
},
|
||||
%{
|
||||
product_id: "642356",
|
||||
cost: "$1800",
|
||||
monthly_product_id: "642352",
|
||||
monthly_cost: "$150",
|
||||
yearly_product_id: "642354",
|
||||
yearly_cost: "$1200"
|
||||
},
|
||||
%{
|
||||
limit: 20_000_000,
|
||||
cycle: "yearly"
|
||||
monthly_product_id: "642355",
|
||||
monthly_cost: "$225",
|
||||
yearly_product_id: "642356",
|
||||
yearly_cost: "$1800"
|
||||
},
|
||||
%{
|
||||
product_id: "650653",
|
||||
cost: "$2640",
|
||||
monthly_cost: "$220",
|
||||
limit: 50_000_000,
|
||||
cycle: "yearly"
|
||||
},
|
||||
%{
|
||||
product_id: "648089",
|
||||
cost: "$4800",
|
||||
monthly_cost: "$400",
|
||||
limit: 150_000_000,
|
||||
cycle: "yearly"
|
||||
monthly_product_id: "650652",
|
||||
monthly_cost: "$330",
|
||||
yearly_product_id: "650653",
|
||||
yearly_cost: "$2640"
|
||||
}
|
||||
]
|
||||
|
||||
@all_plans @monthly_plans ++ @yearly_plans
|
||||
@yearly_plans_v1 [
|
||||
%{limit: 150_000_000, yearly_product_id: "648089", yearly_cost: "$4800"}
|
||||
]
|
||||
|
||||
def plans do
|
||||
monthly =
|
||||
@monthly_plans
|
||||
|> Enum.map(fn plan -> {String.to_atom(number_format(plan[:limit])), plan} end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
yearly =
|
||||
@yearly_plans
|
||||
|> Enum.map(fn plan -> {String.to_atom(number_format(plan[:limit])), plan} end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
%{
|
||||
monthly: monthly,
|
||||
yearly: yearly
|
||||
}
|
||||
def plans_for(user) do
|
||||
@plans_v1 |> Enum.map(fn plan -> Map.put(plan, :volume, number_format(plan[:limit])) end)
|
||||
end
|
||||
|
||||
def yearly_plan_ids do
|
||||
Enum.map(@yearly_plans, fn plan -> plan[:product_id] end)
|
||||
def all_yearly_plan_ids do
|
||||
Enum.map(@plans_v1, fn plan -> plan[:yearly_product_id] end)
|
||||
end
|
||||
|
||||
def for_product_id(product_id) do
|
||||
Enum.find(@all_plans, fn plan -> plan[:product_id] == product_id end)
|
||||
Enum.find(@plans_v1, fn plan ->
|
||||
product_id in [plan[:monthly_product_id], plan[:yearly_product_id]]
|
||||
end)
|
||||
end
|
||||
|
||||
def subscription_quota("free_10k"), do: "10k"
|
||||
@ -90,38 +103,32 @@ defmodule Plausible.Billing.Plans do
|
||||
|
||||
def subscription_interval(product_id) do
|
||||
case for_product_id(product_id) do
|
||||
nil -> raise "Unknown interval for subscription #{product_id}"
|
||||
product -> product[:cycle]
|
||||
nil ->
|
||||
raise "Unknown interval for subscription #{product_id}"
|
||||
|
||||
plan ->
|
||||
if product_id == plan[:monthly_product_id] do
|
||||
"monthly"
|
||||
else
|
||||
"yearly"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def suggested_plan_name(usage) do
|
||||
plan = suggested_plan(usage)
|
||||
number_format(plan[:limit]) <> "/mo"
|
||||
end
|
||||
|
||||
def suggested_plan_cost(usage) do
|
||||
plan = suggested_plan(usage)
|
||||
plan[:cost] <> "/mo"
|
||||
end
|
||||
|
||||
def suggested_plan_cost_yearly(usage) do
|
||||
plan = Enum.find(@yearly_plans, fn plan -> usage < plan[:limit] end)
|
||||
plan[:monthly_cost] <> "/mo"
|
||||
end
|
||||
|
||||
defp suggested_plan(usage) do
|
||||
Enum.find(@monthly_plans, fn plan -> usage < plan[:limit] end)
|
||||
end
|
||||
def allowance(%Plausible.Billing.Subscription{paddle_plan_id: "free_10k"}), do: 10_000
|
||||
|
||||
def allowance(subscription) do
|
||||
found = Enum.find(@all_plans, fn plan -> plan[:product_id] == subscription.paddle_plan_id end)
|
||||
found = for_product_id(subscription.paddle_plan_id)
|
||||
|
||||
if found do
|
||||
Map.fetch!(found, :limit)
|
||||
end
|
||||
end
|
||||
|
||||
def suggested_plan(user, usage) do
|
||||
Enum.find(plans_for(user), fn plan -> usage < plan[:limit] end)
|
||||
end
|
||||
|
||||
defp number_format(num) do
|
||||
PlausibleWeb.StatsView.large_number_format(num)
|
||||
end
|
||||
|
@ -71,6 +71,8 @@ defmodule PlausibleWeb.Email do
|
||||
end
|
||||
|
||||
def trial_upgrade_email(user, day, {pageviews, custom_events}) do
|
||||
suggested_plan = Plausible.Billing.Plans.suggested_plan(user, pageviews + custom_events)
|
||||
|
||||
base_email()
|
||||
|> to(user)
|
||||
|> tag("trial-upgrade-email")
|
||||
@ -79,7 +81,8 @@ defmodule PlausibleWeb.Email do
|
||||
user: user,
|
||||
day: day,
|
||||
custom_events: custom_events,
|
||||
usage: pageviews + custom_events
|
||||
usage: pageviews + custom_events,
|
||||
suggested_plan: suggested_plan
|
||||
)
|
||||
end
|
||||
|
||||
@ -112,7 +115,7 @@ defmodule PlausibleWeb.Email do
|
||||
})
|
||||
end
|
||||
|
||||
def over_limit_email(user, usage, last_cycle) do
|
||||
def over_limit_email(user, usage, last_cycle, suggested_plan) do
|
||||
base_email()
|
||||
|> to(user)
|
||||
|> tag("over-limit")
|
||||
@ -120,7 +123,8 @@ defmodule PlausibleWeb.Email do
|
||||
|> render("over_limit.html", %{
|
||||
user: user,
|
||||
usage: usage,
|
||||
last_cycle: last_cycle
|
||||
last_cycle: last_cycle,
|
||||
suggested_plan: suggested_plan
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<tr @click="volume = '<%= @volume %>'" :class="{'border-2 border-green-300 bg-opacity-20 bg-green-300': volume === '<%= @volume %>', 'border-b border-gray-200 cursor-pointer': volume !== '<%= @volume %>'}">
|
||||
<td class="px-6 py-4 text-sm leading-5 dark:text-gray-100" :class="{'font-bold': volume === '<%= @volume %>'}"><%= @volume %></td>
|
||||
<td class="px-6 py-4 text-sm leading-5 dark:text-gray-100" :class="{'font-bold': volume === '<%= @volume %>'}">
|
||||
<span x-show="billingCycle === 'monthly'"><%= @monthly_price %></span>
|
||||
<span x-show="billingCycle === 'yearly'"><%= @yearly_price %></span>
|
||||
<span x-show="billingCycle === 'monthly'"><%= @monthly_price %> / mo</span>
|
||||
<span x-show="billingCycle === 'yearly'"><%= @yearly_price %> / yr</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -1,5 +1,27 @@
|
||||
<script>
|
||||
window.plans = <%= raw Jason.encode!(Plausible.Billing.Plans.plans()) %>
|
||||
window.plans = function() {
|
||||
return {
|
||||
rawPlans: <%= raw Jason.encode!(Plausible.Billing.Plans.plans_for(@conn.assigns[:current_user])) %>,
|
||||
volume: '10k',
|
||||
billingCycle: 'monthly',
|
||||
selectedPlanPrice() {
|
||||
var selectedPlan = this.rawPlans.find((plan) => plan.volume === this.volume)
|
||||
if (this.billingCycle === 'monthly'){
|
||||
return selectedPlan.monthly_cost
|
||||
} else {
|
||||
return selectedPlan.yearly_cost
|
||||
}
|
||||
},
|
||||
selectedPlanProductId() {
|
||||
var selectedPlan = this.rawPlans.find((plan) => plan.volume === this.volume)
|
||||
if (this.billingCycle === 'monthly'){
|
||||
return selectedPlan.monthly_product_id
|
||||
} else {
|
||||
return selectedPlan.yearly_product_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto mt-6 text-center">
|
||||
@ -7,7 +29,7 @@
|
||||
</div>
|
||||
|
||||
<div class="w-full max-w-lg px-4 mx-auto mt-4">
|
||||
<div x-data="{volume: '10k', billingCycle: 'monthly'}" class="flex-1 px-8 py-4 mt-8 mb-4 bg-white rounded shadow-md dark:bg-gray-800">
|
||||
<div x-data="window.plans()" class="flex-1 px-8 py-4 mt-8 mb-4 bg-white rounded shadow-md dark:bg-gray-800">
|
||||
<div class="w-full pt-2 text-xl font-bold dark:text-gray-100">
|
||||
Select your new plan
|
||||
</div>
|
||||
@ -48,15 +70,9 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white dark:bg-gray-800">
|
||||
<%= render("_plan_option.html", volume: "10k", monthly_price: "$6", yearly_price: "$4") %>
|
||||
<%= render("_plan_option.html", volume: "100k", monthly_price: "$12", yearly_price: "$8") %>
|
||||
<%= render("_plan_option.html", volume: "200k", monthly_price: "$18", yearly_price: "$12") %>
|
||||
<%= render("_plan_option.html", volume: "500k", monthly_price: "$27", yearly_price: "$18") %>
|
||||
<%= render("_plan_option.html", volume: "1M", monthly_price: "$48", yearly_price: "$32") %>
|
||||
<%= render("_plan_option.html", volume: "2M", monthly_price: "$69", yearly_price: "$46") %>
|
||||
<%= render("_plan_option.html", volume: "5M", monthly_price: "$99", yearly_price: "$69") %>
|
||||
<%= render("_plan_option.html", volume: "10M", monthly_price: "$150", yearly_price: "$100") %>
|
||||
<%= render("_plan_option.html", volume: "20M", monthly_price: "$225", yearly_price: "$150") %>
|
||||
<%= for plan <- Plausible.Billing.Plans.plans_for(@conn.assigns[:current_user]) do %>
|
||||
<%= render("_plan_option.html", volume: PlausibleWeb.StatsView.large_number_format(plan[:limit]), monthly_price: plan[:monthly_cost], yearly_price: plan[:yearly_cost]) %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -65,12 +81,12 @@
|
||||
|
||||
<div class="mt-6 text-right">
|
||||
<span class="inline-flex rounded-md shadow-sm">
|
||||
<a x-show="window.plans[billingCycle][volume].product_id !== '<%= @subscription.paddle_plan_id %>'" style="display: none;" :href="'/billing/change-plan/preview/' + window.plans[billingCycle][volume].product_id" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<a x-show="selectedPlanProductId() !== '<%= @subscription.paddle_plan_id %>'" style="display: none;" :href="'/billing/change-plan/preview/' + selectedPlanProductId()" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<svg fill="currentColor" viewBox="0 0 20 20" class="inline w-4 h-4 mr-2"><path d="M10 12a2 2 0 100-4 2 2 0 000 4z"></path><path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"></path></svg>
|
||||
Preview changes
|
||||
</a>
|
||||
|
||||
<a x-show="window.plans[billingCycle][volume].product_id === '<%= @subscription.paddle_plan_id %>'" style="display: none;" tooltip="Select a different plan to continue" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-gray-400 border border-transparent leading-5 rounded-md">
|
||||
<a x-show="selectedPlanProductId() === '<%= @subscription.paddle_plan_id %>'" style="display: none;" tooltip="Select a different plan to continue" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-gray-400 border border-transparent leading-5 rounded-md">
|
||||
<svg fill="currentColor" viewBox="0 0 20 20" class="inline w-4 h-4 mr-2"><path d="M10 12a2 2 0 100-4 2 2 0 000 4z"></path><path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"></path></svg>
|
||||
Preview changes
|
||||
</a>
|
||||
|
@ -1,5 +1,27 @@
|
||||
<script>
|
||||
window.plans = <%= raw Jason.encode!(Plausible.Billing.Plans.plans()) %>
|
||||
window.plans = function() {
|
||||
return {
|
||||
rawPlans: <%= raw Jason.encode!(Plausible.Billing.Plans.plans_for(@user)) %>,
|
||||
volume: '10k',
|
||||
billingCycle: 'monthly',
|
||||
selectedPlanPrice() {
|
||||
var selectedPlan = this.rawPlans.find((plan) => plan.volume === this.volume)
|
||||
if (this.billingCycle === 'monthly'){
|
||||
return selectedPlan.monthly_cost
|
||||
} else {
|
||||
return selectedPlan.yearly_cost
|
||||
}
|
||||
},
|
||||
selectedPlanProductId() {
|
||||
var selectedPlan = this.rawPlans.find((plan) => plan.volume === this.volume)
|
||||
if (this.billingCycle === 'monthly'){
|
||||
return selectedPlan.monthly_product_id
|
||||
} else {
|
||||
return selectedPlan.yearly_product_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto mt-6 text-center">
|
||||
@ -8,7 +30,7 @@
|
||||
|
||||
<div>
|
||||
<div class="flex flex-col w-full max-w-4xl px-4 mx-auto mt-4 md:flex-row">
|
||||
<div x-data="{volume: '10k', billingCycle: 'monthly'}" class="flex-1 px-8 py-4 mt-8 mb-4 bg-white rounded shadow-md dark:bg-gray-800">
|
||||
<div x-data="window.plans()" class="flex-1 px-8 py-4 mt-8 mb-4 bg-white rounded shadow-md dark:bg-gray-800">
|
||||
<div class="w-full py-4 dark:text-gray-100">
|
||||
<span>You've used <b><%= PlausibleWeb.AuthView.delimit_integer(@usage) %></b> billable pageviews in the last 30 days</span>
|
||||
</div>
|
||||
@ -39,20 +61,14 @@
|
||||
Monthly pageviews
|
||||
</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase bg-gray-100 border-b border-gray-200 dark:bg-gray-900 leading-4 dark:text-gray-200">
|
||||
Price per month
|
||||
Price
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white dark:bg-gray-800">
|
||||
<%= render("_plan_option.html", volume: "10k", monthly_price: "$6", yearly_price: "$4") %>
|
||||
<%= render("_plan_option.html", volume: "100k", monthly_price: "$12", yearly_price: "$8") %>
|
||||
<%= render("_plan_option.html", volume: "200k", monthly_price: "$18", yearly_price: "$12") %>
|
||||
<%= render("_plan_option.html", volume: "500k", monthly_price: "$27", yearly_price: "$18") %>
|
||||
<%= render("_plan_option.html", volume: "1M", monthly_price: "$48", yearly_price: "$32") %>
|
||||
<%= render("_plan_option.html", volume: "2M", monthly_price: "$69", yearly_price: "$46") %>
|
||||
<%= render("_plan_option.html", volume: "5M", monthly_price: "$99", yearly_price: "$69") %>
|
||||
<%= render("_plan_option.html", volume: "10M", monthly_price: "$150", yearly_price: "$100") %>
|
||||
<%= render("_plan_option.html", volume: "20M", monthly_price: "$225", yearly_price: "$150") %>
|
||||
<%= for plan <- Plausible.Billing.Plans.plans_for(@user) do %>
|
||||
<%= render("_plan_option.html", volume: PlausibleWeb.StatsView.large_number_format(plan[:limit]), monthly_price: plan[:monthly_cost], yearly_price: plan[:yearly_cost]) %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -60,9 +76,9 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-right">
|
||||
<div class="mb-4 text-sm font-medium dark:text-gray-100">Due today: <b x-text="window.plans[billingCycle][volume].cost">$6</b></div>
|
||||
<div class="mb-4 text-sm font-medium dark:text-gray-100">Due today: <b x-text="selectedPlanPrice()">$6</b></div>
|
||||
<span class="inline-flex rounded-md shadow-sm">
|
||||
<button type="button" data-theme="none" :data-product="window.plans[billingCycle][volume].product_id" data-email="<%= @conn.assigns[:current_user].email %>" data-disable-logout="true" data-passthrough="<%= @conn.assigns[:current_user].id %>" data-success="/billing/upgrade-success" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent paddle_button leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<button type="button" data-theme="none" :data-product="selectedPlanProductId()" data-email="<%= @conn.assigns[:current_user].email %>" data-disable-logout="true" data-passthrough="<%= @conn.assigns[:current_user].id %>" data-success="/billing/upgrade-success" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent paddle_button leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<svg fill="currentColor" viewBox="0 0 20 20" class="inline w-4 h-4 mr-2"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"></path></svg>
|
||||
Pay securely via Paddle
|
||||
</button>
|
||||
|
@ -8,7 +8,7 @@ We don't enforce any hard limits at the moment, we're still counting your stats
|
||||
<br /><br />
|
||||
In the last billing cycle (<%= date_format(@last_cycle.first) %> to <%= date_format(@last_cycle.last) %>), your account has used <%= PlausibleWeb.StatsView.large_number_format(@usage) %> billable pageviews.
|
||||
<%= if @usage <= 20_000_000 do %>
|
||||
Based on that we recommend you select the <%= Plausible.Billing.Plans.suggested_plan_name(@usage) %> plan which runs at <%= Plausible.Billing.Plans.suggested_plan_cost(@usage) %> or <%= Plausible.Billing.Plans.suggested_plan_cost_yearly(@usage) %> when billed yearly.
|
||||
Based on that we recommend you select the <%= @suggested_plan[:volume] %>/mo plan which runs at <%= @suggested_plan[:monthly_cost] %>/mo or <%= @suggested_plan[:yearly_cost] %>/yr when billed yearly.
|
||||
<br /><br />
|
||||
You can upgrade your subscription using our self-serve platform. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
|
||||
<br /><br />
|
||||
|
@ -4,7 +4,7 @@ Thanks for exploring Plausible, a simple and privacy-friendly alternative to Goo
|
||||
<br /><br />
|
||||
In the last month, your account has used <%= PlausibleWeb.AuthView.delimit_integer(@usage) %> billable pageviews<%= if @custom_events > 0, do: " and custom events in total", else: "" %>.
|
||||
<%= if @usage <= 20_000_000 do %>
|
||||
Based on that we recommend you select the <%= Plausible.Billing.Plans.suggested_plan_name(@usage) %> plan which runs at <%= Plausible.Billing.Plans.suggested_plan_cost(@usage) %>.
|
||||
Based on that we recommend you select the <%= @suggested_plan[:volume] %>/mo plan which runs at <%= @suggested_plan[:monthly_cost] %>/mo.
|
||||
|
||||
You can also go with yearly billing to get 33% off on your plan.
|
||||
<br /><br />
|
||||
|
@ -15,7 +15,7 @@ defmodule PlausibleWeb.AuthView do
|
||||
end
|
||||
|
||||
def subscription_quota(subscription) do
|
||||
Plans.subscription_quota(subscription.paddle_plan_id)
|
||||
Plans.allowance(subscription) |> PlausibleWeb.StatsView.large_number_format()
|
||||
end
|
||||
|
||||
def subscription_interval(subscription) do
|
||||
|
@ -53,7 +53,9 @@ defmodule Plausible.Workers.CheckUsage do
|
||||
|
||||
if last_last_month > allowance && last_month > allowance do
|
||||
{_, last_cycle} = billing_mod.last_two_billing_cycles(subscriber)
|
||||
template = PlausibleWeb.Email.over_limit_email(subscriber, last_month, last_cycle)
|
||||
suggested_plan = Plausible.Billing.Plans.suggested_plan(subscriber, last_month)
|
||||
template =
|
||||
PlausibleWeb.Email.over_limit_email(subscriber, last_month, last_cycle, suggested_plan)
|
||||
|
||||
try do
|
||||
Plausible.Mailer.send_email(template)
|
||||
|
@ -2,7 +2,7 @@ defmodule Plausible.Workers.NotifyAnnualRenewal do
|
||||
use Plausible.Repo
|
||||
use Oban.Worker, queue: :notify_annual_renewal
|
||||
|
||||
@yearly_plans Plausible.Billing.Plans.yearly_plan_ids()
|
||||
@yearly_plans Plausible.Billing.Plans.all_yearly_plan_ids()
|
||||
|
||||
@impl Oban.Worker
|
||||
@doc """
|
||||
|
0
priv/plans_v1.json
Normal file
0
priv/plans_v1.json
Normal file
@ -2,12 +2,4 @@ defmodule Plausible.Billing.PlansTest do
|
||||
use Plausible.DataCase
|
||||
use Bamboo.Test, shared: true
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
test "suggested plan name" do
|
||||
assert Plans.suggested_plan_name(110_000) == "200k/mo"
|
||||
end
|
||||
|
||||
test "suggested plan cost" do
|
||||
assert Plans.suggested_plan_cost(110_000) == "$18/mo"
|
||||
end
|
||||
end
|
||||
|
@ -270,6 +270,20 @@ defmodule PlausibleWeb.AuthControllerTest do
|
||||
assert html_response(conn, 200) =~ "10k pageviews"
|
||||
assert html_response(conn, 200) =~ "monthly billing"
|
||||
end
|
||||
|
||||
test "shows yearly subscription", %{conn: conn, user: user} do
|
||||
insert(:subscription, paddle_plan_id: "590752", user: user)
|
||||
conn = get(conn, "/settings")
|
||||
assert html_response(conn, 200) =~ "100k pageviews"
|
||||
assert html_response(conn, 200) =~ "yearly billing"
|
||||
end
|
||||
|
||||
test "shows free subscription", %{conn: conn, user: user} do
|
||||
insert(:subscription, paddle_plan_id: "free_10k", user: user)
|
||||
conn = get(conn, "/settings")
|
||||
assert html_response(conn, 200) =~ "10k pageviews"
|
||||
assert html_response(conn, 200) =~ "N/A billing"
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /settings" do
|
||||
|
@ -7,7 +7,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
setup [:create_user, :create_site]
|
||||
@paddle_id_10k Plans.plans()[:monthly][:"10k"][:product_id]
|
||||
@paddle_id_10k Plans.plans_for(nil) |> List.first() |> Map.get(:monthly_product_id)
|
||||
|
||||
test "ignores user without subscription" do
|
||||
CheckUsage.perform(nil)
|
||||
@ -89,7 +89,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
|
||||
assert_email_delivered_with(
|
||||
to: [user],
|
||||
html_body: ~r/select the 100k\/mo plan which runs at \$12\/mo or \$8\/mo when billed yearly/
|
||||
html_body:
|
||||
~r/select the 100k\/mo plan which runs at \$12\/mo or \$96\/yr when billed yearly/
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -6,8 +6,9 @@ defmodule Plausible.Workers.NotifyAnnualRenewalTest do
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
setup [:create_user, :create_site]
|
||||
@monthly_plan Plans.plans()[:monthly][:"10k"][:product_id]
|
||||
@yearly_plan Plans.plans()[:yearly][:"10k"][:product_id]
|
||||
@plan_10k Plans.plans_for(nil) |> List.first()
|
||||
@monthly_plan @plan_10k[:monthly_product_id]
|
||||
@yearly_plan @plan_10k[:yearly_product_id]
|
||||
|
||||
test "ignores user without subscription" do
|
||||
NotifyAnnualRenewal.perform(nil)
|
||||
|
Loading…
Reference in New Issue
Block a user