solidus_subscriptions 1.0.0.rc1

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 (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