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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Spree::Variant, type: :model do
6
+ let(:variant) { build_stubbed :variant }
7
+
8
+ describe "#pretty_name" do
9
+ subject(:pretty_name) { variant.pretty_name }
10
+
11
+ it 'includes the product and options', :aggregate_failures do
12
+ expect(pretty_name).to match variant.name
13
+ expect(pretty_name).to match variant.options_text
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Spree::WalletPaymentSource do
4
+ describe 'setting it as the default' do
5
+ it 'reports a payment method changed event for subscriptions that use the default payment source' do
6
+ stub_const('Spree::Event', class_spy(Spree::Event))
7
+ user = create(:user)
8
+ subscription = create(:subscription, user: user)
9
+ payment_source = create(:credit_card, user: user)
10
+ wallet_payment_source = user.wallet.add(payment_source)
11
+
12
+ user.wallet.default_wallet_payment_source = wallet_payment_source
13
+
14
+ expect(Spree::Event).to have_received(:fire).with(
15
+ 'solidus_subscriptions.subscription_payment_method_changed',
16
+ subscription: subscription,
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe '/api/v1/line_items' do
4
+ include SolidusSubscriptions::Engine.routes.url_helpers
5
+
6
+ describe 'PATCH /:id' do
7
+ context 'when the subscription belongs to the user' do
8
+ context 'with valid params' do
9
+ it 'responds with 200 OK' do
10
+ user = create(:user, &:generate_spree_api_key!)
11
+ subscription = create(:subscription, user: user)
12
+ line_item = create(:subscription_line_item, subscription: subscription)
13
+
14
+ patch(
15
+ api_v1_line_item_path(line_item),
16
+ params: { subscription_line_item: { quantity: 11 } },
17
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
18
+ )
19
+
20
+ expect(response.status).to eq(200)
21
+ end
22
+
23
+ it 'updates the line item' do
24
+ user = create(:user, &:generate_spree_api_key!)
25
+ subscription = create(:subscription, user: user)
26
+ line_item = create(:subscription_line_item, subscription: subscription)
27
+
28
+ patch(
29
+ api_v1_line_item_path(line_item),
30
+ params: { subscription_line_item: { quantity: 11 } },
31
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
32
+ )
33
+
34
+ expect(line_item.reload.quantity).to eq(11)
35
+ end
36
+ end
37
+
38
+ context 'with invalid params' do
39
+ it 'responds with 422 Unprocessable Entity' do
40
+ user = create(:user, &:generate_spree_api_key!)
41
+ subscription = create(:subscription, user: user)
42
+ line_item = create(:subscription_line_item, subscription: subscription)
43
+
44
+ patch(
45
+ api_v1_line_item_path(line_item),
46
+ params: { subscription_line_item: { quantity: -1 } },
47
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
48
+ )
49
+
50
+ expect(response.status).to eq(422)
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when the subscription does not belong to the user' do
56
+ it 'responds with 401 Unauthorized' do
57
+ user = create(:user, &:generate_spree_api_key!)
58
+ subscription = create(:subscription)
59
+ line_item = create(:subscription_line_item, subscription: subscription)
60
+
61
+ patch(
62
+ api_v1_line_item_path(line_item),
63
+ params: { subscription_line_item: { quantity: 11 } },
64
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
65
+ )
66
+
67
+ expect(response.status).to eq(401)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe 'DELETE /:id' do
73
+ context 'when the subscription belongs to the user' do
74
+ it 'responds with 200 OK' do
75
+ user = create(:user, &:generate_spree_api_key!)
76
+ subscription = create(:subscription, user: user)
77
+ line_item = create(:subscription_line_item, subscription: subscription)
78
+
79
+ delete(
80
+ api_v1_line_item_path(line_item),
81
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
82
+ )
83
+
84
+ expect(response.status).to eq(200)
85
+ end
86
+
87
+ it 'deletes the line item' do
88
+ user = create(:user, &:generate_spree_api_key!)
89
+ subscription = create(:subscription, user: user)
90
+ line_item = create(:subscription_line_item, subscription: subscription)
91
+
92
+ delete(
93
+ api_v1_line_item_path(line_item),
94
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
95
+ )
96
+
97
+ expect { line_item.reload }.to raise_error(ActiveRecord::RecordNotFound)
98
+ end
99
+ end
100
+
101
+ context 'when the subscription does not belong to the user' do
102
+ it 'responds with 401 Unauthorized' do
103
+ user = create(:user, &:generate_spree_api_key!)
104
+ subscription = create(:subscription)
105
+ line_item = create(:subscription_line_item, subscription: subscription)
106
+
107
+ delete(
108
+ api_v1_line_item_path(line_item),
109
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
110
+ )
111
+
112
+ expect(response.status).to eq(401)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,255 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe '/api/v1/subscriptions' do
4
+ include SolidusSubscriptions::Engine.routes.url_helpers
5
+
6
+ describe 'POST /' do
7
+ context 'with valid params' do
8
+ it 'creates the subscription and responds with 200 OK' do
9
+ user = create(:user, &:generate_spree_api_key!)
10
+
11
+ expect do
12
+ post(
13
+ api_v1_subscriptions_path,
14
+ params: { subscription: { interval_length: 11 } },
15
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
16
+ )
17
+ end.to change(SolidusSubscriptions::Subscription, :count).from(0).to(1)
18
+
19
+ expect(response.status).to eq(200)
20
+ end
21
+ end
22
+
23
+ context 'with invalid params' do
24
+ it "doesn't create the subscription and responds with 422 Unprocessable Entity" do
25
+ user = create(:user, &:generate_spree_api_key!)
26
+
27
+ expect do
28
+ post(
29
+ api_v1_subscriptions_path,
30
+ params: { subscription: { interval_length: -1 } },
31
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
32
+ )
33
+ end.not_to change(SolidusSubscriptions::Subscription, :count)
34
+
35
+ expect(response.status).to eq(422)
36
+ end
37
+ end
38
+
39
+ context 'when valid payment attributes are provided' do
40
+ # rubocop:disable RSpec/MultipleExpectations
41
+ it 'creates the subscription using the specified payment' do
42
+ user = create(:user, &:generate_spree_api_key!)
43
+ payment_source = create(:credit_card, user: user)
44
+ payment_params = { payment_method_id: payment_source.payment_method.id, payment_source_id: payment_source.id }
45
+
46
+ expect(user.wallet.default_wallet_payment_source).to be_nil
47
+ expect do
48
+ post(
49
+ api_v1_subscriptions_path,
50
+ params: { subscription: { interval_length: 7 }.merge(payment_params) },
51
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
52
+ )
53
+ end.to change(SolidusSubscriptions::Subscription, :count).from(0).to(1)
54
+ expect(SolidusSubscriptions::Subscription.last).to have_attributes(payment_params)
55
+ end
56
+ # rubocop:enable RSpec/MultipleExpectations
57
+ end
58
+
59
+ # rubocop:disable RSpec/MultipleExpectations
60
+ context 'when an invalid payment method is provided' do
61
+ it "doesn't create the subscription and responds with 422 Unprocessable Entity" do
62
+ user = create(:user, &:generate_spree_api_key!)
63
+ payment_source = create(:credit_card)
64
+ payment_params = { payment_source_id: payment_source.id }
65
+
66
+ expect do
67
+ post(
68
+ api_v1_subscriptions_path,
69
+ params: { subscription: { interval_length: 7 }.merge(payment_params) },
70
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
71
+ )
72
+ end.not_to change(SolidusSubscriptions::Subscription, :count)
73
+
74
+ error_message = I18n.t('solidus_subscriptions.subscription.invalid_payment_details')
75
+ response_body = JSON.parse(response.body)
76
+ expect(response_body).to eq('payment_source_type' => [error_message])
77
+ expect(response.status).to eq(422)
78
+ end
79
+ end
80
+
81
+ context 'when an invalid payment source is provided' do
82
+ it "doesn't create the subscription and responds with 422 Unprocessable Entity" do
83
+ user = create(:user, &:generate_spree_api_key!)
84
+ payment_source = create(:credit_card)
85
+ payment_params = { payment_method_id: payment_source.payment_method.id }
86
+
87
+ expect do
88
+ post(
89
+ api_v1_subscriptions_path,
90
+ params: { subscription: { interval_length: 7 }.merge(payment_params) },
91
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
92
+ )
93
+ end.not_to change(SolidusSubscriptions::Subscription, :count)
94
+
95
+ error_message = I18n.t('solidus_subscriptions.subscription.invalid_payment_details')
96
+ response_body = JSON.parse(response.body)
97
+ expect(response_body).to eq('payment_source_type' => [error_message])
98
+ expect(response.status).to eq(422)
99
+ end
100
+ end
101
+ # rubocop:enable RSpec/MultipleExpectations
102
+ end
103
+
104
+ describe 'PATCH /:id' do
105
+ context 'when the subscription belongs to the user' do
106
+ context 'with valid params' do
107
+ it 'responds with 200 OK' do
108
+ user = create(:user, &:generate_spree_api_key!)
109
+ subscription = create(:subscription, user: user)
110
+
111
+ patch(
112
+ api_v1_subscription_path(subscription),
113
+ params: { subscription: { interval_length: 11 } },
114
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
115
+ )
116
+
117
+ expect(response.status).to eq(200)
118
+ end
119
+
120
+ it 'updates the subscription' do
121
+ user = create(:user, &:generate_spree_api_key!)
122
+ subscription = create(:subscription, user: user)
123
+
124
+ patch(
125
+ api_v1_subscription_path(subscription),
126
+ params: { subscription: { interval_length: 11 } },
127
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
128
+ )
129
+
130
+ expect(subscription.reload.interval_length).to eq(11)
131
+ end
132
+ end
133
+
134
+ context 'with invalid params' do
135
+ it 'responds with 422 Unprocessable Entity' do
136
+ user = create(:user, &:generate_spree_api_key!)
137
+ subscription = create(:subscription, user: user)
138
+
139
+ patch(
140
+ api_v1_subscription_path(subscription),
141
+ params: { subscription: { interval_length: -1 } },
142
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
143
+ )
144
+
145
+ expect(response.status).to eq(422)
146
+ end
147
+ end
148
+ end
149
+
150
+ context 'when the subscription does not belong to the user' do
151
+ it 'responds with 401 Unauthorized' do
152
+ user = create(:user, &:generate_spree_api_key!)
153
+ subscription = create(:subscription)
154
+
155
+ patch(
156
+ api_v1_subscription_path(subscription),
157
+ params: { subscription: { interval_length: 11 } },
158
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
159
+ )
160
+
161
+ expect(response.status).to eq(401)
162
+ end
163
+ end
164
+ end
165
+
166
+ describe 'POST /:id/skip' do
167
+ context 'when the subscription belongs to the user' do
168
+ it 'responds with 200 OK' do
169
+ user = create(:user, &:generate_spree_api_key!)
170
+ subscription = create(:subscription, user: user)
171
+
172
+ post(
173
+ skip_api_v1_subscription_path(subscription),
174
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
175
+ )
176
+
177
+ expect(response.status).to eq(200)
178
+ end
179
+
180
+ it 'skips the subscription' do
181
+ user = create(:user, &:generate_spree_api_key!)
182
+ subscription = create(
183
+ :subscription,
184
+ user: user,
185
+ interval_length: 1,
186
+ interval_units: 'week',
187
+ actionable_date: Time.zone.today,
188
+ )
189
+
190
+ post(
191
+ skip_api_v1_subscription_path(subscription),
192
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
193
+ )
194
+
195
+ expect(subscription.reload.actionable_date).to eq(Time.zone.today + 1.week)
196
+ end
197
+ end
198
+
199
+ context 'when the subscription does not belong to the user' do
200
+ it 'responds with 401 Unauthorized' do
201
+ user = create(:user, &:generate_spree_api_key!)
202
+ subscription = create(:subscription)
203
+
204
+ post(
205
+ skip_api_v1_subscription_path(subscription),
206
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
207
+ )
208
+
209
+ expect(response.status).to eq(401)
210
+ end
211
+ end
212
+ end
213
+
214
+ describe 'POST /:id/cancel' do
215
+ context 'when the subscription belongs to the user' do
216
+ it 'responds with 200 OK' do
217
+ user = create(:user, &:generate_spree_api_key!)
218
+ subscription = create(:subscription, user: user)
219
+
220
+ post(
221
+ cancel_api_v1_subscription_path(subscription),
222
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
223
+ )
224
+
225
+ expect(response.status).to eq(200)
226
+ end
227
+
228
+ it 'cancels the subscription' do
229
+ user = create(:user, &:generate_spree_api_key!)
230
+ subscription = create(:subscription, user: user)
231
+
232
+ post(
233
+ cancel_api_v1_subscription_path(subscription),
234
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
235
+ )
236
+
237
+ expect(subscription.reload.state).to eq('canceled')
238
+ end
239
+ end
240
+
241
+ context 'when the subscription does not belong to the user' do
242
+ it 'responds with 401 Unauthorized' do
243
+ user = create(:user, &:generate_spree_api_key!)
244
+ subscription = create(:subscription)
245
+
246
+ post(
247
+ cancel_api_v1_subscription_path(subscription),
248
+ headers: { 'Authorization' => "Bearer #{user.spree_api_key}" },
249
+ )
250
+
251
+ expect(response.status).to eq(401)
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Configure Rails Environment
4
+ ENV['RAILS_ENV'] = 'test'
5
+
6
+ # Run Coverage report
7
+ require 'solidus_dev_support/rspec/coverage'
8
+
9
+ # Create the dummy app if it's still missing.
10
+ dummy_env = "#{__dir__}/dummy/config/environment.rb"
11
+ system 'bin/rake extension:test_app' unless File.exist? dummy_env
12
+ require dummy_env
13
+
14
+ # Requires factories and other useful helpers defined in spree_core.
15
+ require 'solidus_dev_support/rspec/feature_helper'
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f }
20
+
21
+ SolidusDevSupport::TestingSupport::Factories.load_for(SolidusSubscriptions::Engine)
22
+
23
+ RSpec.configure do |config|
24
+ config.infer_spec_type_from_file_location!
25
+ config.use_transactional_fixtures = false
26
+
27
+ if Spree.solidus_gem_version < Gem::Version.new('2.11')
28
+ config.extend Spree::TestingSupport::AuthorizationHelpers::Request, type: :system
29
+ end
30
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SolidusSubscriptions::ChurnBusterSubscriber do
4
+ describe '#report_subscription_cancellation' do
5
+ it 'reports the cancellation to Churn Buster' do
6
+ churn_buster = instance_spy(SolidusSubscriptions::ChurnBuster::Client)
7
+ allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster)
8
+
9
+ subscription = create(:subscription)
10
+ Spree::Event.fire('solidus_subscriptions.subscription_canceled', subscription: subscription)
11
+
12
+ expect(churn_buster).to have_received(:report_subscription_cancellation).with(subscription)
13
+ end
14
+ end
15
+
16
+ describe '#report_subscription_ending' do
17
+ it 'reports the cancellation to Churn Buster' do
18
+ churn_buster = instance_spy(SolidusSubscriptions::ChurnBuster::Client)
19
+ allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster)
20
+
21
+ subscription = create(:subscription)
22
+ Spree::Event.fire('solidus_subscriptions.subscription_ended', subscription: subscription)
23
+
24
+ expect(churn_buster).to have_received(:report_subscription_cancellation).with(subscription)
25
+ end
26
+ end
27
+
28
+ describe '#report_payment_success' do
29
+ it 'reports the success to Churn Buster' do
30
+ churn_buster = instance_spy(SolidusSubscriptions::ChurnBuster::Client)
31
+ allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster)
32
+
33
+ order = build_stubbed(:order)
34
+ installment = build_stubbed(:installment)
35
+ Spree::Event.fire(
36
+ 'solidus_subscriptions.installment_succeeded',
37
+ installment: installment,
38
+ order: order,
39
+ )
40
+
41
+ expect(churn_buster).to have_received(:report_successful_payment).with(order)
42
+ end
43
+ end
44
+
45
+ describe '#report_payment_failure' do
46
+ it 'reports the failure to Churn Buster' do
47
+ churn_buster = instance_spy(SolidusSubscriptions::ChurnBuster::Client)
48
+ allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster)
49
+
50
+ order = build_stubbed(:order)
51
+ installment = build_stubbed(:installment)
52
+ Spree::Event.fire(
53
+ 'solidus_subscriptions.installment_failed_payment',
54
+ installment: installment,
55
+ order: order,
56
+ )
57
+
58
+ expect(churn_buster).to have_received(:report_failed_payment).with(order)
59
+ end
60
+ end
61
+
62
+ describe '#report_payment_method_change' do
63
+ it 'reports the payment method change to Churn Buster' do
64
+ churn_buster = instance_spy(SolidusSubscriptions::ChurnBuster::Client)
65
+ allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster)
66
+
67
+ subscription = create(:subscription)
68
+ Spree::Event.fire(
69
+ 'solidus_subscriptions.subscription_payment_method_changed',
70
+ subscription: subscription,
71
+ )
72
+
73
+ expect(churn_buster).to have_received(:report_payment_method_change).with(subscription)
74
+ end
75
+ end
76
+ end