summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Desantis <desa.alessandro@gmail.com>2020-10-13 10:02:49 +0200
committerGitHub <noreply@github.com>2020-10-13 10:02:49 +0200
commit8ff161a4b02d395ec81f9f6331e0e11f8e81363c (patch)
tree5fcc055e81075520842cf335a6b671f17001e0bc
parent6b5c54f6998ed9ebe99e9c047e077cffdd7827b6 (diff)
parente234e5b21e1099f615b137a57458bf7f3fe3321f (diff)
Merge pull request #160 from solidusio-contrib/aldesantis/maximum-retry-period
Add maximum_reprocessing_attempts preference
-rw-r--r--app/models/solidus_subscriptions/installment.rb16
-rw-r--r--app/models/solidus_subscriptions/subscription.rb6
-rw-r--r--lib/generators/solidus_subscriptions/install/templates/initializer.rb4
-rw-r--r--lib/solidus_subscriptions/configuration.rb3
-rw-r--r--spec/models/solidus_subscriptions/installment_spec.rb104
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