solidus_subscriptions-alpha 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/README.md +128 -0
- data/Rakefile +28 -0
- data/app/assets/javascripts/spree/backend/solidus_subscriptions.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_subscriptions.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_subscriptions.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_subscriptions.css +4 -0
- data/app/controllers/solidus_subscriptions/api/v1/line_items_controller.rb +35 -0
- data/app/controllers/solidus_subscriptions/api/v1/subscriptions_controller.rb +44 -0
- data/app/controllers/spree/admin/subscriptions_controller.rb +66 -0
- data/app/decorators/spree/controllers/api/line_items/create_subscription_line_items.rb +28 -0
- data/app/decorators/spree/controllers/orders/create_subscription_line_items.rb +33 -0
- data/app/decorators/spree/line_items/subscription_line_items_association.rb +22 -0
- data/app/decorators/spree/orders/after_create.rb +15 -0
- data/app/decorators/spree/orders/finalize_creates_subscriptions.rb +19 -0
- data/app/decorators/spree/orders/subscription_line_items_association.rb +15 -0
- data/app/decorators/spree/users/have_many_subscriptions.rb +18 -0
- data/app/decorators/spree/variant_pretty_name.rb +13 -0
- data/app/jobs/solidus_subscriptions/process_installments_job.rb +22 -0
- data/app/models/solidus_subscriptions/checkout.rb +137 -0
- data/app/models/solidus_subscriptions/dispatcher.rb +32 -0
- data/app/models/solidus_subscriptions/failure_dispatcher.rb +19 -0
- data/app/models/solidus_subscriptions/installment.rb +126 -0
- data/app/models/solidus_subscriptions/installment_detail.rb +23 -0
- data/app/models/solidus_subscriptions/interval.rb +24 -0
- data/app/models/solidus_subscriptions/line_item.rb +98 -0
- data/app/models/solidus_subscriptions/line_item_builder.rb +44 -0
- data/app/models/solidus_subscriptions/order_builder.rb +40 -0
- data/app/models/solidus_subscriptions/out_of_stock_dispatcher.rb +19 -0
- data/app/models/solidus_subscriptions/payment_failed_dispatcher.rb +23 -0
- data/app/models/solidus_subscriptions/subscription.rb +217 -0
- data/app/models/solidus_subscriptions/subscription_generator.rb +60 -0
- data/app/models/solidus_subscriptions/subscription_line_item_builder.rb +21 -0
- data/app/models/solidus_subscriptions/subscription_order_promotion_rule.rb +25 -0
- data/app/models/solidus_subscriptions/subscription_promotion_rule.rb +38 -0
- data/app/models/solidus_subscriptions/success_dispatcher.rb +16 -0
- data/app/models/solidus_subscriptions/unsubscribable_error.rb +17 -0
- data/app/models/solidus_subscriptions/user_mismatch_error.rb +15 -0
- data/app/overrides/views/admin_subscribable_checkbox.rb +6 -0
- data/app/overrides/views/admin_subscriptions_menu_link.rb +8 -0
- data/app/overrides/views/subscription_line_item_fields.rb +6 -0
- data/app/views/spree/admin/promotions/rules/_subscription_order_promotion_rule.html.erb +0 -0
- data/app/views/spree/admin/promotions/rules/_subscription_promotion_rule.html.erb +0 -0
- data/app/views/spree/admin/shared/_no_objects_found.html.erb +4 -0
- data/app/views/spree/admin/shared/_subscription_tab.html.erb +3 -0
- data/app/views/spree/admin/solidus_subscriptions/subscriptions/_subscription.html.erb +66 -0
- data/app/views/spree/admin/subscriptions/_form.html.erb +81 -0
- data/app/views/spree/admin/subscriptions/_legacy_form.html.erb +81 -0
- data/app/views/spree/admin/subscriptions/_legacy_sidebar.html.erb +28 -0
- data/app/views/spree/admin/subscriptions/edit.html.erb +21 -0
- data/app/views/spree/admin/subscriptions/index.html.erb +119 -0
- data/app/views/spree/admin/subscriptions/new.html.erb +9 -0
- data/app/views/spree/admin/variants/_subscribable_checkbox.html.erb +6 -0
- data/app/views/spree/frontend/products/_subscription_line_item_fields.html.erb +30 -0
- data/config/locales/en.yml +91 -0
- data/config/routes.rb +25 -0
- data/db/migrate/20160825164850_create_solidus_subscriptions_subscriptions.rb +11 -0
- data/db/migrate/20160825173548_create_solidus_subscriptions_line_items.rb +17 -0
- data/db/migrate/20160825202248_create_solidus_subscriptions_installments.rb +23 -0
- data/db/migrate/20160825211202_create_solidus_subscriptions_installment_details.rb +22 -0
- data/db/migrate/20160825214240_add_subscribable_to_spree_variants.rb +5 -0
- data/db/migrate/20160829201653_change_subscription_line_items_installments_to_max_installments.rb +5 -0
- data/db/migrate/20160902220242_remove_state_from_solidus_susbscriptions_installment_details.rb +5 -0
- data/db/migrate/20160902220604_add_successful_to_solidus_subscriptions_installment_details.rb +5 -0
- data/db/migrate/20160902221218_add_message_to_solidus_subscriptions_installment_details.rb +5 -0
- data/db/migrate/20160922164101_add_interval_length_and_units_to_subscription_line_items.rb +8 -0
- data/db/migrate/20161006191003_add_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
- data/db/migrate/20161006191127_add_successive_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
- data/db/migrate/20161014212649_allow_spree_line_item_id_to_be_null.rb +5 -0
- data/db/migrate/20161017155749_add_order_id_to_solidus_subscriptions_installment_details.rb +6 -0
- data/db/migrate/20161017175509_remove_order_id_from_solidus_subscriptions_installments.rb +6 -0
- data/db/migrate/20161017201944_add_subscription_order_to_spree_orders.rb +5 -0
- data/db/migrate/20161221155142_add_store_to_solidus_subscriptions_subscriptions.rb +6 -0
- data/db/migrate/20161223152905_add_address_id_to_solidus_subscriptions_subscriptions.rb +7 -0
- data/db/migrate/20170106224713_change_line_item_max_installments_to_end_date.rb +6 -0
- data/db/migrate/20170111224458_change_subscription_actionable_date_to_datetime.rb +5 -0
- data/db/migrate/20170111232801_change_inteval_actionable_date_to_datetime.rb +5 -0
- data/db/migrate/20170112012407_add_config_options_to_subscriptions.rb +7 -0
- data/lib/generators/solidus_subscriptions/install/install_generator.rb +30 -0
- data/lib/solidus_subscriptions.rb +6 -0
- data/lib/solidus_subscriptions/ability.rb +19 -0
- data/lib/solidus_subscriptions/config.rb +97 -0
- data/lib/solidus_subscriptions/engine.rb +56 -0
- data/lib/solidus_subscriptions/permitted_attributes.rb +36 -0
- data/lib/solidus_subscriptions/processor.rb +108 -0
- data/lib/solidus_subscriptions/testing_support/factories.rb +5 -0
- data/lib/solidus_subscriptions/testing_support/factories/installment_detail_factory.rb +7 -0
- data/lib/solidus_subscriptions/testing_support/factories/installment_factory.rb +21 -0
- data/lib/solidus_subscriptions/testing_support/factories/line_item_factory.rb +18 -0
- data/lib/solidus_subscriptions/testing_support/factories/spree/line_item_factory.rb +17 -0
- data/lib/solidus_subscriptions/testing_support/factories/spree/order_factory.rb +18 -0
- data/lib/solidus_subscriptions/testing_support/factories/spree_modification_factory.rb +8 -0
- data/lib/solidus_subscriptions/testing_support/factories/subscription_factory.rb +43 -0
- data/lib/solidus_subscriptions/version.rb +3 -0
- data/lib/tasks/process_subscriptions.rake +6 -0
- metadata +460 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class AddIntervalLengthAndUnitsToSubscriptionLineItems < SolidusSupport::Migration[4.2]
|
|
2
|
+
def change
|
|
3
|
+
add_column :solidus_subscriptions_line_items, :interval_units, :integer
|
|
4
|
+
add_column :solidus_subscriptions_line_items, :interval_length, :integer
|
|
5
|
+
|
|
6
|
+
remove_column :solidus_subscriptions_line_items, :interval
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
class AddOrderIdToSolidusSubscriptionsInstallmentDetails < SolidusSupport::Migration[4.2]
|
|
2
|
+
def change
|
|
3
|
+
add_reference :solidus_subscriptions_installment_details, :order, index: true
|
|
4
|
+
add_foreign_key :solidus_subscriptions_installment_details, :spree_orders, column: :order_id
|
|
5
|
+
end
|
|
6
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
class AddStoreToSolidusSubscriptionsSubscriptions < SolidusSupport::Migration[4.2]
|
|
2
|
+
def change
|
|
3
|
+
add_reference :solidus_subscriptions_subscriptions, :store, index: true
|
|
4
|
+
add_foreign_key :solidus_subscriptions_subscriptions, :spree_stores, column: :store_id
|
|
5
|
+
end
|
|
6
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class AddAddressIdToSolidusSubscriptionsSubscriptions < SolidusSupport::Migration[4.2]
|
|
2
|
+
def change
|
|
3
|
+
add_reference :solidus_subscriptions_subscriptions, :shipping_address
|
|
4
|
+
add_index :solidus_subscriptions_subscriptions, :shipping_address_id, name: :index_subscription_shipping_address_id
|
|
5
|
+
add_foreign_key :solidus_subscriptions_subscriptions, :spree_addresses, column: :shipping_address_id
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class AddConfigOptionsToSubscriptions < SolidusSupport::Migration[4.2]
|
|
2
|
+
def change
|
|
3
|
+
add_column :solidus_subscriptions_subscriptions, :interval_length, :integer
|
|
4
|
+
add_column :solidus_subscriptions_subscriptions, :interval_units, :integer
|
|
5
|
+
add_column :solidus_subscriptions_subscriptions, :end_date, :datetime
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module SolidusSubscriptions
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
|
5
|
+
|
|
6
|
+
def add_javascripts
|
|
7
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_subscriptions\n"
|
|
8
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_subscriptions\n"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_stylesheets
|
|
12
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_subscriptions\n", before: /\*\//, verbose: true
|
|
13
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_subscriptions\n", before: /\*\//, verbose: true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_migrations
|
|
17
|
+
run 'bundle exec rake railties:install:migrations FROM=solidus_subscriptions'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def run_migrations
|
|
21
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
|
22
|
+
if run_migrations
|
|
23
|
+
run 'bundle exec rake db:migrate'
|
|
24
|
+
else
|
|
25
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module SolidusSubscriptions
|
|
2
|
+
class Ability
|
|
3
|
+
include CanCan::Ability
|
|
4
|
+
|
|
5
|
+
def initialize(user)
|
|
6
|
+
alias_action :create, :read, :update, :destroy, to: :crud
|
|
7
|
+
|
|
8
|
+
if user.has_spree_role?('admin')
|
|
9
|
+
can(:manage, LineItem)
|
|
10
|
+
can(:manage, Subscription)
|
|
11
|
+
else
|
|
12
|
+
can([:crud, :skip, :cancel], Subscription, user_id: user.id)
|
|
13
|
+
can(:crud, LineItem) do |li, order|
|
|
14
|
+
li.order.user == user || li.order == order
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module SolidusSubscriptions
|
|
2
|
+
module Config
|
|
3
|
+
class << self
|
|
4
|
+
# Processing Event handlers
|
|
5
|
+
# These handlers are pluggable, however it is highly encouraged that you
|
|
6
|
+
# subclass from the the dispatcher you are replacing, and call super
|
|
7
|
+
# from within the #dispatch method (if you override it)
|
|
8
|
+
#
|
|
9
|
+
# This handler is called when a susbcription order is successfully placed.
|
|
10
|
+
attr_writer :success_dispatcher_class
|
|
11
|
+
def success_dispatcher_class
|
|
12
|
+
@success_dispatcher_class ||= ::SolidusSubscriptions::SuccessDispatcher
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# This handler is called when an order cant be placed for a group of
|
|
16
|
+
# installments
|
|
17
|
+
attr_writer :failure_dispatcher_class
|
|
18
|
+
def failure_dispatcher_class
|
|
19
|
+
@failure_dispatcher_class ||= ::SolidusSubscriptions::FailureDispatcher
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# This handler is called when a payment fails on a subscription order
|
|
23
|
+
attr_writer :payment_failed_dispatcher_class
|
|
24
|
+
def payment_failed_dispatcher_class
|
|
25
|
+
@payment_failed_dispatcher_class ||= ::SolidusSubscriptions::PaymentFailedDispatcher
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# This handler is called when installemnts cannot be fulfilled due to lack
|
|
29
|
+
# of stock
|
|
30
|
+
attr_writer :out_of_stock_dispatcher
|
|
31
|
+
def out_of_stock_dispatcher_class
|
|
32
|
+
@out_of_stock_dispatcher_class ||= ::SolidusSubscriptions::OutOfStockDispatcher
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def default_gateway(&block)
|
|
36
|
+
return @gateway.call unless block_given?
|
|
37
|
+
@gateway = block
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Maximum number of times a user can skip their subscription before it
|
|
42
|
+
# must be processed
|
|
43
|
+
mattr_accessor(:maximum_successive_skips) { 1 }
|
|
44
|
+
|
|
45
|
+
# Limit on the number of times a user can skip thier subscription. Once
|
|
46
|
+
# this limit is reached, no skips are permitted
|
|
47
|
+
mattr_accessor(:maximum_total_skips) { nil }
|
|
48
|
+
|
|
49
|
+
# Time between an installment failing to be processed and the system
|
|
50
|
+
# retrying to fulfil it
|
|
51
|
+
mattr_accessor(:reprocessing_interval) { 1.day }
|
|
52
|
+
|
|
53
|
+
mattr_accessor(:minimum_cancellation_notice) { 1.day }
|
|
54
|
+
|
|
55
|
+
# Which queue is responsible for processing subscriptions
|
|
56
|
+
mattr_accessor(:processing_queue) { :default }
|
|
57
|
+
|
|
58
|
+
# SolidusSubscriptions::LineItem attributes which are allowed to
|
|
59
|
+
# be updated from user data
|
|
60
|
+
#
|
|
61
|
+
# This is useful in the case where certain fields should not be allowed to
|
|
62
|
+
# be modified by the user. This locks these attributes from being passed
|
|
63
|
+
# in to the orders controller (or the api controller).
|
|
64
|
+
|
|
65
|
+
# Ie. if a store does not want to allow users to configure the end date of
|
|
66
|
+
# a subscription. Add this to an initializer:
|
|
67
|
+
|
|
68
|
+
# ```
|
|
69
|
+
# SolidusSubscriptions::Config.subscription_line_item_attributes = [
|
|
70
|
+
# :quantity,
|
|
71
|
+
# :interval_length,
|
|
72
|
+
# :interval_units,
|
|
73
|
+
# :subscribable_id
|
|
74
|
+
# ]
|
|
75
|
+
# ```
|
|
76
|
+
# This configuration also easily allows the gem to be customized to track
|
|
77
|
+
# more information on the subcriptions line items.
|
|
78
|
+
mattr_accessor(:subscription_line_item_attributes) do
|
|
79
|
+
[
|
|
80
|
+
:quantity,
|
|
81
|
+
:subscribable_id,
|
|
82
|
+
:interval_length,
|
|
83
|
+
:interval_units,
|
|
84
|
+
:end_date
|
|
85
|
+
]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# SolidusSubscriptions::Subscription attributes which are allowed to
|
|
89
|
+
# be updated from user data
|
|
90
|
+
mattr_accessor(:subscription_attributes) do
|
|
91
|
+
[
|
|
92
|
+
:actionable_date,
|
|
93
|
+
shipping_address_attributes: Spree::PermittedAttributes.address_attributes
|
|
94
|
+
]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module SolidusSubscriptions
|
|
2
|
+
class Engine < Rails::Engine
|
|
3
|
+
require 'spree/core'
|
|
4
|
+
require 'solidus_subscriptions/permitted_attributes'
|
|
5
|
+
require 'solidus_subscriptions/config'
|
|
6
|
+
require 'solidus_subscriptions/processor'
|
|
7
|
+
|
|
8
|
+
isolate_namespace SolidusSubscriptions
|
|
9
|
+
engine_name 'solidus_subscriptions'
|
|
10
|
+
|
|
11
|
+
# use rspec for tests
|
|
12
|
+
config.generators do |g|
|
|
13
|
+
g.test_framework :rspec
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
config.autoload_paths << config.root.join('app', 'jobs')
|
|
17
|
+
|
|
18
|
+
initializer 'configure spree subcription permitted attributes', after: 'require subscription lib helpers' do
|
|
19
|
+
PermittedAttributes.update_spree_permiteed_attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
initializer 'solidus_subscriptions.configs', before: "require subscription lib helpers" do
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
initializer 'register_subscription_promotion_rule', after: 'spree.promo.register.promotion.rules' do |app|
|
|
26
|
+
app.config.spree.promotions.rules << 'SolidusSubscriptions::SubscriptionPromotionRule'
|
|
27
|
+
app.config.spree.promotions.rules << 'SolidusSubscriptions::SubscriptionOrderPromotionRule'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
initializer 'subscriptions_backend' do
|
|
31
|
+
next unless Spree::Backend::Config.respond_to?(:menu_items)
|
|
32
|
+
Spree::Backend::Config.configure do |config|
|
|
33
|
+
config.menu_items << config.class::MenuItem.new(
|
|
34
|
+
[:subscriptions],
|
|
35
|
+
'repeat',
|
|
36
|
+
url: :admin_subscriptions_path,
|
|
37
|
+
condition: ->{ can?(:admin, SolidusSubscriptions::Subscription) }
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.activate
|
|
43
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/decorators/**/*.rb')) do |c|
|
|
44
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
Spree::Ability.register_ability(SolidusSubscriptions::Ability)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
config.to_prepare(&method(:activate).to_proc)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.table_name_prefix
|
|
54
|
+
'solidus_subscriptions_'
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# This module is responsible for managing what attributes can be updated
|
|
2
|
+
# through the api. It also overrides Spree::Permitted attributes to allow the
|
|
3
|
+
# solidus api to accept nested params for subscription models as well
|
|
4
|
+
module SolidusSubscriptions
|
|
5
|
+
module PermittedAttributes
|
|
6
|
+
class << self
|
|
7
|
+
def update_spree_permiteed_attributes
|
|
8
|
+
Spree::PermittedAttributes.line_item_attributes << {
|
|
9
|
+
subscription_line_items_attributes: nested(
|
|
10
|
+
subscription_line_item_attributes
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
Spree::PermittedAttributes.user_attributes << {
|
|
15
|
+
subscriptions_attributes: nested(subscription_attributes)
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def subscription_line_item_attributes
|
|
20
|
+
[Config.subscription_line_item_attributes]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def subscription_attributes
|
|
24
|
+
Config.subscription_attributes | [
|
|
25
|
+
{ line_items_attributes: nested(subscription_line_item_attributes) - [:subscribable_id] }
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def nested(attributes)
|
|
32
|
+
attributes | [:id]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# This class is responsible for finding subscriptions and installments
|
|
2
|
+
# which need to be processed. It will group them together by user and attempts
|
|
3
|
+
# to process them together. Subscriptions will also be grouped by their
|
|
4
|
+
# shiping address id.
|
|
5
|
+
#
|
|
6
|
+
# This class passes the reponsibility of actually creating the order off onto
|
|
7
|
+
# the consolidated installment class.
|
|
8
|
+
#
|
|
9
|
+
# This class generates `ProcessInstallmentsJob`s
|
|
10
|
+
module SolidusSubscriptions
|
|
11
|
+
class Processor
|
|
12
|
+
class << self
|
|
13
|
+
# Find all actionable subscriptions and intallments, group them together
|
|
14
|
+
# by user, and schedule a processing job for the group as a batch
|
|
15
|
+
def run
|
|
16
|
+
batched_users_to_be_processed.each { |batch| new(batch).build_jobs }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def batched_users_to_be_processed
|
|
22
|
+
subscriptions = SolidusSubscriptions::Subscription.arel_table
|
|
23
|
+
installments = SolidusSubscriptions::Installment.arel_table
|
|
24
|
+
|
|
25
|
+
Spree::User.
|
|
26
|
+
joins(:subscriptions).
|
|
27
|
+
joins(
|
|
28
|
+
subscriptions.
|
|
29
|
+
join(installments, Arel::Nodes::OuterJoin).
|
|
30
|
+
on(subscriptions[:id].eq(installments[:subscription_id])).
|
|
31
|
+
join_sources
|
|
32
|
+
).
|
|
33
|
+
where(
|
|
34
|
+
SolidusSubscriptions::Subscription.actionable.arel.constraints.reduce(:and).
|
|
35
|
+
or(SolidusSubscriptions::Installment.actionable.arel.constraints.reduce(:and))
|
|
36
|
+
).
|
|
37
|
+
distinct.
|
|
38
|
+
find_in_batches
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [Array<Spree.user_class>]
|
|
43
|
+
attr_reader :users
|
|
44
|
+
|
|
45
|
+
# Get a new instance of the SolidusSubscriptions::Processor
|
|
46
|
+
#
|
|
47
|
+
# @param users [Array<Spree.user_class>] A list of users with actionable
|
|
48
|
+
# subscriptions or installments
|
|
49
|
+
#
|
|
50
|
+
# @return [SolidusSubscriptions::Processor]
|
|
51
|
+
def initialize(users)
|
|
52
|
+
@users = users
|
|
53
|
+
@installments = {}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Create `ProcessInstallmentsJob`s for the users used to initalize the
|
|
57
|
+
# instance
|
|
58
|
+
def build_jobs
|
|
59
|
+
users.map do |user|
|
|
60
|
+
installemts_by_address_and_user = installments(user).group_by do |i|
|
|
61
|
+
i.subscription.shipping_address_id
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
installemts_by_address_and_user.values.each do |grouped_installments|
|
|
65
|
+
ProcessInstallmentsJob.perform_later grouped_installments.map(&:id)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def subscriptions_by_id
|
|
73
|
+
@subscriptions_by_id ||= Subscription.
|
|
74
|
+
actionable.
|
|
75
|
+
includes(:line_items, :user).
|
|
76
|
+
where(user_id: user_ids).
|
|
77
|
+
group_by(&:user_id)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def retry_installments
|
|
81
|
+
@failed_installments ||= Installment.
|
|
82
|
+
actionable.
|
|
83
|
+
includes(:subscription).
|
|
84
|
+
where(solidus_subscriptions_subscriptions: { user_id: user_ids }).
|
|
85
|
+
group_by { |i| i.subscription.user_id }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def installments(user)
|
|
89
|
+
@installments[user.id] ||= retry_installments.fetch(user.id, []) + new_installments(user)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def new_installments(user)
|
|
93
|
+
ActiveRecord::Base.transaction do
|
|
94
|
+
subscriptions_by_id.fetch(user.id, []).map do |sub|
|
|
95
|
+
sub.successive_skip_count = 0
|
|
96
|
+
sub.advance_actionable_date
|
|
97
|
+
sub.cancel! if sub.pending_cancellation?
|
|
98
|
+
sub.deactivate! if sub.can_be_deactivated?
|
|
99
|
+
sub.installments.create!
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def user_ids
|
|
105
|
+
@user_ids ||= users.map(&:id)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|