From 12780b8ed99f15da00c6959b62729762b35f4acc Mon Sep 17 00:00:00 2001 From: Brendan Deere Date: Fri, 23 Sep 2016 15:04:11 -0700 Subject: Add Processor This class looks up all actionable subscriptions and installments, groups them by user and schedules them to be reprocessed. --- lib/solidus_subscriptions/processor.rb | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 lib/solidus_subscriptions/processor.rb (limited to 'lib/solidus_subscriptions/processor.rb') diff --git a/lib/solidus_subscriptions/processor.rb b/lib/solidus_subscriptions/processor.rb new file mode 100644 index 0000000..97b39df --- /dev/null +++ b/lib/solidus_subscriptions/processor.rb @@ -0,0 +1,90 @@ +# This class is responsible for finding subscriptions and installments +# which need to be processed. It will group them together by user and attempts +# to process them together. +# +# This class passes the reponsibility of actually creating the order off onto +# the consolidated installment class. +# +# This class generates `ProcessInstallmentsJob`s +module SolidusSubscriptions + class Processor + class << self + # Find all actionable subscriptions and intallments, group them together + # by user, and schedule a processing job for the group as a batch + def run + batched_users_to_be_processed.each { |batch| new(batch).build_jobs } + end + + private + + def batched_users_to_be_processed + subscriptions = Subscription.arel_table + installments = Installment.arel_table + + Spree::User. + joins(:subscriptions). + joins( + subscriptions. + join(installments, Arel::Nodes::OuterJoin). + on(subscriptions[:id].eq(installments[:subscription_id])). + join_sources + ). + where( + Subscription.actionable.arel.constraints.reduce(:and). + or(Installment.actionable.arel.constraints.reduce(:and)) + ). + distinct. + find_in_batches + end + end + + # @return [Array] + attr_reader :users + + # Get a new instance of the SolidusSubscriptions::Processor + # + # @param users [Array] A list of users with actionable + # subscriptions or installments + # + # @return [SolidusSubscriptions::Processor] + def initialize(users) + @users = users + @installments = {} + end + + # Create `ProcessInstallmentsJob`s for the users used to initalize the + # instance + def build_jobs + users.map { |user| ProcessInstallmentsJob.perform_later installments(user) } + end + + private + + def subscriptions_by_id + @subscriptions_by_id ||= Subscription. + actionable. + where(user_id: user_ids). + group_by(&:user_id) + end + + def retry_installments + @failed_installments ||= Installment. + actionable. + includes(:subscription). + where(solidus_subscriptions_subscriptions: { user_id: user_ids }). + group_by { |i| i.subscription.user_id } + end + + def installments(user) + @installments[user.id] ||= retry_installments.fetch(user.id, []) + new_installments(user) + end + + def new_installments(user) + subscriptions_by_id.fetch(user.id, []).map { |sub| sub.installments.create! } + end + + def user_ids + @user_ids ||= users.map(&:id) + end + end +end -- cgit v1.2.3