solidus_subscriptions-alpha 0.0.3 → 0.0.4

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +26 -26
  3. data/README.md +130 -130
  4. data/Rakefile +28 -28
  5. data/app/assets/javascripts/spree/backend/solidus_subscriptions.js +1 -1
  6. data/app/assets/javascripts/spree/frontend/solidus_subscriptions.js +1 -1
  7. data/app/assets/stylesheets/spree/backend/solidus_subscriptions.css +4 -4
  8. data/app/assets/stylesheets/spree/frontend/solidus_subscriptions.css +4 -4
  9. data/app/controllers/solidus_subscriptions/api/v1/line_items_controller.rb +35 -35
  10. data/app/controllers/solidus_subscriptions/api/v1/subscriptions_controller.rb +44 -44
  11. data/app/controllers/spree/admin/subscriptions_controller.rb +66 -66
  12. data/app/decorators/spree/controllers/api/line_items/create_subscription_line_items.rb +28 -28
  13. data/app/decorators/spree/controllers/orders/create_subscription_line_items.rb +33 -33
  14. data/app/decorators/spree/line_items/subscription_line_items_association.rb +22 -22
  15. data/app/decorators/spree/orders/after_create.rb +15 -15
  16. data/app/decorators/spree/orders/finalize_creates_subscriptions.rb +19 -19
  17. data/app/decorators/spree/orders/subscription_line_items_association.rb +15 -15
  18. data/app/decorators/spree/products/subscribable_decorator.rb +11 -11
  19. data/app/decorators/spree/users/have_many_subscriptions.rb +18 -18
  20. data/app/decorators/spree/variant_pretty_name.rb +13 -13
  21. data/app/jobs/solidus_subscriptions/process_installments_job.rb +22 -22
  22. data/app/models/solidus_subscriptions/checkout.rb +141 -141
  23. data/app/models/solidus_subscriptions/dispatcher.rb +32 -32
  24. data/app/models/solidus_subscriptions/failure_dispatcher.rb +19 -19
  25. data/app/models/solidus_subscriptions/installment.rb +126 -126
  26. data/app/models/solidus_subscriptions/installment_detail.rb +23 -23
  27. data/app/models/solidus_subscriptions/interval.rb +24 -24
  28. data/app/models/solidus_subscriptions/line_item.rb +98 -98
  29. data/app/models/solidus_subscriptions/line_item_builder.rb +44 -44
  30. data/app/models/solidus_subscriptions/order_builder.rb +40 -40
  31. data/app/models/solidus_subscriptions/out_of_stock_dispatcher.rb +19 -19
  32. data/app/models/solidus_subscriptions/payment_failed_dispatcher.rb +23 -23
  33. data/app/models/solidus_subscriptions/subscription.rb +217 -217
  34. data/app/models/solidus_subscriptions/subscription_generator.rb +60 -60
  35. data/app/models/solidus_subscriptions/subscription_line_item_builder.rb +21 -21
  36. data/app/models/solidus_subscriptions/subscription_order_promotion_rule.rb +25 -25
  37. data/app/models/solidus_subscriptions/subscription_promotion_rule.rb +38 -38
  38. data/app/models/solidus_subscriptions/success_dispatcher.rb +16 -16
  39. data/app/models/solidus_subscriptions/unsubscribable_error.rb +17 -17
  40. data/app/models/solidus_subscriptions/user_mismatch_error.rb +15 -15
  41. data/app/overrides/views/admin_subscribable_checkbox.rb +13 -13
  42. data/app/overrides/views/admin_subscriptions_menu_link.rb +8 -8
  43. data/app/overrides/views/subscription_line_item_fields.rb +6 -6
  44. data/app/views/spree/admin/products/_subscribable_checkbox.html.erb +8 -8
  45. data/app/views/spree/admin/promotions/rules/_subscription_order_promotion_rule.html.erb +0 -0
  46. data/app/views/spree/admin/promotions/rules/_subscription_promotion_rule.html.erb +0 -0
  47. data/app/views/spree/admin/shared/_no_objects_found.html.erb +4 -4
  48. data/app/views/spree/admin/shared/_subscription_tab.html.erb +3 -3
  49. data/app/views/spree/admin/solidus_subscriptions/subscriptions/_subscription.html.erb +66 -66
  50. data/app/views/spree/admin/subscriptions/_form.html.erb +81 -81
  51. data/app/views/spree/admin/subscriptions/_legacy_form.html.erb +81 -81
  52. data/app/views/spree/admin/subscriptions/_legacy_sidebar.html.erb +28 -28
  53. data/app/views/spree/admin/subscriptions/edit.html.erb +21 -21
  54. data/app/views/spree/admin/subscriptions/index.html.erb +119 -119
  55. data/app/views/spree/admin/subscriptions/new.html.erb +9 -9
  56. data/app/views/spree/admin/variants/_subscribable_checkbox.html.erb +6 -6
  57. data/app/views/spree/frontend/products/_subscription_line_item_fields.html.erb +30 -30
  58. data/config/locales/en.yml +91 -91
  59. data/config/routes.rb +25 -25
  60. data/db/migrate/20160825164850_create_solidus_subscriptions_subscriptions.rb +11 -11
  61. data/db/migrate/20160825173548_create_solidus_subscriptions_line_items.rb +17 -17
  62. data/db/migrate/20160825202248_create_solidus_subscriptions_installments.rb +23 -23
  63. data/db/migrate/20160825211202_create_solidus_subscriptions_installment_details.rb +22 -22
  64. data/db/migrate/20160825214240_add_subscribable_to_spree_variants.rb +5 -5
  65. data/db/migrate/20160829201653_change_subscription_line_items_installments_to_max_installments.rb +5 -5
  66. data/db/migrate/20160902220242_remove_state_from_solidus_susbscriptions_installment_details.rb +5 -5
  67. data/db/migrate/20160902220604_add_successful_to_solidus_subscriptions_installment_details.rb +5 -5
  68. data/db/migrate/20160902221218_add_message_to_solidus_subscriptions_installment_details.rb +5 -5
  69. data/db/migrate/20160922164101_add_interval_length_and_units_to_subscription_line_items.rb +8 -8
  70. data/db/migrate/20161006191003_add_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -5
  71. data/db/migrate/20161006191127_add_successive_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -5
  72. data/db/migrate/20161014212649_allow_spree_line_item_id_to_be_null.rb +5 -5
  73. data/db/migrate/20161017155749_add_order_id_to_solidus_subscriptions_installment_details.rb +6 -6
  74. data/db/migrate/20161017175509_remove_order_id_from_solidus_subscriptions_installments.rb +6 -6
  75. data/db/migrate/20161017201944_add_subscription_order_to_spree_orders.rb +5 -5
  76. data/db/migrate/20161221155142_add_store_to_solidus_subscriptions_subscriptions.rb +6 -6
  77. data/db/migrate/20161223152905_add_address_id_to_solidus_subscriptions_subscriptions.rb +7 -7
  78. data/db/migrate/20170106224713_change_line_item_max_installments_to_end_date.rb +6 -6
  79. data/db/migrate/20170111224458_change_subscription_actionable_date_to_datetime.rb +5 -5
  80. data/db/migrate/20170111232801_change_inteval_actionable_date_to_datetime.rb +5 -5
  81. data/db/migrate/20170112012407_add_config_options_to_subscriptions.rb +7 -7
  82. data/lib/generators/solidus_subscriptions/install/install_generator.rb +30 -30
  83. data/lib/solidus_subscriptions.rb +6 -6
  84. data/lib/solidus_subscriptions/ability.rb +19 -19
  85. data/lib/solidus_subscriptions/config.rb +97 -97
  86. data/lib/solidus_subscriptions/engine.rb +56 -56
  87. data/lib/solidus_subscriptions/permitted_attributes.rb +36 -36
  88. data/lib/solidus_subscriptions/processor.rb +108 -108
  89. data/lib/solidus_subscriptions/testing_support/factories.rb +5 -5
  90. data/lib/solidus_subscriptions/testing_support/factories/installment_detail_factory.rb +7 -7
  91. data/lib/solidus_subscriptions/testing_support/factories/installment_factory.rb +21 -21
  92. data/lib/solidus_subscriptions/testing_support/factories/line_item_factory.rb +18 -18
  93. data/lib/solidus_subscriptions/testing_support/factories/spree/line_item_factory.rb +17 -17
  94. data/lib/solidus_subscriptions/testing_support/factories/spree/order_factory.rb +18 -18
  95. data/lib/solidus_subscriptions/testing_support/factories/spree_modification_factory.rb +8 -8
  96. data/lib/solidus_subscriptions/testing_support/factories/subscription_factory.rb +43 -43
  97. data/lib/solidus_subscriptions/version.rb +3 -3
  98. data/lib/tasks/process_subscriptions.rake +6 -6
  99. metadata +3 -3
