solidus_subscriptions 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.github_changelog_generator +2 -0
  6. data/.gitignore +20 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +12 -0
  9. data/.rubocop_todo.yml +86 -0
  10. data/CHANGELOG.md +191 -0
  11. data/Gemfile +33 -0
  12. data/LICENSE +26 -0
  13. data/README.md +221 -0
  14. data/Rakefile +6 -0
  15. data/app/assets/javascripts/spree/backend/solidus_subscriptions.js +1 -0
  16. data/app/assets/javascripts/spree/backend/solidus_subscriptions/edit_subscription_payment.js +32 -0
  17. data/app/controllers/solidus_subscriptions/api/v1/base_controller.rb +13 -0
  18. data/app/controllers/solidus_subscriptions/api/v1/line_items_controller.rb +48 -0
  19. data/app/controllers/solidus_subscriptions/api/v1/subscriptions_controller.rb +100 -0
  20. data/app/controllers/spree/admin/installments_controller.rb +25 -0
  21. data/app/controllers/spree/admin/subscription_events_controller.rb +37 -0
  22. data/app/controllers/spree/admin/subscription_orders_controller.rb +35 -0
  23. data/app/controllers/spree/admin/subscriptions_controller.rb +100 -0
  24. data/app/controllers/spree/admin/users/subscriptions_controller.rb +17 -0
  25. data/app/decorators/controllers/solidus_subscriptions/spree/api/line_items_controller/create_subscription_line_items.rb +36 -0
  26. data/app/decorators/controllers/solidus_subscriptions/spree/orders_controller/create_subscription_line_items.rb +35 -0
  27. data/app/decorators/models/solidus_subscriptions/spree/line_item/subscription_line_items_association.rb +26 -0
  28. data/app/decorators/models/solidus_subscriptions/spree/order/after_create.rb +19 -0
  29. data/app/decorators/models/solidus_subscriptions/spree/order/finalize_creates_subscriptions.rb +23 -0
  30. data/app/decorators/models/solidus_subscriptions/spree/order/installment_details_association.rb +15 -0
  31. data/app/decorators/models/solidus_subscriptions/spree/order/subscription_association.rb +15 -0
  32. data/app/decorators/models/solidus_subscriptions/spree/order/subscription_line_items_association.rb +19 -0
  33. data/app/decorators/models/solidus_subscriptions/spree/product/delegate_subscribable.rb +17 -0
  34. data/app/decorators/models/solidus_subscriptions/spree/user/have_many_subscriptions.rb +30 -0
  35. data/app/decorators/models/solidus_subscriptions/spree/variant/auto_delete_from_subscriptions.rb +20 -0
  36. data/app/decorators/models/solidus_subscriptions/spree/variant/variant_pretty_name.rb +17 -0
  37. data/app/decorators/models/solidus_subscriptions/spree/wallet_payment_source/report_default_change_to_subscriptions.rb +28 -0
  38. data/app/jobs/solidus_subscriptions/process_installment_job.rb +13 -0
  39. data/app/jobs/solidus_subscriptions/process_subscription_job.rb +31 -0
  40. data/app/models/solidus_subscriptions/installment.rb +135 -0
  41. data/app/models/solidus_subscriptions/installment_detail.rb +28 -0
  42. data/app/models/solidus_subscriptions/interval.rb +26 -0
  43. data/app/models/solidus_subscriptions/line_item.rb +42 -0
  44. data/app/models/solidus_subscriptions/promotion/rules/subscription_creation_order.rb +44 -0
  45. data/app/models/solidus_subscriptions/promotion/rules/subscription_installment_order.rb +31 -0
  46. data/app/models/solidus_subscriptions/subscription.rb +392 -0
  47. data/app/models/solidus_subscriptions/subscription_event.rb +11 -0
  48. data/app/overrides/views/admin_subscribable_product_checkbox.rb +8 -0
  49. data/app/overrides/views/admin_subscribable_variant_checkbox.rb +8 -0
  50. data/app/overrides/views/admin_subscriptions_menu_link.rb +10 -0
  51. data/app/overrides/views/admin_users_subscriptions_tab.rb +8 -0
  52. data/app/overrides/views/subscription_line_item_fields.rb +8 -0
  53. data/app/subscribers/solidus_subscriptions/churn_buster_subscriber.rb +39 -0
  54. data/app/subscribers/solidus_subscriptions/event_storage_subscriber.rb +64 -0
  55. data/app/views/spree/admin/installments/_state_pill.html.erb +8 -0
  56. data/app/views/spree/admin/installments/index.html.erb +42 -0
  57. data/app/views/spree/admin/products/_subscribable_checkbox.html.erb +8 -0
  58. data/app/views/spree/admin/promotions/rules/_subscription_creation_order.html.erb +0 -0
  59. data/app/views/spree/admin/promotions/rules/_subscription_installment_order.html.erb +0 -0
  60. data/app/views/spree/admin/shared/_subscription_actions.html.erb +35 -0
  61. data/app/views/spree/admin/shared/_subscription_breadcrumbs.html.erb +4 -0
  62. data/app/views/spree/admin/shared/_subscription_sidebar.html.erb +18 -0
  63. data/app/views/spree/admin/shared/_subscription_tab.html.erb +3 -0
  64. data/app/views/spree/admin/shared/_subscription_tabs.html.erb +18 -0
  65. data/app/views/spree/admin/subscription_events/_state_pill.html.erb +8 -0
  66. data/app/views/spree/admin/subscription_events/index.html.erb +42 -0
  67. data/app/views/spree/admin/subscription_orders/index.html.erb +93 -0
  68. data/app/views/spree/admin/subscriptions/_form.html.erb +150 -0
  69. data/app/views/spree/admin/subscriptions/_processing_state_pill.html.erb +9 -0
  70. data/app/views/spree/admin/subscriptions/_state_pill.html.erb +10 -0
  71. data/app/views/spree/admin/subscriptions/edit.html.erb +10 -0
  72. data/app/views/spree/admin/subscriptions/index.html.erb +176 -0
  73. data/app/views/spree/admin/subscriptions/new.html.erb +5 -0
  74. data/app/views/spree/admin/users/_subscription_tab.html.erb +5 -0
  75. data/app/views/spree/admin/users/subscriptions/index.html.erb +44 -0
  76. data/app/views/spree/admin/variants/_subscribable_checkbox.html.erb +6 -0
  77. data/app/views/spree/frontend/products/_subscription_line_item_fields.html.erb +30 -0
  78. data/bin/console +17 -0
  79. data/bin/rails +7 -0
  80. data/bin/rails-engine +13 -0
  81. data/bin/rails-sandbox +16 -0
  82. data/bin/rake +7 -0
  83. data/bin/sandbox +86 -0
  84. data/bin/setup +8 -0
  85. data/config/initializers/permission_sets.rb +11 -0
  86. data/config/initializers/subscribers.rb +9 -0
  87. data/config/locales/en.yml +129 -0
  88. data/config/routes.rb +34 -0
  89. data/db/migrate/20160825164850_create_solidus_subscriptions_subscriptions.rb +11 -0
  90. data/db/migrate/20160825173548_create_solidus_subscriptions_line_items.rb +17 -0
  91. data/db/migrate/20160825202248_create_solidus_subscriptions_installments.rb +23 -0
  92. data/db/migrate/20160825211202_create_solidus_subscriptions_installment_details.rb +22 -0
  93. data/db/migrate/20160825214240_add_subscribable_to_spree_variants.rb +5 -0
  94. data/db/migrate/20160829201653_change_subscription_line_items_installments_to_max_installments.rb +5 -0
  95. data/db/migrate/20160902220242_remove_state_from_solidus_susbscriptions_installment_details.rb +5 -0
  96. data/db/migrate/20160902220604_add_successful_to_solidus_subscriptions_installment_details.rb +5 -0
  97. data/db/migrate/20160902221218_add_message_to_solidus_subscriptions_installment_details.rb +5 -0
  98. data/db/migrate/20160922164101_add_interval_length_and_units_to_subscription_line_items.rb +8 -0
  99. data/db/migrate/20161006191003_add_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
  100. data/db/migrate/20161006191127_add_successive_skip_count_to_solidus_subscriptions_subscriptions.rb +5 -0
  101. data/db/migrate/20161014212649_allow_spree_line_item_id_to_be_null.rb +5 -0
  102. data/db/migrate/20161017155749_add_order_id_to_solidus_subscriptions_installment_details.rb +6 -0
  103. data/db/migrate/20161017175509_remove_order_id_from_solidus_subscriptions_installments.rb +5 -0
  104. data/db/migrate/20161017201944_add_subscription_order_to_spree_orders.rb +5 -0
  105. data/db/migrate/20161221155142_add_store_to_solidus_subscriptions_subscriptions.rb +6 -0
  106. data/db/migrate/20161223152905_add_address_id_to_solidus_subscriptions_subscriptions.rb +7 -0
  107. data/db/migrate/20170106224713_change_line_item_max_installments_to_end_date.rb +6 -0
  108. data/db/migrate/20170111224458_change_subscription_actionable_date_to_datetime.rb +5 -0
  109. data/db/migrate/20170111232801_change_inteval_actionable_date_to_datetime.rb +5 -0
  110. data/db/migrate/20170112012407_add_config_options_to_subscriptions.rb +7 -0
  111. data/db/migrate/20200617102749_add_billing_address_to_subscriptions.rb +11 -0
  112. data/db/migrate/20200617155042_add_payment_source_to_subscriptions.rb +6 -0
  113. data/db/migrate/20200618092951_add_payment_method_to_subscriptions.rb +11 -0
  114. data/db/migrate/20200730101242_create_solidus_subscriptions_subscription_events.rb +22 -0
  115. data/db/migrate/20200917072152_add_subscription_reference_to_orders.rb +11 -0
  116. data/db/migrate/20201007140032_add_guest_token_to_subscriptions.rb +6 -0
  117. data/db/migrate/20201123171026_change_actionable_date_to_date.rb +15 -0
  118. data/db/migrate/20210205140422_add_currency_to_subscription.rb +5 -0
  119. data/db/migrate/20210323165714_update_promotion_rule_names.rb +22 -0
  120. data/lib/generators/solidus_subscriptions/install/install_generator.rb +32 -0
  121. data/lib/generators/solidus_subscriptions/install/templates/initializer.rb +99 -0
  122. data/lib/solidus_subscriptions.rb +49 -0
  123. data/lib/solidus_subscriptions/checkout.rb +74 -0
  124. data/lib/solidus_subscriptions/churn_buster/client.rb +48 -0
  125. data/lib/solidus_subscriptions/churn_buster/order_serializer.rb +19 -0
  126. data/lib/solidus_subscriptions/churn_buster/serializer.rb +23 -0
  127. data/lib/solidus_subscriptions/churn_buster/subscription_customer_serializer.rb +28 -0
  128. data/lib/solidus_subscriptions/churn_buster/subscription_payment_method_serializer.rb +37 -0
  129. data/lib/solidus_subscriptions/churn_buster/subscription_serializer.rb +17 -0
  130. data/lib/solidus_subscriptions/configuration.rb +84 -0
  131. data/lib/solidus_subscriptions/dispatcher/base.rb +18 -0
  132. data/lib/solidus_subscriptions/dispatcher/failure_dispatcher.rb +13 -0
  133. data/lib/solidus_subscriptions/dispatcher/out_of_stock_dispatcher.rb +11 -0
  134. data/lib/solidus_subscriptions/dispatcher/payment_failed_dispatcher.rb +19 -0
  135. data/lib/solidus_subscriptions/dispatcher/success_dispatcher.rb +17 -0
  136. data/lib/solidus_subscriptions/engine.rb +56 -0
  137. data/lib/solidus_subscriptions/permission_sets/default_customer.rb +19 -0
  138. data/lib/solidus_subscriptions/permission_sets/subscription_management.rb +12 -0
  139. data/lib/solidus_subscriptions/permitted_attributes.rb +20 -0
  140. data/lib/solidus_subscriptions/processor.rb +17 -0
  141. data/lib/solidus_subscriptions/subscription_generator.rb +77 -0
  142. data/lib/solidus_subscriptions/subscription_line_item_builder.rb +23 -0
  143. data/lib/solidus_subscriptions/testing_support/factories/installment_detail_factory.rb +11 -0
  144. data/lib/solidus_subscriptions/testing_support/factories/installment_factory.rb +29 -0
  145. data/lib/solidus_subscriptions/testing_support/factories/line_item_factory.rb +20 -0
  146. data/lib/solidus_subscriptions/testing_support/factories/spree/line_item_factory.rb +17 -0
  147. data/lib/solidus_subscriptions/testing_support/factories/spree/order_factory.rb +17 -0
  148. data/lib/solidus_subscriptions/testing_support/factories/spree_modification_factory.rb +10 -0
  149. data/lib/solidus_subscriptions/testing_support/factories/subscription_event_factory.rb +8 -0
  150. data/lib/solidus_subscriptions/testing_support/factories/subscription_factory.rb +56 -0
  151. data/lib/solidus_subscriptions/version.rb +5 -0
  152. data/lib/tasks/process_subscriptions.rake +8 -0
  153. data/reference/solidus_subscriptions.v1.yaml +290 -0
  154. data/solidus_subscriptions.gemspec +47 -0
  155. data/spec/controllers/spree/admin/subscriptions_controller_spec.rb +202 -0
  156. data/spec/controllers/spree/api/line_items_controller_spec.rb +103 -0
  157. data/spec/controllers/spree/api/orders_controller_spec.rb +57 -0
  158. data/spec/controllers/spree/api/users_controller_spec.rb +48 -0
  159. data/spec/decorators/controllers/solidus_subscriptions/spree/orders_controller/create_subscription_line_items_spec.rb +80 -0
  160. data/spec/decorators/models/solidus_subscriptions/spree/line_item/subscription_line_items_association_spec.rb +10 -0
  161. data/spec/decorators/models/solidus_subscriptions/spree/order/finalize_creates_subscriptions_spec.rb +32 -0
  162. data/spec/decorators/models/solidus_subscriptions/spree/order/installment_details_association_spec.rb +9 -0
  163. data/spec/decorators/models/solidus_subscriptions/spree/order/subscription_line_items_association_spec.rb +9 -0
  164. data/spec/decorators/models/solidus_subscriptions/spree/user/have_many_subscriptions_spec.rb +22 -0
  165. data/spec/decorators/models/solidus_subscriptions/spree/variant/auto_delete_from_subscriptions_spec.rb +25 -0
  166. data/spec/features/admin/subscription_orders_spec.rb +35 -0
  167. data/spec/features/admin/subscriptions_spec.rb +63 -0
  168. data/spec/features/admin_users_subscription_tabs_spec.rb +61 -0
  169. data/spec/fixtures/cassettes/churn_buster.yml +229 -0
  170. data/spec/jobs/solidus_subscriptions/process_installment_job_spec.rb +38 -0
  171. data/spec/jobs/solidus_subscriptions/process_subscription_job_spec.rb +83 -0
  172. data/spec/lib/solidus_subscriptions/checkout_spec.rb +125 -0
  173. data/spec/lib/solidus_subscriptions/churn_buster/client_spec.rb +59 -0
  174. data/spec/lib/solidus_subscriptions/dispatcher/failure_dispatcher_spec.rb +29 -0
  175. data/spec/lib/solidus_subscriptions/dispatcher/out_of_stock_dispatcher_spec.rb +15 -0
  176. data/spec/lib/solidus_subscriptions/dispatcher/payment_failed_dispatcher_spec.rb +44 -0
  177. data/spec/lib/solidus_subscriptions/dispatcher/success_dispatcher_spec.rb +30 -0
  178. data/spec/lib/solidus_subscriptions/permission_sets/default_customer_spec.rb +95 -0
  179. data/spec/lib/solidus_subscriptions/permission_sets/subscription_management_spec.rb +26 -0
  180. data/spec/lib/solidus_subscriptions/processor_spec.rb +34 -0
  181. data/spec/lib/solidus_subscriptions/promotion/rules/subscription_creation_order_spec.rb +57 -0
  182. data/spec/lib/solidus_subscriptions/promotion/rules/subscription_installment_order_spec.rb +39 -0
  183. data/spec/lib/solidus_subscriptions/subscription_generator_spec.rb +83 -0
  184. data/spec/lib/solidus_subscriptions_spec.rb +30 -0
  185. data/spec/models/solidus_subscriptions/installment_detail_spec.rb +23 -0
  186. data/spec/models/solidus_subscriptions/installment_spec.rb +201 -0
  187. data/spec/models/solidus_subscriptions/line_item_spec.rb +29 -0
  188. data/spec/models/solidus_subscriptions/subscription_spec.rb +814 -0
  189. data/spec/models/spree/variant_spec.rb +16 -0
  190. data/spec/models/spree/wallet_payment_source_spec.rb +20 -0
  191. data/spec/requests/api/v1/line_items_spec.rb +116 -0
  192. data/spec/requests/api/v1/subscriptions_spec.rb +255 -0
  193. data/spec/spec_helper.rb +30 -0
  194. data/spec/subscribers/solidus_subscriptions/churn_buster_subscriber_spec.rb +76 -0
  195. data/spec/support/active_model_mocks.rb +1 -0
  196. data/spec/support/cancancan.rb +1 -0
  197. data/spec/support/factories.rb +1 -0
  198. data/spec/support/helpers/checkout_infrastructure.rb +18 -0
  199. data/spec/support/helpers/config.rb +13 -0
  200. data/spec/support/shoulda.rb +7 -0
  201. data/spec/support/timecop.rb +1 -0
  202. data/spec/support/vcr.rb +10 -0
  203. data/spec/support/version_cake.rb +8 -0
  204. metadata +498 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module is responsible for managing what attributes can be updated
