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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +26 -0
  3. data/README.md +128 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/spree/backend/solidus_subscriptions.js +2 -0
  6. data/app/assets/javascripts/spree/frontend/solidus_subscriptions.js +2 -0
  7. data/app/assets/stylesheets/spree/backend/solidus_subscriptions.css +4 -0
  8. data/app/assets/stylesheets/spree/frontend/solidus_subscriptions.css +4 -0
  9. data/app/controllers/solidus_subscriptions/api/v1/line_items_controller.rb +35 -0
  10. data/app/controllers/solidus_subscriptions/api/v1/subscriptions_controller.rb +44 -0
  11. data/app/controllers/spree/admin/subscriptions_controller.rb +66 -0
  12. data/app/decorators/spree/controllers/api/line_items/create_subscription_line_items.rb +28 -0
  13. data/app/decorators/spree/controllers/orders/create_subscription_line_items.rb +33 -0
  14. data/app/decorators/spree/line_items/subscription_line_items_association.rb +22 -0
  15. data/app/decorators/spree/orders/after_create.rb +15 -0
  16. data/app/decorators/spree/orders/finalize_creates_subscriptions.rb +19 -0
  17. data/app/decorators/spree/orders/subscription_line_items_association.rb +15 -0
  18. data/app/decorators/spree/users/have_many_subscriptions.rb +18 -0
  19. data/app/decorators/spree/variant_pretty_name.rb +13 -0
  20. data/app/jobs/solidus_subscriptions/process_installments_job.rb +22 -0
  21. data/app/models/solidus_subscriptions/checkout.rb +137 -0
  22. data/app/models/solidus_subscriptions/dispatcher.rb +32 -0
  23. data/app/models/solidus_subscriptions/failure_dispatcher.rb +19 -0
  24. data/app/models/solidus_subscriptions/installment.rb +126 -0
  25. data/app/models/solidus_subscriptions/installment_detail.rb +23 -0
  26. data/app/models/solidus_subscriptions/interval.rb +24 -0
  27. data/app/models/solidus_subscriptions/line_item.rb +98 -0
  28. data/app/models/solidus_subscriptions/line_item_builder.rb +44 -0
  29. data/app/models/solidus_subscriptions/order_builder.rb +40 -0
  30. data/app/models/solidus_subscriptions/out_of_stock_dispatcher.rb +19 -0
  31. data/app/models/solidus_subscriptions/payment_failed_dispatcher.rb +23 -0
  32. data/app/models/solidus_subscriptions/subscription.rb +217 -0
  33. data/app/models/solidus_subscriptions/subscription_generator.rb +60 -0
  34. data/app/models/solidus_subscriptions/subscription_line_item_builder.rb +21 -0
  35. data/app/models/solidus_subscriptions/subscription_order_promotion_rule.rb +25 -0
  36. data/app/models/solidus_subscriptions/subscription_promotion_rule.rb +38 -0
  37. data/app/models/solidus_subscriptions/success_dispatcher.rb +16 -0
  38. data/app/models/solidus_subscriptions/unsubscribable_error.rb +17 -0
  39. data/app/models/solidus_subscriptions/user_mismatch_error.rb +15 -0
  40. data/app/overrides/views/admin_subscribable_checkbox.rb +6 -0
  41. data/app/overrides/views/admin_subscriptions_menu_link.rb +8 -0
  42. data/app/overrides/views/subscription_line_item_fields.rb +6 -0
  43. data/app/views/spree/admin/promotions/rules/_subscription_order_promotion_rule.html.erb +0 -0
  44. data/app/views/spree/admin/promotions/rules/_subscription_promotion_rule.html.erb +0 -0
  45. data/app/views/spree/admin/shared/_no_objects_found.html.erb +4 -0
  46. data/app/views/spree/admin/shared/_subscription_tab.html.erb +3 -0
  47. data/app/views/spree/admin/solidus_subscriptions/subscriptions/_subscription.html.erb +66 -0
  48. data/app/views/spree/admin/subscriptions/_form.html.erb +81 -0
  49. data/app/views/spree/admin/subscriptions/_legacy_form.html.erb +81 -0
  50. data/app/views/spree/admin/subscriptions/_legacy_sidebar.html.erb +28 -0
  51. data/app/views/spree/admin/subscriptions/edit.html.erb +21 -0
  52. data/app/views/spree/admin/subscriptions/index.html.erb +119 -0
  53. data/app/views/spree/admin/subscriptions/new.html.erb +9 -0
  54. data/app/views/spree/admin/variants/_subscribable_checkbox.html.erb +6 -0
  55. data/app/views/spree/frontend/products/_subscription_line_item_fields.html.erb +30 -0
  56. data/config/locales/en.yml +91 -0
  57. data/config/routes.rb +25 -0
  58. data/db/migrate/20160825164850_create_solidus_subscriptions_subscriptions.rb +11 -0
  59. data/db/migrate/20160825173548_create_solidus_subscriptions_line_items.rb +17 -0
  60. data/db/migrate/20160825202248_create_solidus_subscriptions_installments.rb +23 -0
  61. data/db/migrate/20160825211202_create_solidus_subscriptions_installment_details.rb +22 -0
  62. data/db/migrate/20160825214240_add_subscribable_to_spree_variants.rb +5 -0
  63. data/db/migrate/20160829201653_change_subscription_line_items_installments_to_max_installments.rb +5 -0
  64. data/db/migrate/20160902220242_remove_state_from_solidus_susbscriptions_installment_details.rb +5 -0
  65. data/db/migrate/20160902220604_add_successful_to_solidus_subscriptions_installment_details.rb +5 -0
  66. data/db/migrate/20160902221218_add_message_to_solidus_subscriptions_installment_details.rb +5 -0
  67. data/db/migrate/20160922164101_add_interval_length_and_units_to_subscription_line_items.rb +8 -0
  68. data/db/migrate/20161006191003_add_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
  69. data/db/migrate/20161006191127_add_successive_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
  70. data/db/migrate/20161014212649_allow_spree_line_item_id_to_be_null.rb +5 -0
  71. data/db/migrate/20161017155749_add_order_id_to_solidus_subscriptions_installment_details.rb +6 -0
  72. data/db/migrate/20161017175509_remove_order_id_from_solidus_subscriptions_installments.rb +6 -0
  73. data/db/migrate/20161017201944_add_subscription_order_to_spree_orders.rb +5 -0
  74. data/db/migrate/20161221155142_add_store_to_solidus_subscriptions_subscriptions.rb +6 -0
  75. data/db/migrate/20161223152905_add_address_id_to_solidus_subscriptions_subscriptions.rb +7 -0
  76. data/db/migrate/20170106224713_change_line_item_max_installments_to_end_date.rb +6 -0
  77. data/db/migrate/20170111224458_change_subscription_actionable_date_to_datetime.rb +5 -0
  78. data/db/migrate/20170111232801_change_inteval_actionable_date_to_datetime.rb +5 -0
  79. data/db/migrate/20170112012407_add_config_options_to_subscriptions.rb +7 -0
  80. data/lib/generators/solidus_subscriptions/install/install_generator.rb +30 -0
  81. data/lib/solidus_subscriptions.rb +6 -0
  82. data/lib/solidus_subscriptions/ability.rb +19 -0
  83. data/lib/solidus_subscriptions/config.rb +97 -0
  84. data/lib/solidus_subscriptions/engine.rb +56 -0
  85. data/lib/solidus_subscriptions/permitted_attributes.rb +36 -0
  86. data/lib/solidus_subscriptions/processor.rb +108 -0
  87. data/lib/solidus_subscriptions/testing_support/factories.rb +5 -0
  88. data/lib/solidus_subscriptions/testing_support/factories/installment_detail_factory.rb +7 -0
  89. data/lib/solidus_subscriptions/testing_support/factories/installment_factory.rb +21 -0
  90. data/lib/solidus_subscriptions/testing_support/factories/line_item_factory.rb +18 -0
  91. data/lib/solidus_subscriptions/testing_support/factories/spree/line_item_factory.rb +17 -0
  92. data/lib/solidus_subscriptions/testing_support/factories/spree/order_factory.rb +18 -0
  93. data/lib/solidus_subscriptions/testing_support/factories/spree_modification_factory.rb +8 -0
  94. data/lib/solidus_subscriptions/testing_support/factories/subscription_factory.rb +43 -0
  95. data/lib/solidus_subscriptions/version.rb +3 -0
  96. data/lib/tasks/process_subscriptions.rake +6 -0
  97. metadata +460 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0d10eb4c148ba35b53a03253ce3ee04e8a0e4ee
