Skip to content

Commit

Permalink
Merge pull request #160 from solidusio-contrib/aldesantis/maximum-ret…
Browse files Browse the repository at this point in the history
…ry-period

Add maximum_reprocessing_attempts preference
  • Loading branch information
aldesantis authored Oct 13, 2020
2 parents 6b5c54f + e234e5b commit 8ff161a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 19 deletions.
16 changes: 14 additions & 2 deletions app/models/solidus_subscriptions/installment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,25 @@ def state
# @return [SolidusSubscriptions::InstallmentDetail] The record of the
# failed processing attempt
def payment_failed!(order)
advance_actionable_date!

details.create!(
success: false,
order: order,
message: I18n.t('solidus_subscriptions.installment_details.payment_failed')
)

if maximum_attempts_reached? && !subscription.canceled?
subscription.force_cancel!
update!(actionable_date: nil)
else
advance_actionable_date!
end
end

# Returns whether this installment has reached the maximum number of reprocessing attempts.
def maximum_attempts_reached?
return false unless SolidusSubscriptions.configuration.maximum_reprocessing_attempts

details.where(success: false).count >= SolidusSubscriptions.configuration.maximum_reprocessing_attempts
end

private
Expand Down
6 changes: 6 additions & 0 deletions app/models/solidus_subscriptions/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ def self.processing_states
transition active: :pending_cancellation
end

event :force_cancel do
transition [:active, :pending_cancellation] => :canceled
transition inactive: :inactive
transition canceled: :canceled
end

after_transition to: :canceled, do: :advance_actionable_date

event :deactivate do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
# Time between an installment failing to be processed and the system retrying to fulfill it.
# config.reprocessing_interval = 1.day

# Maximum number of times the system attempts to reprocess a failed payment before cancelling
# the subscription (`nil` is the default and will make the system reprocess indefinitely).
# config.maximum_reprocessing_attempts = nil

# ========================================= Dispatchers ==========================================
#
# These dispatchers are pluggable. If you override any handlers, it is highly encouraged that you
Expand Down
3 changes: 2 additions & 1 deletion lib/solidus_subscriptions/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
module SolidusSubscriptions
class Configuration
attr_accessor(
:maximum_total_skips, :churn_buster_account_id, :churn_buster_api_key,
:maximum_total_skips, :maximum_reprocessing_attempts, :churn_buster_account_id,
:churn_buster_api_key,
)

attr_writer(
Expand Down
104 changes: 88 additions & 16 deletions spec/models/solidus_subscriptions/installment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,100 @@
end

describe '#payment_failed!' do
subject { installment.payment_failed!(order) }
context 'when maximum_reprocessing_attempts is nil' do
it 'creates a new installment detail' do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: nil,
reprocessing_interval: 2.days,
)
installment = create(:installment)

let(:order) { create :order }
installment.payment_failed!(create(:order))

let(:expected_date) do
(DateTime.current + SolidusSubscriptions.configuration.reprocessing_interval).beginning_of_minute
end
expect(installment.details.count).to eq(1)
end

it { is_expected.to be_a SolidusSubscriptions::InstallmentDetail }
it { is_expected.not_to be_successful }
it "advances the installment's actionable_date" do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: nil,
reprocessing_interval: 2.days,
)
installment = create(:installment)

it 'has the correct message' do
expect(subject).to have_attributes(
order: order,
message: I18n.t('solidus_subscriptions.installment_details.payment_failed')
)
installment.payment_failed!(create(:order))

expect(installment.actionable_date).to eq((Time.zone.now + 2.days).beginning_of_minute)
end
end

it 'advances the installment actionable_date' do
subject
actionable_date = installment.reload.actionable_date
expect(actionable_date).to eq expected_date
context 'when maximum_reprocessing_attempts is configured' do
context 'when the installment has reached the maximum number of attempts' do
it 'creates a new installment detail' do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: 3,
reprocessing_interval: 2.days,
)
installment = create(:installment)
create_list(:installment_detail, 2, installment: installment, success: false)

installment.payment_failed!(create(:order))

expect(installment.details.count).to eq(3)
end

it 'sets the actionable_date to nil' do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: 3,
)
installment = create(:installment)
create_list(:installment_detail, 2, installment: installment, success: false)

installment.payment_failed!(create(:order))

expect(installment.actionable_date).to eq(nil)
end

it 'cancels the subscription' do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: 3,
reprocessing_interval: 2.days,
)
installment = create(:installment)
create_list(:installment_detail, 2, installment: installment, success: false)

installment.payment_failed!(create(:order))

expect(installment.subscription.state).to eq('canceled')
end
end

context 'when the installment has not reached the maximum number of attempts' do
it 'creates a new installment detail' do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: 3,
reprocessing_interval: 2.days,
)
installment = create(:installment)
create_list(:installment_detail, 1, installment: installment, success: false)

installment.payment_failed!(create(:order))

expect(installment.details.count).to eq(2)
end

it "advances the installment's actionable_date" do
allow(SolidusSubscriptions.configuration).to receive_messages(
maximum_reprocessing_attempts: 3,
reprocessing_interval: 2.days,
)
installment = create(:installment)
create_list(:installment_detail, 1, installment: installment, success: false)

installment.payment_failed!(create(:order))

expect(installment.actionable_date).to eq((Time.zone.now + 2.days).beginning_of_minute)
end
end
end
end
end

0 comments on commit 8ff161a

Please sign in to comment.