Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-factor subscription logic for new pricing structure #1849

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions app/controllers/plans_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
class PlansController < ApplicationController
MARKETPLACE_URL = ENV.fetch(
"MARKETPLACE_URL",
"https://www.github.com/marketplace/hound"
)

helper_method :plan_selector

def index
Expand All @@ -23,12 +18,12 @@ def plan_params
end

def plan_selector
@_plan_selector ||= PlanSelector.new(user: current_user, repo: repo)
@_plan_selector ||= PlanSelector.new(repo.owner)
end

def marketplace_upgrade_url
if plan_selector.marketplace_plan?
"#{MARKETPLACE_URL}/order/#{plan_selector.next_plan.slug}?account=#{repo.owner.name}"
plan_selector.marketplace_upgrade_url
end
end

Expand Down
10 changes: 5 additions & 5 deletions app/controllers/subscriptions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ class FailedToActivate < StandardError; end
before_action :update_email

def create
plan_selector = PlanSelector.new(user: current_user, repo: repo)
plan_selector = PlanSelector.new(repo.owner)

if plan_selector.upgrade?
if plan_selector.paywall?
render json: {}, status: :payment_required
elsif plan_selector.marketplace_plan?
elsif plan_selector.upgrade?
render json: {}, status: :payment_required
else
repo.activate

render json: repo, status: :created
else
activate_and_create_subscription
end
end

Expand Down
13 changes: 6 additions & 7 deletions app/javascript/components/ReposContainer/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,12 @@ export default class App extends React.Component {
}

createSubscriptionWithExistingCard(repo) {
Ajax.createSubscription({ repo_id: repo.id })
.then(resp => {
this.activateAndTrackRepoSubscription(
repo, resp.stripe_subscription_id
);
})
.catch(error => this.onSubscriptionError(repo, error));
Ajax.createSubscription({ repo_id: repo.id }).then( resp => {
this.activateAndTrackRepoSubscription(
repo,
resp.stripe_subscription_id
);
}).catch(error => this.onSubscriptionError(repo, error));
}

