You can change your current plan for another one at anytime.
- {changedPlan && (
+
Available tiers
+
You can change your membership tier to another one at anytime.
+ {hasPlanChange && (
- We have changed your subscription successfully.
+ Your plan is scheduled to change on the next billing cycle
)}
{plans.map(plan => {
@@ -77,10 +78,10 @@ function CurrentPlanView ({ user, currentPlan, plans }) {
- Pick plan
+ Select this tier
)
diff --git a/app/jobs/find_overdue_subscriptions_job.rb b/app/jobs/find_overdue_subscriptions_job.rb
index c308f367..e49f0e83 100644
--- a/app/jobs/find_overdue_subscriptions_job.rb
+++ b/app/jobs/find_overdue_subscriptions_job.rb
@@ -4,11 +4,11 @@ class FindOverdueSubscriptionsJob < ApplicationJob
queue_as :default
def perform
- subscriptions_to_charge = Subscription.where(active: true).select do |subscription|
- # create charge if there's no last_charge_at date, meaning it would be the
- # first time we attempt to charge this customer this subscription.
- subscription.last_charge_at ? subscription.last_charge_at <= 30.days.ago : true
- end
+ subscriptions_to_charge =
+ Subscription.where(active: true).where(
+ 'last_charge_at <= ? OR last_charge_at = null',
+ 30.days.ago
+ )
subscriptions_to_charge.each do |subscription_to_charge|
SubscriptionPaymentJob.perform_later(subscription_to_charge)
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index 190fb0ce..83ad733b 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -5,12 +5,12 @@
- mailers
:schedule:
find_overdue_subscriptions:
- every: '45m'
+ every: '1h'
queue: default
class: FindOverdueSubscriptionsJob
description: 'This job finds all active overdue subscriptions and creates a sidekiq job to charge the subscriber'
find_subscription_plan_changes:
- every: '45m'
+ every: '15m'
queue: default
class: ChangeSubscriptionPlansJob
description: 'This job finds all pending subscription changes and creates a sidekiq job to perform the plan change'
diff --git a/spec/features/plan_change_spec.rb b/spec/features/plan_change_spec.rb
index 6924f08c..98d542f2 100644
--- a/spec/features/plan_change_spec.rb
+++ b/spec/features/plan_change_spec.rb
@@ -23,7 +23,7 @@
click_link 'Change Subscription'
- expect(page).to have_content('Available plans')
+ expect(page).to have_content('Available tiers')
within "#plan-#{active_plan.id}" do
expect(page).to have_content(active_plan.name)
@@ -31,7 +31,7 @@
within "#plan-#{new_plan.id}" do
expect(page).to have_content(new_plan.name)
- click_button 'Pick plan'
+ click_button 'Select this tier'
end
expect(page).to have_content('We have changed your subscription successfully.')
From 143543af00338cb5fdd2c4580ac4166bccb71242 Mon Sep 17 00:00:00 2001
From: Orlando Del Aguila
Date: Mon, 14 Sep 2020 12:53:25 -0500
Subject: [PATCH 5/8] chore(renovate): run renovate the first day of the month
---
renovate.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/renovate.json b/renovate.json
index 0f49eb57..c36e8039 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,6 +1,6 @@
{
"extends": ["config:base"],
- "schedule": ["before 11pm on Monday"],
+ "schedule": ["before 4am on the first day of the month"],
"bundler": {
"enabled": true
}
From 97b996b6e0af929af0a837b45df6ea06dd0508c0 Mon Sep 17 00:00:00 2001
From: Orlando Del Aguila
Date: Mon, 14 Sep 2020 18:43:06 -0500
Subject: [PATCH 6/8] fix: user should be able to change subscriptions more
than once
---
app/controllers/plan_changes_controller.rb | 25 +++++++-----
.../bundles/User/components/CurrentPlan.jsx | 20 ++++++----
.../User/components/SubscriptionCancel.jsx | 9 +----
...oggle_user_active_subscription_plan_job.rb | 23 +++++++----
app/models/subscription.rb | 14 ++++---
app/models/user.rb | 11 ++++-
app/models/user_plan_change.rb | 12 +++++-
app/views/plan_changes/index.html.erb | 2 +-
config/routes.rb | 34 ++++++++--------
...0200914231027_remove_subscription_index.rb | 5 +++
db/schema.rb | 3 +-
spec/factories/subscriptions.rb | 5 +--
spec/features/plan_change_spec.rb | 2 +-
..._user_active_subscription_plan_job_spec.rb | 15 ++++---
spec/models/subscription_spec.rb | 40 ++++++++++++++++---
spec/models/user_plan_change_spec.rb | 20 ++++++++++
spec/rails_helper.rb | 4 ++
17 files changed, 168 insertions(+), 76 deletions(-)
create mode 100644 db/migrate/20200914231027_remove_subscription_index.rb
diff --git a/app/controllers/plan_changes_controller.rb b/app/controllers/plan_changes_controller.rb
index 1875b067..cdcc1d0e 100644
--- a/app/controllers/plan_changes_controller.rb
+++ b/app/controllers/plan_changes_controller.rb
@@ -9,25 +9,30 @@ def index
redirect_to root_path unless current_user&.active_subscription
@user = current_user
+ @pending_plan_change = @user.pending_plan_change
@plans = Plan.all
end
- # GET /users/:user_id/plan_changes/new
- # GET /users/:user_id/plan_changes/new.json
- def new
- @plan_change = UserPlanChange.new
- end
-
# POST /users/:user_id/plan_changes
# POST /users/:user_id/plan_changes.json
def create
- @plan = UserPlanChange.new(user_id: current_user.id, old_plan_id: plan_change_params[:old_plan_id], new_plan_id: plan_change_params[:new_plan_id], status: 'pending')
+ @plan_change =
+ current_user.user_plan_changes.new(
+ old_plan_id: plan_change_params[:old_plan_id],
+ new_plan_id: plan_change_params[:new_plan_id],
+ status: 'pending'
+ )
respond_to do |format|
- if @plan.save
- format.json { render json: @plan, status: :ok }
+ if @plan_change.save
+ format.html { render :index, notice: 'Plan changed successfully' }
+ format.json { render json: @plan_change, status: :ok }
else
- format.html { render :index }
+ format.html { render :index, notice: 'Error while changing plans' }
+ format.json do
+ render json: { errors: @plan_change.errors.full_messages },
+ status: :ok
+ end
end
end
end
diff --git a/app/javascript/bundles/User/components/CurrentPlan.jsx b/app/javascript/bundles/User/components/CurrentPlan.jsx
index fa5b485c..892abd8f 100644
--- a/app/javascript/bundles/User/components/CurrentPlan.jsx
+++ b/app/javascript/bundles/User/components/CurrentPlan.jsx
@@ -18,13 +18,15 @@ const useStyles = makeStyles(theme => ({
const CHANGE_PLAN_ENDPOINT = id => `/users/${id}/plan_changes`
-function CurrentPlanView ({ user, currentPlan, plans }) {
+function CurrentPlanView ({ user, currentPlan, pendingPlanChange, plans }) {
const classes = useStyles()
- const [hasPlanChange, setPlanChanged] = useState(false)
+ const [planChange, setPlanChange] = useState(pendingPlanChange)
+ const pendingPlanChangePlan =
+ planChange && plans.find(plan => plan.id == planChange.new_plan_id)
const changePlan = async selectedPlanId => {
try {
- await fetch(CHANGE_PLAN_ENDPOINT(user.id), {
+ const response = await fetch(CHANGE_PLAN_ENDPOINT(user.id), {
body: JSON.stringify({
plan_change: {
old_plan_id: currentPlan.id,
@@ -38,7 +40,9 @@ function CurrentPlanView ({ user, currentPlan, plans }) {
},
method: 'post'
})
- setPlanChanged(true)
+
+ const json = await response.json()
+ setPlanChange(json)
} catch (error) {
console.error(error)
Sentry.captureException(error)
@@ -56,9 +60,11 @@ function CurrentPlanView ({ user, currentPlan, plans }) {
Available tiers
You can change your membership tier to another one at anytime.
- {hasPlanChange && (
+ {planChange && (
- Your plan is scheduled to change on the next billing cycle
+ Your plan is scheduled to change to{' '}
+ {pendingPlanChangePlan.name}. The new amount will be
+ charged on your next billing cycle.
)}
{plans.map(plan => {
@@ -78,7 +84,7 @@ function CurrentPlanView ({ user, currentPlan, plans }) {
Select this tier
diff --git a/app/javascript/bundles/User/components/SubscriptionCancel.jsx b/app/javascript/bundles/User/components/SubscriptionCancel.jsx
index 915d1f0b..8c6aefc3 100644
--- a/app/javascript/bundles/User/components/SubscriptionCancel.jsx
+++ b/app/javascript/bundles/User/components/SubscriptionCancel.jsx
@@ -95,8 +95,7 @@ function SubscriptionCancelView ({
You're subscribed
- The plan you're using to contribute is{' '}
- {currentPlan.name}.
+ Your membership tier is {currentPlan.name}.
{!isSubscriptionChanging && (
Do you want to terminate your current subscription?
-
-
- Terminating your subscription will stop your current plan and the
- benefits you receive from it.
-
-
Close
diff --git a/app/jobs/toggle_user_active_subscription_plan_job.rb b/app/jobs/toggle_user_active_subscription_plan_job.rb
index d5be5450..24ac690a 100644
--- a/app/jobs/toggle_user_active_subscription_plan_job.rb
+++ b/app/jobs/toggle_user_active_subscription_plan_job.rb
@@ -4,24 +4,31 @@ class ToggleUserActiveSubscriptionPlanJob < ApplicationJob
queue_as :default
def perform(user_plan_change)
- # find the user
+ # find user
user = User.find(user_plan_change.user_id)
# disable current user subscription.
old_subscription = user.active_subscription
+
ActiveRecord::Base.transaction do
old_subscription.update(active: false)
# creates a new subscription with the new plan details.
- new_subscription = Subscription.new(
- user_id: user_plan_change.user_id,
- plan_id: user_plan_change.new_plan_id,
- last_charge_at: old_subscription.last_charge_at,
- active: true
- )
+ new_subscription =
+ Subscription.new(
+ user_id: user.id,
+ plan_id: user_plan_change.new_plan_id,
+ last_charge_at: old_subscription.last_charge_at,
+ active: true
+ )
if new_subscription.save
- UserPlanChange.find(user_plan_change.id).update(status: "succeeded")
+ UserPlanChange.find(user_plan_change.id).update(status: 'succeeded')
+ else
+ Raven.capture_message(
+ "We couldn't process subscription plan change",
+ extra: { user_id: user.id, subscription_id: old_subscription.id }
+ )
end
end
end
diff --git a/app/models/subscription.rb b/app/models/subscription.rb
index 340cbe4d..164f0272 100644
--- a/app/models/subscription.rb
+++ b/app/models/subscription.rb
@@ -15,9 +15,8 @@
#
# Indexes
#
-# index_subscriptions_on_plan_id (plan_id)
-# index_subscriptions_on_user_id (user_id)
-# index_subscriptions_on_user_id_and_plan_id_and_active (user_id,plan_id,active) UNIQUE
+# index_subscriptions_on_plan_id (plan_id)
+# index_subscriptions_on_user_id (user_id)
#
class Subscription < ApplicationRecord
before_create :store_start_date
@@ -25,8 +24,7 @@ class Subscription < ApplicationRecord
belongs_to :user, optional: true
belongs_to :plan
- validates :plan_id, presence: true
- validates :user_id, uniqueness: {scope: %i[plan_id active]}, if: :user?
+ validate :only_one_active_subscription, on: :create
def user?
!user_id.blank?
@@ -43,4 +41,10 @@ def cancel!
def store_start_date
self.start_date = DateTime.now if start_date.nil?
end
+
+ def only_one_active_subscription
+ if Subscription.exists?(user_id: user_id, active: true)
+ errors.add(:base, 'already has an active subscription')
+ end
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 488ca62f..66a3e99a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -32,11 +32,12 @@ class User < ApplicationRecord
has_many :subscriptions
has_many :donations
+ has_many :user_plan_changes
validates :external_id, presence: true
def self.find_or_create_from_sso(payload)
- external_id = payload.fetch("external_id")
+ external_id = payload.fetch('external_id')
user = User.find_or_initialize_by(external_id: external_id)
new_record = user.new_record?
@@ -63,12 +64,18 @@ def current_streak
start_date = subscription.start_date
today = Date.today
- months = (today.year * 12 + today.month) - (start_date.year * 12 + start_date.month)
+ months =
+ (today.year * 12 + today.month) -
+ (start_date.year * 12 + start_date.month)
months += 1 if months == 0
months
end
+ def pending_plan_change
+ user_plan_changes.where(status: :pending).first
+ end
+
def active_subscription
subscriptions.includes(:plan).where(active: true).last
end
diff --git a/app/models/user_plan_change.rb b/app/models/user_plan_change.rb
index a5af0bea..842dbb72 100644
--- a/app/models/user_plan_change.rb
+++ b/app/models/user_plan_change.rb
@@ -15,8 +15,16 @@
class UserPlanChange < ApplicationRecord
belongs_to :user
- enum status: {succeeded: 0, pending: 1, failed: 2}
+ enum status: { succeeded: 0, pending: 1, failed: 2 }
validates :old_plan_id, :new_plan_id, :user_id, presence: true
- validates :user_id, uniqueness: true
+ validate :only_one_pending_plan_change, on: :create
+
+ private
+
+ def only_one_pending_plan_change
+ if UserPlanChange.exists?(user_id: user_id, status: 'pending')
+ errors.add(:base, 'already has a pending plan change')
+ end
+ end
end
diff --git a/app/views/plan_changes/index.html.erb b/app/views/plan_changes/index.html.erb
index be58f09a..12b92252 100644
--- a/app/views/plan_changes/index.html.erb
+++ b/app/views/plan_changes/index.html.erb
@@ -1,3 +1,3 @@
- <%= react_component("CurrentPlan", props: {user: @user, currentPlan: @user.active_subscription&.plan, plans: @plans}) %>
+ <%= react_component("CurrentPlan", props: {user: @user, currentPlan: @user.active_subscription&.plan, pendingPlanChange: @pending_plan_change, plans: @plans}) %>
diff --git a/config/routes.rb b/config/routes.rb
index a2ec8ab7..c32919bc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,21 +1,21 @@
# frozen_string_literal: true
-require "sidekiq/web"
-require "sidekiq-scheduler/web"
+require 'sidekiq/web'
+require 'sidekiq-scheduler/web'
Rails.application.routes.draw do
- get "/card/new" => "billings#new_card", :as => :add_payment_method
- post "/card" => "billings#create_card", :as => :create_payment_method
+ get '/card/new' => 'billings#new_card', as: :add_payment_method
+ post '/card' => 'billings#create_card', as: :create_payment_method
- get "/thank-you" => "static_pages#thank_you"
+ get '/thank-you' => 'static_pages#thank_you'
resources :subscription_charges, only: %i[new edit create update]
resources :billings, only: %i[new create]
resources :charges,
- only: %i[new create], path: "donate", path_names: {new: ""}
+ only: %i[new create], path: 'donate', path_names: { new: '' }
namespace :admin do
- get "/dashboard" => "dashboard#index"
+ get '/dashboard' => 'dashboard#index'
resources :users
resources :plans
resources :funds, except: %i[show]
@@ -23,25 +23,25 @@
resources :donations, only: %i[index show]
end
- get "/admin", to: redirect("/admin/dashboard")
+ get '/admin', to: redirect('/admin/dashboard')
resources :users, only: %i[show new edit update create destroy] do
- get "/subscription" => "users#subscription", :as => :current_subscription
- get "/donations" => "users#donation_history", :as => :latest_donations
+ get '/subscription' => 'users#subscription', as: :current_subscription
+ get '/donations' => 'users#donation_history', as: :latest_donations
resource :streak, only: %i[show]
resource :subscription, only: %i[destroy]
- resources :plan_changes, only: %i[index new create]
+ resources :plan_changes, only: %i[index create]
end
- get "/login" => "sessions#login"
- get "/signup" => "sessions#signup"
+ get '/login' => 'sessions#login'
+ get '/signup' => 'sessions#signup'
if Rails.env.production?
- mount Sidekiq::Web => "/sidekiq",
- :constraints => AdminConstraint.new(require_master: true)
+ mount Sidekiq::Web => '/sidekiq',
+ constraints: AdminConstraint.new(require_master: true)
else
- mount Sidekiq::Web => "/sidekiq"
+ mount Sidekiq::Web => '/sidekiq'
end
- root "static_pages#home"
+ root 'static_pages#home'
end
diff --git a/db/migrate/20200914231027_remove_subscription_index.rb b/db/migrate/20200914231027_remove_subscription_index.rb
new file mode 100644
index 00000000..e503b106
--- /dev/null
+++ b/db/migrate/20200914231027_remove_subscription_index.rb
@@ -0,0 +1,5 @@
+class RemoveSubscriptionIndex < ActiveRecord::Migration[6.0]
+ def change
+ remove_index :subscriptions, [:user_id, :plan_id, :active]
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4e0bc4b5..2b6e341f 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_09_01_215441) do
+ActiveRecord::Schema.define(version: 2020_09_14_231027) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -102,7 +102,6 @@
t.datetime "start_date"
t.datetime "last_charge_at"
t.index ["plan_id"], name: "index_subscriptions_on_plan_id"
- t.index ["user_id", "plan_id", "active"], name: "index_subscriptions_on_user_id_and_plan_id_and_active", unique: true
t.index ["user_id"], name: "index_subscriptions_on_user_id"
end
diff --git a/spec/factories/subscriptions.rb b/spec/factories/subscriptions.rb
index e2aa75d1..68be67ab 100644
--- a/spec/factories/subscriptions.rb
+++ b/spec/factories/subscriptions.rb
@@ -15,9 +15,8 @@
#
# Indexes
#
-# index_subscriptions_on_plan_id (plan_id)
-# index_subscriptions_on_user_id (user_id)
-# index_subscriptions_on_user_id_and_plan_id_and_active (user_id,plan_id,active) UNIQUE
+# index_subscriptions_on_plan_id (plan_id)
+# index_subscriptions_on_user_id (user_id)
#
FactoryBot.define do
factory :subscription do
diff --git a/spec/features/plan_change_spec.rb b/spec/features/plan_change_spec.rb
index 98d542f2..e0102235 100644
--- a/spec/features/plan_change_spec.rb
+++ b/spec/features/plan_change_spec.rb
@@ -34,7 +34,7 @@
click_button 'Select this tier'
end
- expect(page).to have_content('We have changed your subscription successfully.')
+ expect(page).to have_content("Your plan is scheduled to change to #{new_plan.name}")
expect(UserPlanChange.where(user_id: user.id).length).to be(1)
end
end
diff --git a/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb b/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
index b2fde652..4082f2c8 100644
--- a/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
+++ b/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
@@ -2,16 +2,16 @@
require "rails_helper"
-RSpec.describe ToggleUserActiveSubscriptionPlanJob do
+RSpec.describe ToggleUserActiveSubscriptionPlanJob, type: :job do
let(:user) { FactoryBot.create(:user) }
let!(:old_plan) { FactoryBot.create(:plan) }
let!(:new_plan) { FactoryBot.create(:plan) }
let!(:active_subscription) { FactoryBot.create(:subscription, user: user, plan: old_plan) }
- let!(:plan_change) { FactoryBot.create(:user_plan_change, user: user, old_plan_id: old_plan.id, new_plan_id: new_plan.id, status: "pending") }
-
- subject(:job) { described_class.perform_later(plan_change) }
it "queues the job" do
+ plan_change = FactoryBot.create(:user_plan_change, user: user, old_plan_id: old_plan.id, new_plan_id: new_plan.id, status: "pending")
+ job = ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change)
+
expect { job }
.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1)
end
@@ -21,6 +21,9 @@
end
it "executes perform" do
+ plan_change = FactoryBot.create(:user_plan_change, user: user, old_plan_id: old_plan.id, new_plan_id: new_plan.id, status: "pending")
+ job = ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change)
+
expect(Subscription.count).to eq(1)
expect(user.active_subscription.plan.id).to eq(old_plan.id)
@@ -28,8 +31,10 @@
expect(Subscription.count).to eq(2)
user.active_subscription.reload
+ plan_change.reload
+
expect(user.active_subscription.plan.id).to eq(new_plan.id)
- expect(plan_change.reload.status).to eq("succeeded")
+ expect(plan_change.status).to eq("succeeded")
end
after do
diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb
index be6ba15f..e066b7cf 100644
--- a/spec/models/subscription_spec.rb
+++ b/spec/models/subscription_spec.rb
@@ -15,14 +15,14 @@
#
# Indexes
#
-# index_subscriptions_on_plan_id (plan_id)
-# index_subscriptions_on_user_id (user_id)
-# index_subscriptions_on_user_id_and_plan_id_and_active (user_id,plan_id,active) UNIQUE
+# index_subscriptions_on_plan_id (plan_id)
+# index_subscriptions_on_user_id (user_id)
#
require 'rails_helper'
RSpec.describe Subscription, type: :model do
let(:subscription) { FactoryBot.create(:subscription) }
+ let(:plan) { FactoryBot.create(:plan) }
subject { subscription }
@@ -34,7 +34,37 @@
end
describe 'validations' do
- it { is_expected.to validate_presence_of(:plan_id) }
- it { is_expected.to validate_uniqueness_of(:user_id).scoped_to(:plan_id, :active).ignoring_case_sensitivity }
+ it { should belong_to(:plan) }
+ it { should belong_to(:user).optional(true) }
+
+ it 'can have many subscriptions' do
+ user = FactoryBot.create(:user)
+ FactoryBot.create(:subscription, user: user, active: false)
+
+ new_subscription = Subscription.new(
+ user_id: user.id,
+ plan_id: plan.id,
+ active: true
+ )
+
+ new_subscription.save
+
+ expect(new_subscription.errors).to be_empty
+ end
+
+ it 'only can be one active subscription at a time' do
+ user = FactoryBot.create(:user)
+ FactoryBot.create(:subscription, user: user)
+
+ new_subscription = Subscription.new(
+ user_id: user.id,
+ plan_id: plan.id,
+ active: true
+ )
+
+ new_subscription.save
+
+ expect(new_subscription.errors.full_messages).to eq(['already has an active subscription'])
+ end
end
end
diff --git a/spec/models/user_plan_change_spec.rb b/spec/models/user_plan_change_spec.rb
index 8fbaf770..59c6afa8 100644
--- a/spec/models/user_plan_change_spec.rb
+++ b/spec/models/user_plan_change_spec.rb
@@ -15,6 +15,9 @@
require 'rails_helper'
RSpec.describe UserPlanChange, type: :model do
+ let!(:user) { FactoryBot.create(:user) }
+ let!(:plan1) { FactoryBot.create(:plan) }
+ let!(:plan2) { FactoryBot.create(:plan) }
let!(:user_plan_change) { FactoryBot.create(:user_plan_change) }
subject { user_plan_change }
@@ -30,5 +33,22 @@
it { is_expected.to validate_presence_of(:user_id) }
it { is_expected.to validate_presence_of(:old_plan_id) }
it { is_expected.to validate_presence_of(:new_plan_id) }
+
+ it 'can have multiple plan changes' do
+ plan_change = FactoryBot.create(:user_plan_change, user: user, status: 'succeeded', new_plan_id: plan1.id, old_plan_id: plan2.id)
+ second_plan_change = user.user_plan_changes.new(new_plan_id: plan2, old_plan_id: plan1)
+ second_plan_change.save
+
+ expect(second_plan_change.errors).to be_empty
+ end
+
+ it 'allows only one pending plan change' do
+ pending_plan_change = FactoryBot.create(:user_plan_change, user: user, status: 'pending', new_plan_id: plan1.id, old_plan_id: plan2.id)
+
+ second_pending_plan_change = user.user_plan_changes.new(new_plan_id: plan2, old_plan_id: plan1)
+ second_pending_plan_change.save
+
+ expect(second_pending_plan_change.errors.full_messages).to eq(['already has a pending plan change'])
+ end
end
end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index af51dced..d6095e82 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -69,6 +69,10 @@
DatabaseCleaner.strategy = :transaction
end
+ config.before(:each, type: :job) do
+ DatabaseCleaner.strategy = :truncation
+ end
+
config.before(:each, type: :feature) do
# :rack_test driver's Rack app under test shares database connection
# with the specs, so continue to use transaction strategy for speed.
From 43210d671246f9d3e25091e3d7368e025d33e7ce Mon Sep 17 00:00:00 2001
From: Orlando Del Aguila
Date: Mon, 14 Sep 2020 19:04:41 -0500
Subject: [PATCH 7/8] test: fix job tests
---
app/jobs/find_overdue_subscriptions_job.rb | 2 +-
spec/jobs/find_overdue_subscriptions_job_spec.rb | 11 ++++-------
.../toggle_user_active_subscription_plan_job_spec.rb | 6 ++----
3 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/app/jobs/find_overdue_subscriptions_job.rb b/app/jobs/find_overdue_subscriptions_job.rb
index e49f0e83..ab7f5aca 100644
--- a/app/jobs/find_overdue_subscriptions_job.rb
+++ b/app/jobs/find_overdue_subscriptions_job.rb
@@ -6,7 +6,7 @@ class FindOverdueSubscriptionsJob < ApplicationJob
def perform
subscriptions_to_charge =
Subscription.where(active: true).where(
- 'last_charge_at <= ? OR last_charge_at = null',
+ 'last_charge_at IS NULL OR last_charge_at <= ?',
30.days.ago
)
diff --git a/spec/jobs/find_overdue_subscriptions_job_spec.rb b/spec/jobs/find_overdue_subscriptions_job_spec.rb
index 5e947c3a..0e9f9379 100644
--- a/spec/jobs/find_overdue_subscriptions_job_spec.rb
+++ b/spec/jobs/find_overdue_subscriptions_job_spec.rb
@@ -6,12 +6,10 @@
let!(:recently_paid_active_subscription) { FactoryBot.create(:subscription, last_charge_at: 2.weeks.ago) }
let!(:inactive_subscription) { FactoryBot.create(:subscription, active: false) }
let!(:active_subscription_one) { FactoryBot.create(:subscription, last_charge_at: 32.days.ago) }
- let!(:active_subscription_two) { FactoryBot.create(:subscription) }
-
- subject(:job) { described_class.perform_later }
+ let!(:active_subscription_two) { FactoryBot.create(:subscription, last_charge_at: nil) }
it 'queues the job' do
- expect { job }
+ expect { FindOverdueSubscriptionsJob.perform_later }
.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1)
end
@@ -20,9 +18,8 @@
end
it 'executes perform' do
- expect do
- described_class.perform_now
- end.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(2)
+ expect { FindOverdueSubscriptionsJob.perform_now }
+ .to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(2)
end
after do
diff --git a/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb b/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
index 4082f2c8..95916b52 100644
--- a/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
+++ b/spec/jobs/toggle_user_active_subscription_plan_job_spec.rb
@@ -10,9 +10,8 @@
it "queues the job" do
plan_change = FactoryBot.create(:user_plan_change, user: user, old_plan_id: old_plan.id, new_plan_id: new_plan.id, status: "pending")
- job = ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change)
- expect { job }
+ expect { ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change) }
.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1)
end
@@ -22,12 +21,11 @@
it "executes perform" do
plan_change = FactoryBot.create(:user_plan_change, user: user, old_plan_id: old_plan.id, new_plan_id: new_plan.id, status: "pending")
- job = ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change)
expect(Subscription.count).to eq(1)
expect(user.active_subscription.plan.id).to eq(old_plan.id)
- perform_enqueued_jobs { job }
+ perform_enqueued_jobs { ToggleUserActiveSubscriptionPlanJob.perform_later(plan_change) }
expect(Subscription.count).to eq(2)
user.active_subscription.reload
From 370c4762ca7b176f5d4143acda6530e3e10f2a59 Mon Sep 17 00:00:00 2001
From: Orlando Del Aguila
Date: Mon, 14 Sep 2020 19:12:50 -0500
Subject: [PATCH 8/8] chore: set codecov patch threshold
---
codecov.yml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/codecov.yml b/codecov.yml
index 1b446323..0155d936 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,6 +1,10 @@
coverage:
status:
+ patch:
+ default:
+ target: auto
+ threshold: 3%
project:
default:
target: auto
- threshold: 2%
+ threshold: 3%