@@ -1,15 +1,15 @@
1
- # Spree::Orders may contain many subscription_line_items. When the order is
2
- # finalized these subscription_line_items are converted into subscritpions.
3
- # The order needs to be able to get a list of associated subscription_line_items
4
- # to be able to populate the full subscriptions.
5
- module Spree
6
- module Orders
7
- module SubscriptionLineItemsAssociation
8
- def self.prepended(base)
9
- base.has_many :subscription_line_items, through: :line_items
10
- end
11
- end
12
- end
13
- end
14
-
15
- Spree::Order.prepend Spree::Orders::SubscriptionLineItemsAssociation
1
+ # Spree::Orders may contain many subscription_line_items. When the order is
2
+ # finalized these subscription_line_items are converted into subscritpions.
3
+ # The order needs to be able to get a list of associated subscription_line_items
4
+ # to be able to populate the full subscriptions.
5
+ module Spree
6
+ module Orders
7
+ module SubscriptionLineItemsAssociation
8
+ def self.prepended(base)
9
+ base.has_many :subscription_line_items, through: :line_items
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ Spree::Order.prepend Spree::Orders::SubscriptionLineItemsAssociation
@@ -1,11 +1,11 @@
1
- module Spree
2
- module Products
3
- module Subscribable
4
- def self.prepended(klass)
5
- klass.delegate :"subscribable", :"subscribable=", to: :find_or_build_master
6
- end
7
- end
8
- end
9
- end
10
-
11
- Spree::Product.prepend Spree::Products::Subscribable
1
+ module Spree
2
+ module Products
3
+ module Subscribable
4
+ def self.prepended(klass)
5
+ klass.delegate :"subscribable", :"subscribable=", to: :find_or_build_master
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ Spree::Product.prepend Spree::Products::Subscribable
@@ -1,18 +1,18 @@
1
- # Spree::Users maintain a list of the subscriptions associated with them
2
- module Spree
3
- module Users
4
- module HaveManySubscritptions
5
- def self.prepended(base)
6
- base.has_many(
7
- :subscriptions,
8
- class_name: 'SolidusSubscriptions::Subscription',
9
- foreign_key: 'user_id'
10
- )
11
-
12
- base.accepts_nested_attributes_for :subscriptions
13
- end
14
- end
15
- end
16
- end
17
-
18
- Spree.user_class.prepend(Spree::Users::HaveManySubscritptions)
1
+ # Spree::Users maintain a list of the subscriptions associated with them
2
+ module Spree
3
+ module Users
4
+ module HaveManySubscritptions
5
+ def self.prepended(base)
6
+ base.has_many(
7
+ :subscriptions,
8
+ class_name: 'SolidusSubscriptions::Subscription',
9
+ foreign_key: 'user_id'
10
+ )
11
+
12
+ base.accepts_nested_attributes_for :subscriptions
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ Spree.user_class.prepend(Spree::Users::HaveManySubscritptions)
@@ -1,13 +1,13 @@
1
- module Spree
2
- module Variants
3
- module VariantPrettyName
4
- def pretty_name
5
- name = product.name
6
- name += " - #{options_text}" if options_text.present?
7
- name
8
- end
9
- end
10
- end
11
- end
12
-
13
- Spree::Variant.prepend Spree::Variants::VariantPrettyName
1
+ module Spree
2
+ module Variants
3
+ module VariantPrettyName
4
+ def pretty_name
5
+ name = product.name
6
+ name += " - #{options_text}" if options_text.present?
7
+ name
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ Spree::Variant.prepend Spree::Variants::VariantPrettyName
@@ -1,22 +1,22 @@
1
- # This job is responsible for creating a consolidated installment from a
2
- # list of installments and processing it.
3
-
4
- module SolidusSubscriptions
5
- class ProcessInstallmentsJob < ActiveJob::Base
6
- queue_as Config.processing_queue
7
-
8
- # Process a collection of installments
9
- #
10
- # @param installment_ids [Array<Integer>] The ids of the
11
- # installments to be processed together and fulfilled by the same order
12
- #
13
- # @return [Spree::Order] The order which fulfills the list of installments
14
- def perform(installment_ids)
15
- return if installment_ids.empty?
16
-
17
- installments = SolidusSubscriptions::Installment.where(id: installment_ids).
18
- includes(subscription: [:line_items, :user])
19
- Checkout.new(installments).process
20
- end
21
- end
22
- end
1
+ # This job is responsible for creating a consolidated installment from a
2
+ # list of installments and processing it.
3
+
4
+ module SolidusSubscriptions
5
+ class ProcessInstallmentsJob < ActiveJob::Base
6
+ queue_as Config.processing_queue
7
+
8
+ # Process a collection of installments
9
+ #
10
+ # @param installment_ids [Array<Integer>] The ids of the
11
+ # installments to be processed together and fulfilled by the same order
12
+ #
13
+ # @return [Spree::Order] The order which fulfills the list of installments
14
+ def perform(installment_ids)
15
+ return if installment_ids.empty?
16
+
17
+ installments = SolidusSubscriptions::Installment.where(id: installment_ids).
18
+ includes(subscription: [:line_items, :user])
19
+ Checkout.new(installments).process
20
+ end
21
+ end
22
+ end
@@ -1,141 +1,141 @@
1
- # This class takes a collection of installments and populates a new spree
2
- # order with the correct contents based on the subscriptions associated to the
3
- # intallments. This is to group together subscriptions being
4
- # processed on the same day for a specific user
5
- module SolidusSubscriptions
6
- class Checkout
7
- # @return [Array<Installment>] The collection of installments to be used
8
- # when generating a new order
9
- attr_reader :installments
10
-
11
- delegate :user, to: :subscription
12
-
13
- # Get a new instance of a Checkout
14
- #
15
- # @param installments [Array<Installment>] The collection of installments
16
- # to be used when generating a new order
17
- def initialize(installments)
18
- @installments = installments
19
- raise UserMismatchError.new(installments) if different_owners?
20
- end
21
-
22
- # Generate a new Spree::Order based on the information associated to the
23
- # installments
24
- #
25
- # @return [Spree::Order]
26
- def process
27
- populate
28
-
29
- # Installments are removed and set for future processing if they are
30
- # out of stock. If there are no line items left there is nothing to do
31
- return if installments.empty?
32
-
33
- if checkout
34
- Config.success_dispatcher_class.new(installments, order).dispatch
35
- return order
36
- end
37
-
38
- # A new order will only have 1 payment that we created
39
- if order.payments.any?(&:failed?)
40
- Config.payment_failed_dispatcher_class.new(installments, order).dispatch
41
- installments.clear
42
- nil
43
- end
44
- ensure
45
- # Any installments that failed to be processed will be reprocessed
46
- unfulfilled_installments = installments.select(&:unfulfilled?)
47
- if unfulfilled_installments.any?
48
- Config.failure_dispatcher_class.
49
- new(unfulfilled_installments, order).dispatch
50
- end
51
- end
52
-
53
- # The order fulfilling the consolidated installment
54
- #
55
- # @return [Spree::Order]
56
- def order
57
- @order ||= Spree::Order.create(
58
- user: user,
59
- email: user.email,
60
- store: subscription.store || Spree::Store.default,
61
- subscription_order: true
62
- )
63
- end
64
-
65
- private
66
-
67
- def checkout
68
- order.update!
69
- apply_promotions
70
-
71
- order.checkout_steps.count.times do
72
- order.ship_address = ship_address if order.state == "address"
73
- create_payment if order.state == "payment"
74
- order.next! if order.next_transition.present?
75
- end
76
-
77
- # Do this as a separate "quiet" transition so that it returns true or
78
- # false rather than raising a failed transition error
79
- order.complete
80
- end
81
-
82
- def populate
83
- unfulfilled_installments = []
84
-
85
- order_line_items = installments.flat_map do |installment|
86
- line_items = installment.line_item_builder.spree_line_items
87
-
88
- unfulfilled_installments.push(installment) if line_items.empty?
89
-
90
- line_items
91
- end
92
-
93
- # Remove installments which had no stock from the active list
94
- # They will be reprocessed later
95
- @installments -= unfulfilled_installments
96
- if unfulfilled_installments.any?
97
- Config.out_of_stock_dispatcher_class.new(unfulfilled_installments).dispatch
98
- end
99
-
100
- return if installments.empty?
101
- order_builder.add_line_items(order_line_items)
102
- end
103
-
104
- def order_builder
105
- @order_builder ||= OrderBuilder.new(order)
106
- end
107
-
108
- def subscription
109
- installments.first.subscription
110
- end
111
-
112
- def ship_address
113
- subscription.shipping_address || user.ship_address
114
- end
115
-
116
- def active_card
117
- if SolidusSupport.solidus_gem_version < Gem::Version.new("2.2.0")
118
- user.credit_cards.default.last
119
- else
120
- user.wallet.default_wallet_payment_source.payment_source
121
- end
122
- end
123
-
124
- def create_payment
125
- order.payments.create(
126
- source: active_card,
127
- amount: order.total,
128
- payment_method: Config.default_gateway
129
- )
130
- end
131
-
132
- def apply_promotions
133
- Spree::PromotionHandler::Cart.new(order).activate
134
- order.updater.update # reload totals
135
- end
136
-
137
- def different_owners?
138
- installments.map { |i| i.subscription.user }.uniq.length > 1
139
- end
140
- end
141
- end
1
+ # This class takes a collection of installments and populates a new spree
2
+ # order with the correct contents based on the subscriptions associated to the
3
+ # intallments. This is to group together subscriptions being
4
+ # processed on the same day for a specific user
5
+ module SolidusSubscriptions
6
+ class Checkout
7
+ # @return [Array<Installment>] The collection of installments to be used
8
+ # when generating a new order
9
+ attr_reader :installments
10
+
11
+ delegate :user, to: :subscription
12
+
13
+ # Get a new instance of a Checkout
14
+ #
15
+ # @param installments [Array<Installment>] The collection of installments
16
+ # to be used when generating a new order
17
+ def initialize(installments)
18
+ @installments = installments
19
+ raise UserMismatchError.new(installments) if different_owners?
20
+ end
21
+
22
+ # Generate a new Spree::Order based on the information associated to the
23
+ # installments
24
+ #
25
+ # @return [Spree::Order]
26
+ def process
27
+ populate
28
+
29
+ # Installments are removed and set for future processing if they are
30
+ # out of stock. If there are no line items left there is nothing to do
31
+ return if installments.empty?
32
+
33
+ if checkout
34
+ Config.success_dispatcher_class.new(installments, order).dispatch
35
+ return order
36
+ end
37
+
38
+ # A new order will only have 1 payment that we created
39
+ if order.payments.any?(&:failed?)
40
+ Config.payment_failed_dispatcher_class.new(installments, order).dispatch
41
+ installments.clear
42
+ nil
43
+ end
44
+ ensure
45
+ # Any installments that failed to be processed will be reprocessed
46
+ unfulfilled_installments = installments.select(&:unfulfilled?)
47
+ if unfulfilled_installments.any?
48
+ Config.failure_dispatcher_class.
49
+ new(unfulfilled_installments, order).dispatch
50
+ end
51
+ end
52
+
53
+ # The order fulfilling the consolidated installment
54
+ #
55
+ # @return [Spree::Order]
56
+ def order
57
+ @order ||= Spree::Order.create(
58
+ user: user,
59
+ email: user.email,
60
+ store: subscription.store || Spree::Store.default,
61
+ subscription_order: true
62
+ )
63
+ end
64
+
65
+ private
66
+
67
+ def checkout
68
+ order.update!
69
+ apply_promotions
70
+
71
+ order.checkout_steps.count.times do
72
+ order.ship_address = ship_address if order.state == "address"
73
+ create_payment if order.state == "payment"
74
+ order.next! if order.next_transition.present?
75
+ end
76
+
77
+ # Do this as a separate "quiet" transition so that it returns true or
78
+ # false rather than raising a failed transition error
79
+ order.complete
80
+ end
81
+
82
+ def populate
83
+ unfulfilled_installments = []
84
+
85
+ order_line_items = installments.flat_map do |installment|
86
+ line_items = installment.line_item_builder.spree_line_items
87
+
88
+ unfulfilled_installments.push(installment) if line_items.empty?
89
+
90
+ line_items
91
+ end
92
+
93
+ # Remove installments which had no stock from the active list
94
+ # They will be reprocessed later
95
+ @installments -= unfulfilled_installments
96
+ if unfulfilled_installments.any?
97
+ Config.out_of_stock_dispatcher_class.new(unfulfilled_installments).dispatch
98
+ end
99
+
100
+ return if installments.empty?
101
+ order_builder.add_line_items(order_line_items)
102
+ end
103
+
104
+ def order_builder
105
+ @order_builder ||= OrderBuilder.new(order)
106
+ end
107
+
108
+ def subscription
109
+ installments.first.subscription
110
+ end
111
+
112
+ def ship_address
113
+ subscription.shipping_address || user.ship_address
114
+ end
115
+
116
+ def active_card
117
+ if SolidusSupport.solidus_gem_version < Gem::Version.new("2.2.0")
118
+ user.credit_cards.default.last
119
+ else
120
+ user.wallet.default_wallet_payment_source.payment_source
121
+ end
122
+ end
123
+
124
+ def create_payment
125
+ order.payments.create(
126
+ source: active_card,
127
+ amount: order.total,
128
+ payment_method: Config.default_gateway
129
+ )
130
+ end
131
+
132
+ def apply_promotions
133
+ Spree::PromotionHandler::Cart.new(order).activate
134
+ order.updater.update # reload totals
135
+ end
136
+
137
+ def different_owners?
138
+ installments.map { |i| i.subscription.user }.uniq.length > 1
139
+ end
140
+ end
141
+ end