4
+ data.tar.gz: 1aaf99dda496e4de2eb61f8ab4df96d9bc663947
5
+ SHA512:
6
+ metadata.gz: f055e7676ddb8241132a8e7a0189622a9a115e88b0d9e92b274d5d795fea4a69922074c2da45e251875a1e56ac8d17f18051b72680d3a66ab048f6de9e969cb0
7
+ data.tar.gz: b50200bee8ed2f9e36536bad5196ba265fa98479dc12b4c0f8d0575ea962cb4d98c4446e70ecc9030906bea64dc7b08ac85d89f2a3c2df4df7d37c83127102a7
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2016 [name of plugin creator]
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,128 @@
1
+ # SolidusSubscriptions
2
+
3
+ A Solidus extension for subscriptions. **Important note**: this is
4
+ **PRE-RELEASE** software and is currently a work-in-progress. There are **no
5
+ guarantees** this will work for your store!
6
+
7
+ Sponsored by [Goby](https://www.goby.co) - Electrify your routine!
8
+
9
+ ## Installation
10
+
11
+ Add solidus_subscriptions to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'solidus_subscriptions', github: 'solidusio-contrib/solidus_subscriptions'
15
+ ```
16
+
17
+ Bundle your dependencies and run the installation generator:
18
+
19
+ ```shell
20
+ bundle
21
+ bundle exec rails g solidus_subscriptions:install
22
+ ```
23
+
24
+ ## Configuration
25
+ This gem requires a gateway which supports credit cards in order to process
26
+ subscription orders.
27
+
28
+ Add this to specify the gateway used by the gem:
29
+ an initializer.
30
+
31
+ ```ruby
32
+ SolidusSubscriptions::Config.default_gateway { my_gateway }
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Purchasing Subscriptions
38
+ By default only Spree::Variants can be subscribed to. To subscribe to a variant, it
39
+ must have the `:subscribable` attribute set to true.
40
+
41
+ To subscribe to a variant include the following parameters when posting to
42
+ `/orders/populate` (The add to cart button on the product page):
43
+
44
+ ```js
45
+ {
46
+ // other add to cart params
47
+ subscription_line_item: {
48
+ quantity: 2, // number of units in each subscription order.
49
+ subscribable_id: 1234, // Which variant the subscription is for.
50
+ interval_length: 1, // The time between subscription activations.
51
+ interval_units: "month", // A plural qualifier for length.
52
+ // Can be one of "day", "week", "month", or "year".
53
+ end_date: '2011/12/13' // Stop processing after this date
54
+ // (use null to process the subscription ad nauseam)
55
+ }
56
+ }
57
+ ```
58
+
59
+ This will associate a `SolidusSubscriptions::LineItem` to the line item
60
+ being added to the cart.
61
+
62
+ The customer will not be charged for the subscription until it is processed. The
63
+ subscription line items should be shown to the user on the cart page by
64
+ looping over `Spree::Order#subscription_line_items`.
65
+ `SolidusSubscriptions::LineItem#dummy_line_item` may be useful to help you display
66
+ the subscription line item with your existing cart infrastructure.
67
+
68
+ When the order is finalized, a `SolidusSubscriptions::Subscription` will be
69
+ created for each group of subscription line items which can be fulfilled by a single
70
+ subscription.
71
+
72
+ #### Example:
73
+
74
+ An order is finalized and has following associated subscription line items:
75
+
76
+ 1. { subscribable_id: 1, interval_length: 1, interval_units: 'month'}
77
+ 2. { subscribable_id: 2, interval_length: 1, interval_units: 'month' }
78
+ 3. { subscribable_id: 1, interval_length: 2, interval_units: 'month' }
79
+
80
+ This will generate 2 Subscriptions objects. The first related to
81
+ subscription_line_items 1 & 2. The second related to line item 3.
82
+
83
+ ### Processing Subscriptions
84
+
85
+ To process actionable subscriptions simply run:
86
+
87
+ `bundle exec rake solidus_subscriptions:process`
88
+
89
+ To schedule this task we suggest using the [Whenever](https://github.com/javan/whenever) gem.
90
+
91
+ This task creates ActiveJobs which can be fulfilled by the queue library of your
92
+ choice.
93
+
94
+ ### Guest Checkout
95
+
96
+ Subscriptions require a user to be present to allow them to be managed after
97
+ they are purchased.
98
+
99
+ Because of this you must disabling guest checkout for orders
100
+ which contain `subscription_line_items`.
101
+
102
+ An example of this would be adding this to the registration page:
103
+
104
+ ```erb
105
+ <%# spree/checkout/registration.html.erb %>
106
+ <% if Spree::Config[:allow_guest_checkout] && current_order.subscription_line_items.empty? %>
107
+ ```
108
+
109
+ This allows guests to add subscriptions to their carts as guests, but forces them
110
+ to login or create an account before purchasing them.
111
+
112
+ ## Testing
113
+
114
+ First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs, and [Rubocop](https://github.com/bbatsov/rubocop) static code analysis. The dummy app can be regenerated by using `rake test_app`.
115
+
116
+ ```shell
117
+ bundle
118
+ bundle exec rake
119
+ ```
120
+
121
+ When testing your applications integration with this extension you may use it's factories.
122
+ Simply add this require statement to your spec_helper:
123
+
124
+ ```ruby
125
+ require 'solidus_subscriptions/testing_support/factories'
126
+ ```
127
+
128
+ Copyright (c) 2016 Stembolt, released under the New BSD License
@@ -0,0 +1,28 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ begin
6
+ require 'spree/testing_support/extension_rake'
7
+ require 'rubocop/rake_task'
8
+ require 'rspec/core/rake_task'
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task default: %i(first_run spec)
13
+ rescue LoadError
14
+ # no rspec available
15
+ end
16
+
17
+ task :first_run do
18
+ if Dir['spec/dummy'].empty?
19
+ Rake::Task[:test_app].invoke
20
+ Dir.chdir('../../')
21
+ end
22
+ end
23
+
24
+ desc 'Generates a dummy app for testing'
25
+ task :test_app do
26
+ ENV['LIB_NAME'] = 'solidus_subscriptions'
27
+ Rake::Task['extension:test_app'].invoke
28
+ end
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js'
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
4
+ */
@@ -0,0 +1,35 @@
1
+ class SolidusSubscriptions::Api::V1::LineItemsController < Spree::Api::BaseController
2
+ before_action :load_line_item, only: [:update, :destroy]
3
+ wrap_parameters :subscription_line_item
4
+
5
+ def update
6
+ authorize! :crud, @line_item, @order
7
+ if @line_item.update(line_item_params)
8
+ render json: @line_item.to_json
9
+ else
10
+ render json: @line_item.errors.to_json, status: 422
11
+ end
12
+ end
13
+
14
+ def destroy
15
+ authorize! :crud, @line_item, @order
16
+ return render json: {}, status: 400 if @line_item.order.complete?
17
+
18
+ @line_item.destroy!
19
+ @line_item.order.update!
20
+
21
+ render json: @line_item.to_json
22
+ end
23
+
24
+ private
25
+
26
+ def line_item_params
27
+ params.require(:subscription_line_item).permit(
28
+ SolidusSubscriptions::PermittedAttributes.subscription_line_item_attributes - [:subscribable_id]
29
+ )
30
+ end
31
+
32
+ def load_line_item
33
+ @line_item = SolidusSubscriptions::LineItem.find(params[:id])
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ class SolidusSubscriptions::Api::V1::SubscriptionsController < Spree::Api::BaseController
2
+ before_action :load_subscription, only: [:cancel, :update, :skip]
3
+
4
+ def update
5
+ if @subscription.update(subscription_params)
6
+ render json: @subscription.to_json(include: [:line_items, :shipping_address])
7
+ else
8
+ render json: @subscription.errors.to_json, status: 422
9
+ end
10
+ end
11
+
12
+ def skip
13
+ if @subscription.skip
14
+ render json: @subscription.to_json
15
+ else
16
+ render json: @subscription.errors.to_json, status: 422
17
+ end
18
+ end
19
+
20
+ def cancel
21
+ if @subscription.cancel
22
+ render json: @subscription.to_json
23
+ else
24
+ render json: @subscription.errors.to_json, status: 422
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def load_subscription
31
+ @subscription = current_api_user.subscriptions.find(params[:id])
32
+ end
33
+
34
+ def subscription_params
35
+ params.require(:subscription).permit(
36
+ line_items_attributes: line_item_attributes,
37
+ shipping_address_attributes: Spree::PermittedAttributes.address_attributes
38
+ )
39
+ end
40
+
41
+ def line_item_attributes
42
+ SolidusSubscriptions::Config.subscription_line_item_attributes - [:subscribable_id] + [:id]
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ module Spree
2
+ module Admin
3
+ class SubscriptionsController < ResourceController
4
+ skip_before_action :load_resource, only: :index
5
+
6
+ def index
7
+ @search = SolidusSubscriptions::Subscription.
8
+ accessible_by(current_ability, :index).ransack(params[:q])
9
+
10
+ @subscriptions = @search.result(distinct: true).
11
+ includes(:line_items, :user).
12
+ joins(:line_items, :user).
13
+ page(params[:page]).
14
+ per(params[:per_page] || Spree::Config[:orders_per_page])
15
+ end
16
+
17
+ def new
18
+ @subscription.line_items.new
19
+ end
20
+
21
+ def cancel
22
+ @subscription.transaction do
23
+ @subscription.actionable_date = nil
24
+ @subscription.cancel
25
+ end
26
+
27
+ if @subscription.errors.none?
28
+ notice = I18n.t('spree.admin.subscriptions.successfully_canceled')
29
+ else
30
+ notice = @subscription.errors.full_messages.to_sentence
31
+ end
32
+
33
+ redirect_to spree.admin_subscriptions_path, notice: notice
34
+ end
35
+
36
+ def activate
37
+ @subscription.activate
38
+
39
+ if @subscription.errors.none?
40
+ notice = I18n.t('spree.admin.subscriptions.successfully_activated')
41
+ else
42
+ notice = @subscription.errors.full_messages.to_sentence
43
+ end
44
+
45
+ redirect_to spree.admin_subscriptions_path, notice: notice
46
+ end
47
+
48
+ def skip
49
+ @subscription.advance_actionable_date
50
+
51
+ notice = I18n.t(
52
+ 'spree.admin.subscriptions.successfully_skipped',
53
+ date: @subscription.actionable_date
54
+ )
55
+
56
+ redirect_to spree.admin_subscriptions_path, notice: notice
57
+ end
58
+
59
+ private
60
+
61
+ def model_class
62
+ ::SolidusSubscriptions::Subscription
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ # Create new subscription line items associated to the current order, when
2
+ # a line item is added to the cart which includes subscription_line_item
3
+ # params.
4
+ #
5
+ # The Subscriptions::LineItem acts as a line item place holder for a
6
+ # Subscription, indicating that it has been added to the order, but not
7
+ # yet purchased
8
+ module Spree
9
+ module Controllers::Api::LineItems::CreateSubscriptionLineItems
10
+ include SolidusSubscriptions::SubscriptionLineItemBuilder
11
+
12
+ def self.prepended(base)
13
+ base.after_action(
14
+ :handle_subscription_line_items,
15
+ only: [:create, :update],
16
+ if: ->{ params[:subscription_line_item] }
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ def handle_subscription_line_items
23
+ create_subscription_line_item(@line_item)
24
+ end
25
+ end
26
+ end
27
+
28
+ Spree::Api::LineItemsController.prepend(Spree::Controllers::Api::LineItems::CreateSubscriptionLineItems)
@@ -0,0 +1,33 @@
1
+ # Create new subscription line items associated to the current order, when
2
+ # a line item is added to the cart which includes subscription_line_item
3
+ # params.
4
+ #
5
+ # The Subscriptions::LineItem acts as a line item place holder for a
6
+ # Subscription, indicating that it has been added to the order, but not
7
+ # yet purchased
8
+ module Spree
9
+ module Controllers
10
+ module Orders
11
+ module CreateSubscriptionLineItems
12
+ include SolidusSubscriptions::SubscriptionLineItemBuilder
13
+
14
+ def self.prepended(base)
15
+ base.after_action(
16
+ :handle_subscription_line_items,
17
+ only: :populate,
18
+ if: ->{ params[:subscription_line_item] }
19
+ )
20
+ end
21
+
22
+ private
23
+
24
+ def handle_subscription_line_items
25
+ line_item = @current_order.line_items.find_by(variant_id: params[:variant_id])
26
+ create_subscription_line_item(line_item)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Spree::OrdersController.prepend(Spree::Controllers::Orders::CreateSubscriptionLineItems)
@@ -0,0 +1,22 @@
1
+ # Each Spree::LineItem can have multiple subscription_line_items. This
2
+ # allows a cart to represent multiple subscriptions to the same item in
3
+ # the same order.
4
+ module Spree
5
+ module LineItems
6
+ module SubscriptionLineItemsAssociation
7
+ def self.prepended(base)
8
+ base.has_many(
9
+ :subscription_line_items,
10
+ class_name: 'SolidusSubscriptions::LineItem',
11
+ foreign_key: :spree_line_item_id,
12
+ inverse_of: :spree_line_item,
13
+ dependent: :destroy
14
+ )
15
+
16
+ base.accepts_nested_attributes_for :subscription_line_items
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Spree::LineItem.prepend Spree::LineItems::SubscriptionLineItemsAssociation