diff options
author | Alessandro Desantis <desa.alessandro@gmail.com> | 2020-10-09 13:43:18 +0200 |
---|---|---|
committer | Alessandro Desantis <desa.alessandro@gmail.com> | 2020-10-10 10:18:17 +0200 |
commit | e234e5b21e1099f615b137a57458bf7f3fe3321f (patch) | |
tree | 5fcc055e81075520842cf335a6b671f17001e0bc | |
parent | 2086c908517fd66d1edee8bfbec4975fdf03b052 (diff) |
Cancel subscription once it reaches the maximum retry attempts
-rw-r--r-- | app/models/solidus_subscriptions/installment.rb | 16 | ||||
-rw-r--r-- | app/models/solidus_subscriptions/subscription.rb | 6 | ||||
-rw-r--r-- | spec/models/solidus_subscriptions/installment_spec.rb | 104 |
3 files changed, 108 insertions, 18 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/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 |