diff options
-rw-r--r-- | app/jobs/solidus_subscriptions/process_subscription_job.rb | 31 | ||||
-rw-r--r-- | lib/solidus_subscriptions/processor.rb | 31 | ||||
-rw-r--r-- | spec/jobs/solidus_subscriptions/process_subscription_job_spec.rb | 83 | ||||
-rw-r--r-- | spec/lib/solidus_subscriptions/processor_spec.rb | 132 |
4 files changed, 140 insertions, 137 deletions
diff --git a/app/jobs/solidus_subscriptions/process_subscription_job.rb b/app/jobs/solidus_subscriptions/process_subscription_job.rb new file mode 100644 index 0000000..569fa6f --- /dev/null +++ b/app/jobs/solidus_subscriptions/process_subscription_job.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module SolidusSubscriptions + class ProcessSubscriptionJob < ApplicationJob + queue_as { SolidusSubscriptions.configuration.processing_queue } + + def perform(subscription) + ActiveRecord::Base.transaction do + if SolidusSubscriptions.configuration.clear_past_installments + subscription.installments.unfulfilled.actionable.each do |installment| + installment.update!(actionable_date: nil) + end + end + + if subscription.actionable? + subscription.successive_skip_count = 0 + subscription.advance_actionable_date + + subscription.installments.create!(actionable_date: Time.zone.now) + end + + subscription.cancel! if subscription.pending_cancellation? + subscription.deactivate! if subscription.can_be_deactivated? + + subscription.installments.actionable.find_each do |installment| + SolidusSubscriptions::ProcessInstallmentJob.perform_later(installment) + end + end + end + end +end diff --git a/lib/solidus_subscriptions/processor.rb b/lib/solidus_subscriptions/processor.rb index ffc274b..04b84e8 100644 --- a/lib/solidus_subscriptions/processor.rb +++ b/lib/solidus_subscriptions/processor.rb @@ -4,32 +4,13 @@ module SolidusSubscriptions class Processor class << self def run - SolidusSubscriptions::Subscription.actionable.find_each(&method(:process_subscription)) - SolidusSubscriptions::Installment.actionable.find_each(&method(:process_installment)) - end - - private - - def process_subscription(subscription) - ActiveRecord::Base.transaction do - subscription.successive_skip_count = 0 - subscription.advance_actionable_date - - subscription.cancel! if subscription.pending_cancellation? - subscription.deactivate! if subscription.can_be_deactivated? - - if SolidusSubscriptions.configuration.clear_past_installments - subscription.installments.unfulfilled.actionable.each do |installment| - installment.update!(actionable_date: nil) - end + SolidusSubscriptions::Subscription + .where(installments: SolidusSubscriptions::Installment.actionable) + .or(SolidusSubscriptions::Subscription.actionable) + .distinct + .find_each do |subscription| + ProcessSubscriptionJob.perform_later(subscription) end - - subscription.installments.create!(actionable_date: Time.zone.now) - end - end - - def process_installment(installment) - ProcessInstallmentJob.perform_later(installment) end end end diff --git a/spec/jobs/solidus_subscriptions/process_subscription_job_spec.rb b/spec/jobs/solidus_subscriptions/process_subscription_job_spec.rb new file mode 100644 index 0000000..1a3cf6f --- /dev/null +++ b/spec/jobs/solidus_subscriptions/process_subscription_job_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +RSpec.describe SolidusSubscriptions::ProcessSubscriptionJob do + context 'when clear_past_installments is enabled' do + it 'voids the actionable date of the unfulfilled installments' do + stub_config(clear_past_installments: true) + subscription = create(:subscription) + unfulfilled_installment = create(:installment, :failed, subscription: subscription) + + described_class.perform_now(subscription) + + expect(unfulfilled_installment.reload.actionable_date).to eq(nil) + end + end + + context 'when the subscription is actionable' do + it 'resets the successive_skip_count' do + subscription = create(:subscription, :actionable, successive_skip_count: 3) + + described_class.perform_now(subscription) + + expect(subscription.reload.successive_skip_count).to eq(0) + end + + it 'creates a new installment' do + subscription = create(:subscription, :actionable) + + described_class.perform_now(subscription) + + expect(subscription.installments.count).to eq(1) + end + + it 'advances the actionable date' do + subscription = create(:subscription, :actionable) + subscription.update_columns(interval_length: 1, interval_units: 'week') + old_actionable_date = subscription.reload.actionable_date + + described_class.perform_now(subscription) + + expect(subscription.reload.actionable_date.to_date).to eq((old_actionable_date + 1.week).to_date) + end + end + + context 'when the subscription is pending cancellation' do + it 'cancels the subscription' do + subscription = create( + :subscription, + :actionable, + :pending_cancellation, + ) + described_class.perform_now(subscription) + + expect(subscription.reload.state).to eq('canceled') + end + end + + context 'when the subscription is pending of deactivation' do + it 'deactivates the subscription' do + subscription = create( + :subscription, + :actionable, + interval_units: 'week', + interval_length: 2, + end_date: 3.days.from_now, + ) + described_class.perform_now(subscription) + + expect(subscription.reload.state).to eq('inactive') + end + end + + it 'schedules all the subscription actionable installments for processing' do + subscription = create(:subscription, :actionable) + unfulfilled_installment = create(:installment, :failed, subscription: subscription) + + described_class.perform_now(subscription) + + new_installment = subscription.reload.installments.last + [unfulfilled_installment, new_installment].each do |installment| + expect(SolidusSubscriptions::ProcessInstallmentJob).to have_been_enqueued.with(installment) + end + end +end diff --git a/spec/lib/solidus_subscriptions/processor_spec.rb b/spec/lib/solidus_subscriptions/processor_spec.rb index e82c0e9..5deaba4 100644 --- a/spec/lib/solidus_subscriptions/processor_spec.rb +++ b/spec/lib/solidus_subscriptions/processor_spec.rb @@ -1,124 +1,32 @@ -RSpec.describe SolidusSubscriptions::Processor, :checkout do - shared_examples 'processes the subscription' do - it 'resets the successive_skip_count' do - subscription - subscription.update_columns(successive_skip_count: 3) +RSpec.describe SolidusSubscriptions::Processor do + it 'schedules the processing of actionable subscriptions' do + actionable_subscription = create(:subscription, :actionable) - described_class.run + described_class.run - expect(subscription.reload.successive_skip_count).to eq(0) - end - - context 'with clear_past_installments set to true' do - it 'clears any past unfulfilled installments' do - stub_config(clear_past_installments: true) - subscription - installment = create(:installment, :actionable, subscription: subscription) - - described_class.run - - expect(installment.reload.actionable_date).to eq(nil) - end - end - - context 'with clear_past_installments set to false' do - it 'does not clear any past unfulfilled installments' do - stub_config(clear_past_installments: false) - subscription - installment = create(:installment, :actionable, subscription: subscription) - - described_class.run - - expect(installment.reload.actionable_date).not_to be_nil - end - end - - it 'creates a new installment' do - subscription - - described_class.run - - expect(subscription.installments.count).to eq(1) - end - - it 'schedules the newly created installment for processing' do - subscription - - described_class.run - - expect(SolidusSubscriptions::ProcessInstallmentJob).to have_been_enqueued - .with(subscription.installments.last) - end - - it 'schedules other actionable installments for processing' do - actionable_installment = create(:installment, :actionable) - - described_class.run - - expect(SolidusSubscriptions::ProcessInstallmentJob).to have_been_enqueued - .with(actionable_installment) - end + expect(SolidusSubscriptions::ProcessSubscriptionJob).to have_been_enqueued + .with(actionable_subscription) end - shared_examples 'schedules the subscription for reprocessing' do - it 'advances the actionable_date' do - subscription - subscription.update_columns(interval_length: 1, interval_units: 'week') - old_actionable_date = subscription.actionable_date + it 'schedules the processing of non actionable subscriptions with actionable installments' do + subscription_with_actionable_installment = create( + :subscription, + actionable_date: Time.zone.today + 7.days, + installments: [create(:installment, :actionable)] + ) - described_class.run + described_class.run - expect(subscription.reload.actionable_date.to_date).to eq((old_actionable_date + 1.week).to_date) - end + expect(SolidusSubscriptions::ProcessSubscriptionJob).to have_been_enqueued + .with(subscription_with_actionable_installment) end - context 'with a regular subscription' do - let(:subscription) { create(:subscription, :actionable) } - - include_examples 'processes the subscription' - include_examples 'schedules the subscription for reprocessing' - end - - context 'with a subscription that is pending deactivation' do - let(:subscription) do - create( - :subscription, - :actionable, - interval_units: 'week', - interval_length: 2, - end_date: 3.days.from_now, - ) - end - - include_examples 'processes the subscription' - include_examples 'schedules the subscription for reprocessing' - - it 'deactivates the subscription' do - subscription - - described_class.run - - expect(subscription.reload.state).to eq('inactive') - end - end - - context 'with a subscription that is pending cancellation' do - let(:subscription) do - create( - :subscription, - :actionable, - :pending_cancellation, - ) - end - - include_examples 'processes the subscription' - - it 'cancels the subscription' do - subscription + it 'does not schedule the processing of non actionable subscriptions' do + non_actionable_subscription = create(:subscription, actionable_date: Time.zone.today + 14.days) - described_class.run + described_class.run - expect(subscription.reload.state).to eq('canceled') - end + expect(SolidusSubscriptions::ProcessSubscriptionJob).not_to have_been_enqueued + .with(non_actionable_subscription) end end |