activateFreeRepo(repo) {
Expand Down
2 changes: 1 addition & 1 deletion app/models/home.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ def open_source_repos
end

def plan_selector
PlanSelector.new(user: user)
PlanSelector.new(user.owner)
end
end
46 changes: 0 additions & 46 deletions app/models/metered_stripe_plan.rb

This file was deleted.

18 changes: 11 additions & 7 deletions app/models/owner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,23 @@ def recent_invoice_url
end

def recent_builds
Build.where(
"DATE(created_at) > DATE(?) AND DATE(created_at) < DATE(?)",
1.month.ago,
Time.current,
).where(
repo_id: repo_ids,
).count
Build.
where(repo_id: repo_ids).
where(
"DATE(created_at) > DATE(?) AND DATE(created_at) < DATE(?)",
1.month.ago,
Time.current,
).count
end

def metered_plan?
marketplace_plan_id.blank?
end

def stripe_plan_id
@_stripe_plan_id ||= PaymentGatewayCustomer.new(self).subscription.plan
end

private

def hound_config
Expand Down
3 changes: 2 additions & 1 deletion app/models/payment_gateway_customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ def update_email(email)
private

def create_subscription(options)
subscription = customer.subscriptions.create(options)
PaymentGatewaySubscription.new(
stripe_subscription: customer.subscriptions.create(options),
stripe_subscription: subscription,
user: user,
).tap do |subscription|
Analytics.new(user).track_purchase(subscription.stripe_subscription)
Expand Down
70 changes: 30 additions & 40 deletions app/models/plan_selector.rb
Original file line number Diff line number Diff line change
@@ -1,76 +1,66 @@
class PlanSelector
BULK_ID = "bulk".freeze
MARKETPLACE_URL = ENV.fetch(
"MARKETPLACE_URL",
"https://www.github.com/marketplace/hound",
)

def initialize(user:, repo: nil)
@user = user
@repo = repo || user.first_available_repo
def initialize(owner)
@owner = owner
end

def current_plan
def paywall?
owner.stripe_customer_id.blank? && marketplace_plan_id.blank?
end

def upgrade?
if marketplace_plan?
plans.detect { |plan| plan.id == marketplace_plan_id }
elsif metered_plan?
plans.detect { |plan| plan.id == user.payment_gateway_subscription.plan }
owner.active_private_repos_count + 1 > current_plan.allowance
else
find_plan_by_active_repo_count(active_repo_count)
owner.recent_builds >= current_plan.allowance
end
end

def upgrade?
if repo&.owner&.whitelisted?
false
elsif metered_plan?
current_plan.open_source?
def current_plan
if marketplace_plan?
plans.detect { |plan| plan.id == marketplace_plan_id }
else
!!(next_plan && next_plan.allowance > current_plan.allowance)
plans.detect { |plan| plan.id == owner.stripe_plan_id } || free_plan
end
end

def next_plan
find_plan_by_active_repo_count(active_repo_count.succ)
current_plan_index = plans.index(current_plan)
if current_plan_index
plans[current_plan_index + 1] || plans.last
end
end

def previous_plan
find_plan_by_active_repo_count(active_repo_count.pred)
def plans
@_plans ||= plan_class::PLANS.map { |plan| plan_class.new(**plan) }
end

def marketplace_plan?
marketplace_plan_id.present?
end

def plans
plan_class::PLANS.map { |plan| plan_class.new(**plan) }
end

private

attr_reader :user, :repo
attr_reader :owner

def find_plan_by_active_repo_count(active_repo_count)
plans.detect do |plan|
plan.range.include? active_repo_count
end
def free_plan
plan_class.new(**plan_class::PLANS[0])
end

def plan_class
if marketplace_plan?
GitHubPlan
elsif metered_plan?
MeteredStripePlan
else
StripePlan
end
marketplace_plan? ? GitHubPlan : StripePlan
end

def marketplace_plan_id
repo&.owner&.marketplace_plan_id
end

def active_repo_count
user.subscribed_repos.size
owner.marketplace_plan_id
end

def metered_plan?
repo&.metered_plan?
def marketplace_upgrade_url
"#{MARKETPLACE_URL}/order/#{next_plan.slug}?account=#{owner.name}"
end
end
4 changes: 0 additions & 4 deletions app/models/repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ def stripe_subscription_id
end
end

def metered_plan?
owner.metered_plan?
end

def total_violations
builds.sum(:violations_count)
end
Expand Down
46 changes: 42 additions & 4 deletions app/models/stripe_plan.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,46 @@
class StripePlan < Plan
PLANS = [
{ id: "basic", price: 0, range: 0..0, title: "Hound" },
{ id: "tier1", price: 49, range: 1..4, title: "Chihuahua" },
{ id: "tier2", price: 99, range: 5..10, title: "Labrador" },
{ id: "tier3", price: 249, range: 11..30, title: "Great Dane" },
{
id: "free",
price: 0,
title: "Open Source",
range: (0..0),
},
{
id: "plan_FXpsAlar939qfx",
price: 29,
title: "Chihuahua",
range: (0..50),
},
{
id: "plan_FXpsHlYOH8tAfo",
price: 49,
title: "Terrier",
range: (51..300),
},
{
id: "plan_FXptlXmCZwt7Rf",
price: 99,
title: "Labrador",
range: (301..1_000),
},
{
id: "plan_FXptCDypXrtK0c",
price: 199,
title: "Husky",
range: (1_001..3_000),
},
{
id: "plan_FXpu6Y3Dhrllj6",
price: 299,
title: "Great Dane",
range: (3_001..10_000),
},
{
id: "price_1IRPYr2QAwplLIsJv7ilvH7K",
price: 299 * 12,
title: "Great Dane (Yearly)",
range: (3_001..10_000),
},
].freeze
end
Loading