4
+ # through the api. It also overrides Spree::Permitted attributes to allow the
5
+ # solidus api to accept nested params for subscription models as well
6
+ module SolidusSubscriptions
7
+ module PermittedAttributes
8
+ class << self
9
+ def subscription_line_item_attributes
10
+ [SolidusSubscriptions.configuration.subscription_line_item_attributes]
11
+ end
12
+
13
+ def subscription_attributes
14
+ SolidusSubscriptions.configuration.subscription_attributes | [
15
+ line_items_attributes: (subscription_line_item_attributes | [:id] - [:subscribable_id]),
16
+ ]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusSubscriptions
4
+ class Processor
5
+ class << self
6
+ def run
7
+ SolidusSubscriptions::Subscription
8
+ .where(installments: SolidusSubscriptions::Installment.actionable)
9
+ .or(SolidusSubscriptions::Subscription.actionable)
10
+ .distinct
11
+ .find_each do |subscription|
12
+ ProcessSubscriptionJob.perform_later(subscription)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module is responsible for taking SolidusSubscriptions::LineItem
4
+ # objects and creating SolidusSubscriptions::Subscription Objects
5
+ module SolidusSubscriptions
6
+ module SubscriptionGenerator
7
+ extend self
8
+
9
+ SubscriptionConfiguration = Struct.new(:interval_length, :interval_units, :end_date)
10
+
11
+ # Create and persist a subscription for a collection of subscription
12
+ # line items
13
+ #
14
+ # @param subscription_line_items [Array<SolidusSubscriptions::LineItem>] The
15
+ # subscription_line_items to be activated
16
+ #
17
+ # @return [SolidusSubscriptions::Subscription]
18
+ def activate(subscription_line_items)
19
+ return if subscription_line_items.empty?
20
+
21
+ order = subscription_line_items.first.order
22
+ configuration = subscription_configuration(subscription_line_items.first)
23
+
24
+ subscription_attributes = {
25
+ user: order.user,
26
+ line_items: subscription_line_items,
27
+ store: order.store,
28
+ shipping_address: order.ship_address,
29
+ billing_address: order.bill_address,
30
+ payment_source: order.payments.valid.last&.payment_source,
31
+ payment_method: order.payments.valid.last&.payment_method,
32
+ currency: order.currency,
33
+ **configuration.to_h
34
+ }
35
+
36
+ Subscription.create!(subscription_attributes) do |sub|
37
+ sub.actionable_date = sub.next_actionable_date
38
+ end.tap do |_subscription|
39
+ cleanup_subscription_line_items(subscription_line_items)
40
+ end
41
+ end
42
+
43
+ # Group a collection of line items by common subscription configuration
44
+ # options. Grouped subscription_line_items can belong to a single
45
+ # subscription.
46
+ #
47
+ # @param subscription_line_items [Array<SolidusSubscriptions::LineItem>] The
48
+ # subscription_line_items to be grouped.
49
+ #
50
+ # @return [Array<Array<SolidusSubscriptions::LineItem>>]
51
+ def group(subscription_line_items)
52
+ subscription_line_items.group_by do |li|
53
+ subscription_configuration(li)
54
+ end.
55
+ values
56
+ end
57
+
58
+ private
59
+
60
+ def cleanup_subscription_line_items(subscription_line_items)
61
+ ids = subscription_line_items.pluck :id
62
+ SolidusSubscriptions::LineItem.where(id: ids).update_all(
63
+ interval_length: nil,
64
+ interval_units: nil,
65
+ end_date: nil
66
+ )
67
+ end
68
+
69
+ def subscription_configuration(subscription_line_item)
70
+ SubscriptionConfiguration.new(
71
+ subscription_line_item.interval_length,
72
+ subscription_line_item.interval_units,
73
+ subscription_line_item.end_date
74
+ )
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusSubscriptions
4
+ module SubscriptionLineItemBuilder
5
+ private
6
+
7
+ def create_subscription_line_item(line_item)
8
+ SolidusSubscriptions::LineItem.create!(
9
+ subscription_params.merge(spree_line_item: line_item)
10
+ )
11
+
12
+ # Rerun the promotion handler to pickup subscription promotions
13
+ ::Spree::PromotionHandler::Cart.new(line_item.order).activate
14
+ line_item.order.recalculate
15
+ end
16
+
17
+ def subscription_params
18
+ params.require(:subscription_line_item).permit(
19
+ SolidusSubscriptions.configuration.subscription_line_item_attributes
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :installment_detail, class: 'SolidusSubscriptions::InstallmentDetail' do
5
+ installment
6
+
7
+ trait(:success) {
8
+ success { true }
9
+ }
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :installment, class: 'SolidusSubscriptions::Installment' do
5
+ transient {
6
+ subscription_traits { [] }
7
+ }
8
+ subscription { association(:subscription, :with_line_item, *subscription_traits) }
9
+
10
+ trait :failed do
11
+ actionable_date { Time.zone.yesterday }
12
+ details { [association(:installment_detail, installment: @instance)] }
13
+ end
14
+
15
+ trait :success do
16
+ transient do
17
+ order { create :completed_order_with_totals }
18
+ end
19
+
20
+ details do
21
+ [association(:installment_detail, :success, installment: @instance, order: order)]
22
+ end
23
+ end
24
+
25
+ trait :actionable do
26
+ actionable_date { Time.zone.now }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :subscription_line_item, class: 'SolidusSubscriptions::LineItem' do
5
+ subscribable_id { create(:variant, subscribable: true).id }
6
+ quantity { 1 }
7
+ interval_length { 1 }
8
+ interval_units { :month }
9
+
10
+ association :spree_line_item, factory: :line_item
11
+
12
+ trait :with_subscription do
13
+ transient do
14
+ subscription_traits { [] }
15
+ end
16
+
17
+ subscription { association :subscription, *subscription_traits }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :line_item do
5
+ trait :with_subscription_line_items do
6
+ transient do
7
+ n_subscription_line_items { 1 }
8
+ end
9
+
10
+ subscription_line_items do
11
+ Array.new(n_subscription_line_items) do
12
+ association :subscription_line_item, spree_line_item: @instance
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :order do
5
+ trait :with_subscription_line_items do
6
+ transient do
7
+ n_line_items { 1 }
8
+ end
9
+
10
+ line_items do
11
+ Array.new(n_line_items) do
12
+ association :line_item, :with_subscription_line_items, order: @instance
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :user do
5
+ trait :subscription_user do
6
+ bill_address
7
+ ship_address
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :subscription_event, class: 'SolidusSubscriptions::SubscriptionEvent' do
5
+ subscription
6
+ event_type { 'test_event' }
7
+ end
8
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :subscription, class: 'SolidusSubscriptions::Subscription' do
5
+ store
6
+ interval_length { 1 }
7
+ interval_units { :month }
8
+ currency { 'USD' }
9
+
10
+ user do
11
+ new_user = create(:user, :subscription_user)
12
+ card = create(:credit_card, gateway_customer_profile_id: 'BGS-123', user: new_user)
13
+ wallet_payment_source = new_user.wallet.add(card)
14
+ new_user.wallet.default_wallet_payment_source = wallet_payment_source
15
+ new_user
16
+ end
17
+
18
+ trait :with_line_item do
19
+ transient do
20
+ line_item_traits { [] }
21
+ end
22
+
23
+ line_items { [association(:subscription_line_item, *line_item_traits)] }
24
+ end
25
+
26
+ trait :with_shipping_address do
27
+ association :shipping_address, factory: :address
28
+ end
29
+
30
+ trait :with_billing_address do
31
+ association :billing_address, factory: :address
32
+ end
33
+
34
+ trait :actionable do
35
+ with_line_item
36
+ actionable_date { Time.zone.now.yesterday.beginning_of_minute }
37
+ end
38
+
39
+ trait :not_actionable do
40
+ with_line_item
41
+ actionable_date { Time.zone.now.tomorrow.beginning_of_minute }
42
+ end
43
+
44
+ trait(:pending_cancellation) do
45
+ actionable
46
+ state { 'pending_cancellation' }
47
+ end
48
+
49
+ trait(:canceled) {
50
+ state { 'canceled' }
51
+ }
52
+ trait(:inactive) {
53
+ state { 'inactive' }
54
+ }
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusSubscriptions
4
+ VERSION = '1.0.0.rc1'
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :solidus_subscriptions do
4
+ desc 'Create orders for actionable subscriptions'
5
+ task process: :environment do
6
+ SolidusSubscriptions::Processor.run
7
+ end
8
+ end
@@ -0,0 +1,290 @@
1
+ openapi: 3.0.0
2
+ info:
3
+ title: solidus_subscriptions
4
+ version: '1.0'
5
+ servers:
6
+ - url: 'http://localhost:3000'
7
+ paths:
8
+ '/api/orders/{order_id}/line_items':
9
+ parameters:
10
+ - schema:
11
+ type: string
12
+ name: order_id
13
+ in: path
14
+ required: true
15
+ post:
16
+ summary: Create Subscription Line Item
17
+ tags:
18
+ - Subscription Line Items
19
+ responses: {}
20
+ operationId: post-api-orders-order_id-line_items
21
+ requestBody:
22
+ content:
23
+ application/json:
24
+ schema:
25
+ type: object
26
+ properties:
27
+ subscription_line_item:
28
+ $ref: '#/components/schemas/SubscriptionLineItem'
29
+ '/subscriptions/api/v1/line_items/{id}':
30
+ parameters:
31
+ - schema:
32
+ type: string
33
+ name: id
34
+ in: path
35
+ required: true
36
+ patch:
37
+ summary: Update Subscription Line Item
38
+ tags:
39
+ - Subscription Line Items
40
+ responses:
41
+ '200':
42
+ description: OK
43
+ content:
44
+ application/json:
45
+ schema:
46
+ $ref: '#/components/schemas/SubscriptionLineItemOutput'
47
+ operationId: patch-subscriptions-api-v1-line_item-id
48
+ requestBody:
49
+ content:
50
+ application/json:
51
+ schema:
52
+ type: object
53
+ properties:
54
+ subscription_line_item:
55
+ $ref: '#/components/schemas/SubscriptionLineItem'
56
+ delete:
57
+ summary: Delete Subscription Line Item
58
+ operationId: delete-subscriptions-api-v1-line_item-id
59
+ responses:
60
+ '200':
61
+ description: OK
62
+ content:
63
+ application/json:
64
+ schema:
65
+ $ref: '#/components/schemas/SubscriptionLineItemOutput'
66
+ description: ''
67
+ tags:
68
+ - Subscription Line Items
69
+ '/subscriptions/api/v1/subscriptions/:id/skip':
70
+ post:
71
+ summary: Skip Subscription
72
+ tags:
73
+ - Subscriptions
74
+ responses:
75
+ '200':
76
+ description: OK
77
+ content:
78
+ application/json:
79
+ schema:
80
+ $ref: '#/components/schemas/SubscriptionOutput'
81
+ operationId: 'post-subscriptions-api-v1-subscriptions-:id-skip'
82
+ '/subscriptions/api/v1/subscriptions/{id}/cancel':
83
+ parameters:
84
+ - schema:
85
+ type: string
86
+ name: id
87
+ in: path
88
+ required: true
89
+ post:
90
+ summary: Cancel Subscription
91
+ tags:
92
+ - Subscriptions
93
+ responses:
94
+ '200':
95
+ description: OK
96
+ content:
97
+ application/json:
98
+ schema:
99
+ $ref: '#/components/schemas/SubscriptionOutput'
100
+ operationId: post-subscriptions-api-v1-subscriptions-id-cancel
101
+ '/subscriptions/api/v1/subscriptions/{id}':
102
+ parameters:
103
+ - schema:
104
+ type: string
105
+ name: id
106
+ in: path
107
+ required: true
108
+ patch:
109
+ summary: Update Subscription
110
+ tags:
111
+ - Subscriptions
112
+ responses:
113
+ '200':
114
+ description: OK
115
+ content:
116
+ application/json:
117
+ schema:
118
+ allOf:
119
+ - type: object
120
+ properties:
121
+ line_items:
122
+ type: array
123
+ items:
124
+ $ref: '#/components/schemas/SubscriptionLineItemOutput'
125
+ shipping_address:
126
+ type: object
127
+ billing_address:
128
+ type: object
129
+ - $ref: '#/components/schemas/SubscriptionOutput'
130
+ operationId: patch-subscriptions-api-v1-subscriptions-id
131
+ requestBody:
132
+ content:
133
+ application/json:
134
+ schema:
135
+ type: object
136
+ properties:
137
+ subscription:
138
+ allOf:
139
+ - type: object
140
+ properties:
141
+ line_items_attributes:
142
+ type: array
143
+ items:
144
+ $ref: '#/components/schemas/SubscriptionLineItem'
145
+ shipping_address_attributes:
146
+ type: object
147
+ billing_address_attributes:
148
+ type: object
149
+ - $ref: '#/components/schemas/Subscription'
150
+ '/subscriptions/api/v1/subscriptions/{id}/activate':
151
+ parameters:
152
+ - schema:
153
+ type: string
154
+ name: id
155
+ in: path
156
+ required: true
157
+ post:
158
+ summary: Activate Subscription
159
+ tags:
160
+ - Subscriptions
161
+ responses:
162
+ '200':
163
+ description: OK
164
+ content:
165
+ application/json:
166
+ schema:
167
+ $ref: '#/components/schemas/SubscriptionOutput'
168
+ operationId: post-subscriptions-api-v1-subscriptions-id-activate
169
+ components:
170
+ schemas:
171
+ SubscriptionLineItem:
172
+ title: SubscriptionLineItem
173
+ type: object
174
+ properties:
175
+ quantity:
176
+ type: integer
177
+ minimum: 1
178
+ end_date:
179
+ type: string
180
+ format: date
181
+ interval_length:
182
+ type: integer
183
+ minimum: 1
184
+ interval_units:
185
+ type: string
186
+ enum:
187
+ - day
188
+ - week
189
+ - month
190
+ - year
191
+ subscribable_id:
192
+ type: integer
193
+ required:
194
+ - quantity
195
+ - end_date
196
+ - interval_length
197
+ - interval_units
198
+ - subscribable_id
199
+ x-tags:
200
+ - Models
201
+ SubscriptionLineItemOutput:
202
+ title: SubscriptionLineItemOutput
203
+ allOf:
204
+ - $ref: '#/components/schemas/SubscriptionLineItem'
205
+ - type: object
206
+ properties:
207
+ id:
208
+ type: integer
209
+ spree_line_item_id:
210
+ type: integer
211
+ subscription_id:
212
+ type: integer
213
+ created_at:
214
+ type: string
215
+ format: date-time
216
+ updated_at:
217
+ type: string
218
+ format: date-time
219
+ required:
220
+ - id
221
+ - spree_line_item_id
222
+ - subscription_id
223
+ - created_at
224
+ - updated_at
225
+ x-tags:
226
+ - Models
227
+ Subscription:
228
+ title: Subscription
229
+ type: object
230
+ x-tags:
231
+ - Models
232
+ properties:
233
+ actionable_date:
234
+ type: string
235
+ format: date
236
+ interval_units:
237
+ type: string
238
+ enum:
239
+ - day
240
+ - week
241
+ - month
242
+ - year
243
+ interval_length:
244
+ type: string
245
+ end_date:
246
+ type: string
247
+ format: date
248
+ required:
249
+ - actionable_date
250
+ - interval_units
251
+ - interval_length
252
+ - end_date
253
+ SubscriptionOutput:
254
+ title: SubscriptionOutput
255
+ allOf:
256
+ - $ref: '#/components/schemas/Subscription'
257
+ - type: object
258
+ properties:
259
+ id:
260
+ type: integer
261
+ created_at:
262
+ type: string
263
+ format: date-time
264
+ updated_at:
265
+ type: string
266
+ format: date-time
267
+ state:
268
+ type: string
269
+ enum:
270
+ - active
271
+ - canceled
272
+ - pending_cancellation
273
+ - inactive
274
+ user_id:
275
+ type: integer
276
+ processing_state:
277
+ type: string
278
+ enum:
279
+ - pending
280
+ - success
281
+ - failed
282
+ required:
283
+ - id
284
+ - created_at
285
+ - updated_at
286
+ - state
287
+ - user_id
288
+ - processing_state
289
+ x-tags:
290
+ - Models