summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Desantis <desa.alessandro@gmail.com>2020-10-09 13:43:18 +0200
committerAlessandro Desantis <desa.alessandro@gmail.com>2020-10-10 10:18:17 +0200
commite234e5b21e1099f615b137a57458bf7f3fe3321f (patch)
tree5fcc055e81075520842cf335a6b671f17001e0bc
parent2086c908517fd66d1edee8bfbec4975fdf03b052 (diff)
Cancel subscription once it reaches the maximum retry attempts
-rw-r--r--app/models/solidus_subscriptions/installment.rb16
-rw-r--r--app/models/solidus_subscriptions/subscription.rb6
-rw-r--r--spec/models/solidus_subscriptions/installment_spec.rb104
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