diff options
author | Alessandro Desantis <desa.alessandro@gmail.com> | 2020-10-13 10:02:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-13 10:02:49 +0200 |
commit | 8ff161a4b02d395ec81f9f6331e0e11f8e81363c (patch) | |
tree | 5fcc055e81075520842cf335a6b671f17001e0bc | |
parent | 6b5c54f6998ed9ebe99e9c047e077cffdd7827b6 (diff) | |
parent | e234e5b21e1099f615b137a57458bf7f3fe3321f (diff) |
Merge pull request #160 from solidusio-contrib/aldesantis/maximum-retry-period
Add maximum_reprocessing_attempts preference
5 files changed, 114 insertions, 19 deletions
diff --git a/app/models/solidus_subscriptions/installment.rb b/app/models/solidus_subscriptions/installment.rb index 33146e6..da68112 100644 --- a/app/models/solidus_subscriptions/installment.rb +++ b/app/models/solidus_subscriptions/installment.rb @@ -110,13 +110,25 @@ module SolidusSubscriptions # @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 diff --git a/app/models/solidus_subscriptions/subscription.rb b/app/models/solidus_subscriptions/subscription.rb index 08de3c9..b598e36 100644 --- a/app/models/solidus_subscriptions/subscription.rb +++ b/app/models/solidus_subscriptions/subscription.rb @@ -107,6 +107,12 @@ module SolidusSubscriptions 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 diff --git a/lib/generators/solidus_subscriptions/install/templates/initializer.rb b/lib/generators/solidus_subscriptions/install/templates/initializer.rb index e1e9731..150f439 100644 --- a/lib/generators/solidus_subscriptions/install/templates/initializer.rb +++ b/lib/generators/solidus_subscriptions/install/templates/initializer.rb @@ -22,6 +22,10 @@ SolidusSubscriptions.configure do |config| # 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 diff --git a/lib/solidus_subscriptions/configuration.rb b/lib/solidus_subscriptions/configuration.rb index 22b7d84..9cf1408 100644 --- a/lib/solidus_subscriptions/configuration.rb +++ b/lib/solidus_subscriptions/configuration.rb @@ -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( diff --git a/spec/models/solidus_subscriptions/installment_spec.rb b/spec/models/solidus_subscriptions/installment_spec.rb index 0928c3c..16e3b91 100644 --- a/spec/models/solidus_subscriptions/installment_spec.rb +++ b/spec/models/solidus_subscriptions/installment_spec.rb @@ -141,28 +141,100 @@ RSpec.describe SolidusSubscriptions::Installment, type: :model do 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 |