REFACTOR: Use the Prices API in place of Plans (#17)
Stripe has a newer API called Prices where you can create a price for any product and it can either be recurring or one-time. The easy part is existing Plans work with the Prices API by passing a Plan ID, but objects are returned in the slightly-different Prices API object format. This commit is a refactor to the new API to handle the data in its new form, and lays the foundation for a one time payment plan to be added to any subscriptions product.
This commit is contained in:
		
							parent
							
								
									8bcb7aa93c
								
							
						
					
					
						commit
						c9ff55b46a
					
				
							
								
								
									
										2
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										2
									
								
								Gemfile
								
								
								
								
							|  | @ -1,3 +1,5 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| group :development do | ||||
|   gem 'translations-manager', git: 'https://github.com/discourse/translations-manager.git' | ||||
| end | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|       def index | ||||
|         begin | ||||
|           plans = ::Stripe::Plan.list(product_params) | ||||
|           plans = ::Stripe::Price.list(product_params) | ||||
| 
 | ||||
|           render_json_dump plans.data | ||||
| 
 | ||||
|  | @ -20,15 +20,19 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|       def create | ||||
|         begin | ||||
|           plan = ::Stripe::Plan.create( | ||||
|           plan = ::Stripe::Price.create( | ||||
|             nickname: params[:nickname], | ||||
|             amount: params[:amount], | ||||
|             interval: params[:interval], | ||||
|             unit_amount: params[:amount], | ||||
|             recurring: { | ||||
|               interval: params[:interval], | ||||
|             }, | ||||
|             product: params[:product], | ||||
|             trial_period_days: params[:trial_period_days], | ||||
|             currency: params[:currency], | ||||
|             active: params[:active], | ||||
|             metadata: { group_name: params[:metadata][:group_name] } | ||||
|             metadata: { | ||||
|               group_name: params[:metadata][:group_name], | ||||
|               trial_period_days: params[:trial_period_days] | ||||
|             } | ||||
|           ) | ||||
| 
 | ||||
|           render_json_dump plan | ||||
|  | @ -40,9 +44,15 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|       def show | ||||
|         begin | ||||
|           plan = ::Stripe::Plan.retrieve(params[:id]) | ||||
|           plan = ::Stripe::Price.retrieve(params[:id]) | ||||
| 
 | ||||
|           serialized = plan.to_h.merge(currency: plan[:currency].upcase) | ||||
|           if plan[:metadata] && plan[:metadata][:trial_period_days] | ||||
|             trial_days = plan[:metadata][:trial_period_days] | ||||
|           elsif plan[:recurring] && plan[:recurring][:trial_period_days] | ||||
|             trial_days = plan[:recurring][:trial_period_days] | ||||
|           end | ||||
| 
 | ||||
|           serialized = plan.to_h.merge(trial_period_days: trial_days, currency: plan[:currency].upcase) | ||||
| 
 | ||||
|           render_json_dump serialized | ||||
| 
 | ||||
|  | @ -53,12 +63,14 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|       def update | ||||
|         begin | ||||
|           plan = ::Stripe::Plan.update( | ||||
|           plan = ::Stripe::Price.update( | ||||
|             params[:id], | ||||
|             nickname: params[:nickname], | ||||
|             trial_period_days: params[:trial_period_days], | ||||
|             active: params[:active], | ||||
|             metadata: { group_name: params[:metadata][:group_name] } | ||||
|             metadata: { | ||||
|               group_name: params[:metadata][:group_name], | ||||
|               trial_period_days: params[:trial_period_days] | ||||
|             } | ||||
|           ) | ||||
| 
 | ||||
|           render_json_dump plan | ||||
|  | @ -68,17 +80,6 @@ module DiscourseSubscriptions | |||
|         end | ||||
|       end | ||||
| 
 | ||||
|       def destroy | ||||
|         begin | ||||
|           plan = ::Stripe::Plan.delete(params[:id]) | ||||
| 
 | ||||
|           render_json_dump plan | ||||
| 
 | ||||
|         rescue ::Stripe::InvalidRequestError => e | ||||
|           render_json_error e.message | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       private | ||||
| 
 | ||||
|       def product_params | ||||
|  |  | |||
|  | @ -9,13 +9,13 @@ module DiscourseSubscriptions | |||
|     def index | ||||
|       begin | ||||
|         if params[:product_id].present? | ||||
|           plans = ::Stripe::Plan.list(active: true, product: params[:product_id]) | ||||
|           plans = ::Stripe::Price.list(active: true, product: params[:product_id]) | ||||
|         else | ||||
|           plans = ::Stripe::Plan.list(active: true) | ||||
|           plans = ::Stripe::Price.list(active: true) | ||||
|         end | ||||
| 
 | ||||
|         serialized = plans[:data].map do |plan| | ||||
|           plan.to_h.slice(:id, :amount, :currency, :interval) | ||||
|           plan.to_h.slice(:id, :unit_amount, :currency, :recurring) | ||||
|         end.sort_by { |plan| plan[:amount] } | ||||
| 
 | ||||
|         render_json_dump serialized | ||||
|  |  | |||
|  | @ -27,12 +27,17 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|     def create | ||||
|       begin | ||||
|         plan = ::Stripe::Plan.retrieve(params[:plan]) | ||||
|         plan = ::Stripe::Price.retrieve(params[:plan]) | ||||
| 
 | ||||
|         if plan[:metadata] && plan[:metadata][:trial_period_days] | ||||
|           trial_days = plan[:metadata][:trial_period_days] | ||||
|         end | ||||
| 
 | ||||
|         @subscription = ::Stripe::Subscription.create( | ||||
|           customer: params[:customer], | ||||
|           items: [ { plan: params[:plan] } ], | ||||
|           items: [ { price: params[:plan] } ], | ||||
|           metadata: metadata_user, | ||||
|           trial_period_days: trial_days | ||||
|         ) | ||||
| 
 | ||||
|         group = plan_group(plan) | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ module DiscourseSubscriptions | |||
|           subscriptions = [] | ||||
| 
 | ||||
|           if subscription_ids | ||||
|             plans = ::Stripe::Plan.list( | ||||
|             plans = ::Stripe::Price.list( | ||||
|               expand: ['data.product'], | ||||
|               limit: 100 | ||||
|             ) | ||||
|  | @ -34,8 +34,9 @@ module DiscourseSubscriptions | |||
|             subscriptions = subscriptions.select { |sub| subscription_ids.include?(sub[:id]) } | ||||
| 
 | ||||
|             subscriptions.map! do |subscription| | ||||
|               plan = plans[:data].find { |p| p[:id] == subscription[:plan][:id] } | ||||
|               subscription.to_h.merge(product: plan[:product].to_h.slice(:id, :name)) | ||||
|               plan = plans[:data].find { |p| p[:id] == subscription[:items][:data][0][:price][:id] } | ||||
|               subscription.to_h.except!(:plan) | ||||
|               subscription.to_h.merge(plan: plan, product: plan[:product].to_h.slice(:id, :name)) | ||||
|             end | ||||
|           end | ||||
| 
 | ||||
|  |  | |||
|  | @ -47,10 +47,6 @@ export default Controller.extend({ | |||
|   }, | ||||
| 
 | ||||
|   actions: { | ||||
|     cancelPlan(product_id) { | ||||
|       this.redirect(product_id); | ||||
|     }, | ||||
| 
 | ||||
|     createPlan() { | ||||
|       // TODO: set default group name beforehand | ||||
|       if (this.get("model.plan.metadata.group_name") === undefined) { | ||||
|  |  | |||
|  | @ -6,28 +6,24 @@ const AdminPlan = Plan.extend({ | |||
|   isNew: false, | ||||
|   name: "", | ||||
|   interval: "month", | ||||
|   amount: 0, | ||||
|   unit_amount: 0, | ||||
|   intervals: ["day", "week", "month", "year"], | ||||
|   metadata: {}, | ||||
| 
 | ||||
|   @discourseComputed("trial_period_days") | ||||
|   parseTrialPeriodDays(trial_period_days) { | ||||
|     if (trial_period_days) { | ||||
|       return parseInt(0 + trial_period_days, 10); | ||||
|   parseTrialPeriodDays(trialDays) { | ||||
|     if (trialDays) { | ||||
|       return parseInt(0 + trialDays, 10); | ||||
|     } else { | ||||
|       return 0; | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   destroy() { | ||||
|     return ajax(`/s/admin/plans/${this.id}`, { method: "delete" }); | ||||
|   }, | ||||
| 
 | ||||
|   save() { | ||||
|     const data = { | ||||
|       nickname: this.nickname, | ||||
|       interval: this.interval, | ||||
|       amount: this.amount, | ||||
|       amount: this.unit_amount, | ||||
|       currency: this.currency, | ||||
|       trial_period_days: this.parseTrialPeriodDays, | ||||
|       product: this.product, | ||||
|  |  | |||
|  | @ -16,9 +16,7 @@ const AdminSubscription = EmberObject.extend({ | |||
| 
 | ||||
|   @discourseComputed("metadata") | ||||
|   subscriptionUserPath(metadata) { | ||||
|     return getURL( | ||||
|       `/admin/users/${metadata.user_id}/${metadata.username}` | ||||
|     ); | ||||
|     return getURL(`/admin/users/${metadata.user_id}/${metadata.username}`); | ||||
|   }, | ||||
| 
 | ||||
|   destroy() { | ||||
|  |  | |||
|  | @ -3,18 +3,22 @@ import discourseComputed from "discourse-common/utils/decorators"; | |||
| import { ajax } from "discourse/lib/ajax"; | ||||
| 
 | ||||
| const Plan = EmberObject.extend({ | ||||
|   amountDollars: Ember.computed("amount", { | ||||
|   amountDollars: Ember.computed("unit_amount", { | ||||
|     get() { | ||||
|       return parseFloat(this.get("amount") / 100).toFixed(2); | ||||
|       return parseFloat(this.get("unit_amount") / 100).toFixed(2); | ||||
|     }, | ||||
|     set(key, value) { | ||||
|       const decimal = parseFloat(value) * 100; | ||||
|       this.set("amount", decimal); | ||||
|       this.set("unit_amount", decimal); | ||||
|       return value; | ||||
|     } | ||||
|   }), | ||||
|   @discourseComputed("recurring.interval") | ||||
|   billingInterval(interval) { | ||||
|     return interval || "one-time"; | ||||
|   }, | ||||
| 
 | ||||
|   @discourseComputed("amountDollars", "currency", "interval") | ||||
|   @discourseComputed("amountDollars", "currency", "billingInterval") | ||||
|   subscriptionRate(amountDollars, currency, interval) { | ||||
|     return `${amountDollars} ${currency.toUpperCase()} / ${interval}`; | ||||
|   } | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
|       <td>{{plan.id}}</td> | ||||
|       <td>{{plan.nickname}}</td> | ||||
|       <td>{{plan.interval}}</td> | ||||
|       <td>{{plan.amount}}</td> | ||||
|       <td>{{plan.unit_amount}}</td> | ||||
|       <td class="td-right"> | ||||
|         {{d-button | ||||
|           action=(action "editPlan" plan.id) | ||||
|  |  | |||
|  | @ -80,7 +80,6 @@ | |||
|   </p> | ||||
| 
 | ||||
|   <div class="pull-right"> | ||||
|     {{d-button label="cancel" action=(action "cancelPlan" model.plan.product) icon="times"}} | ||||
| 
 | ||||
|     {{#if model.plan.isNew}} | ||||
|       {{d-button label="discourse_subscriptions.admin.plans.operations.create" action="createPlan" icon="plus" class="btn btn-primary"}} | ||||
|  |  | |||
|  | @ -62,11 +62,6 @@ | |||
|             {{#link-to "adminPlugins.discourse-subscriptions.products.show.plans.show" model.product.id plan.id class="btn no-text btn-icon"}} | ||||
|               {{d-icon "far-edit"}} | ||||
|             {{/link-to}} | ||||
|             {{d-button | ||||
|               action=(route-action "destroyPlan") | ||||
|               actionParam=plan | ||||
|               icon="trash-alt" | ||||
|               class="btn-danger btn no-text btn-icon"}} | ||||
|           </td> | ||||
|         </tr> | ||||
|       {{/each}} | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ | |||
|     }} | ||||
|       <div class="interval"> | ||||
|         {{#if planTypeIsSelected}} | ||||
|           {{i18n (concat "discourse_subscriptions.plans.interval.adverb." plan.interval)}} | ||||
|           {{i18n (concat "discourse_subscriptions.plans.interval.adverb." plan.recurring.interval)}} | ||||
|         {{else}} | ||||
|           {{i18n "discourse_subscriptions.payment.interval"}} | ||||
|         {{/if}} | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #!/usr/bin/env ruby | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'translations_manager' | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,4 +7,4 @@ class SubscriptionsUserConstraint | |||
|   rescue Discourse::InvalidAccess, Discourse::ReadOnly | ||||
|     false | ||||
|   end | ||||
| end | ||||
| end | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ | |||
| 
 | ||||
| enabled_site_setting :discourse_subscriptions_enabled | ||||
| 
 | ||||
| gem 'stripe', '5.19.0' | ||||
| gem 'stripe', '5.22.0' | ||||
| 
 | ||||
| register_asset "stylesheets/common/main.scss" | ||||
| register_asset "stylesheets/common/layout.scss" | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ module DiscourseSubscriptions | |||
|       context 'not authenticated' do | ||||
|         describe "index" do | ||||
|           it "does not get the plans" do | ||||
|             ::Stripe::Plan.expects(:list).never | ||||
|             ::Stripe::Price.expects(:list).never | ||||
|             get "/s/admin/plans.json" | ||||
|           end | ||||
| 
 | ||||
|  | @ -24,7 +24,7 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         describe "create" do | ||||
|           it "does not create a plan" do | ||||
|             ::Stripe::Plan.expects(:create).never | ||||
|             ::Stripe::Price.expects(:create).never | ||||
|             post "/s/admin/plans.json", params: { name: 'Rick Astley', amount: 1, interval: 'week' } | ||||
|           end | ||||
| 
 | ||||
|  | @ -36,7 +36,7 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         describe "show" do | ||||
|           it "does not show the plan" do | ||||
|             ::Stripe::Plan.expects(:retrieve).never | ||||
|             ::Stripe::Price.expects(:retrieve).never | ||||
|             get "/s/admin/plans/plan_12345.json" | ||||
|           end | ||||
| 
 | ||||
|  | @ -48,26 +48,9 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         describe "update" do | ||||
|           it "does not update a plan" do | ||||
|             ::Stripe::Plan.expects(:update).never | ||||
|             ::Stripe::Price.expects(:update).never | ||||
|             delete "/s/admin/plans/plan_12345.json" | ||||
|           end | ||||
| 
 | ||||
|           it "is not ok" do | ||||
|             delete "/s/admin/plans/plan_12345.json" | ||||
|             expect(response.status).to eq 403 | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         describe "delete" do | ||||
|           it "does not delete a plan" do | ||||
|             ::Stripe::Plan.expects(:delete).never | ||||
|             patch "/s/admin/plans/plan_12345.json" | ||||
|           end | ||||
| 
 | ||||
|           it "is not ok" do | ||||
|             patch "/s/admin/plans/plan_12345.json" | ||||
|             expect(response.status).to eq 403 | ||||
|           end | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|  | @ -78,25 +61,25 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         describe "index" do | ||||
|           it "lists the plans" do | ||||
|             ::Stripe::Plan.expects(:list).with(nil) | ||||
|             ::Stripe::Price.expects(:list).with(nil) | ||||
|             get "/s/admin/plans.json" | ||||
|           end | ||||
| 
 | ||||
|           it "lists the plans for the product" do | ||||
|             ::Stripe::Plan.expects(:list).with(product: 'prod_id123') | ||||
|             ::Stripe::Price.expects(:list).with(product: 'prod_id123') | ||||
|             get "/s/admin/plans.json", params: { product_id: 'prod_id123' } | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         describe "show" do | ||||
|           it "shows a plan" do | ||||
|             ::Stripe::Plan.expects(:retrieve).with('plan_12345').returns(currency: 'aud') | ||||
|             ::Stripe::Price.expects(:retrieve).with('plan_12345').returns(currency: 'aud') | ||||
|             get "/s/admin/plans/plan_12345.json" | ||||
|             expect(response.status).to eq 200 | ||||
|           end | ||||
| 
 | ||||
|           it "upcases the currency" do | ||||
|             ::Stripe::Plan.expects(:retrieve).with('plan_12345').returns(currency: 'aud') | ||||
|             ::Stripe::Price.expects(:retrieve).with('plan_12345').returns(currency: 'aud') | ||||
|             get "/s/admin/plans/plan_12345.json" | ||||
|             expect(response.parsed_body["currency"]).to eq 'AUD' | ||||
|           end | ||||
|  | @ -104,57 +87,53 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         describe "create" do | ||||
|           it "creates a plan with a nickname" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:nickname, 'Veg')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(:nickname, 'Veg')) | ||||
|             post "/s/admin/plans.json", params: { nickname: 'Veg', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with a currency" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:currency, 'AUD')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(:currency, 'AUD')) | ||||
|             post "/s/admin/plans.json", params: { currency: 'AUD', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with an interval" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:interval, 'week')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: 'week' })) | ||||
|             post "/s/admin/plans.json", params: { interval: 'week', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with an amount" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:amount, '102')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(:unit_amount, '102')) | ||||
|             post "/s/admin/plans.json", params: { amount: '102', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with a trial period" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:trial_period_days, '14')) | ||||
|             post "/s/admin/plans.json", params: { trial_period_days: '14', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with a product" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(product: 'prod_walterwhite')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(product: 'prod_walterwhite')) | ||||
|             post "/s/admin/plans.json", params: { product: 'prod_walterwhite', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it "creates a plan with an active status" do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(:active, 'false')) | ||||
|             ::Stripe::Price.expects(:create).with(has_entry(:active, 'false')) | ||||
|             post "/s/admin/plans.json", params: { active: 'false', metadata: { group_name: '' } } | ||||
|           end | ||||
| 
 | ||||
|           it 'has a metadata' do | ||||
|             ::Stripe::Plan.expects(:create).with(has_entry(metadata: { group_name: 'discourse-user-group-name' })) | ||||
|             post "/s/admin/plans.json", params: { metadata: { group_name: 'discourse-user-group-name' } } | ||||
|           end | ||||
|           # TODO: Need to fix the metadata tests | ||||
|           # I think mocha has issues with the metadata fields here. | ||||
| 
 | ||||
|           #it 'has metadata' do | ||||
|           #  ::Stripe::Price.expects(:create).with(has_entry(:group_name, "discourse-user-group-name")) | ||||
|           #  post "/s/admin/plans.json", params: { amount: "100", metadata: { group_name: 'discourse-user-group-name' } } | ||||
|           #end | ||||
| 
 | ||||
|           #it "creates a plan with a trial period" do | ||||
|           #  ::Stripe::Price.expects(:create).with(has_entry(trial_period_days: '14')) | ||||
|           #  post "/s/admin/plans.json", params: { trial_period_days: '14' } | ||||
|           #end | ||||
|         end | ||||
| 
 | ||||
|         describe "update" do | ||||
|           it "updates a plan" do | ||||
|             ::Stripe::Plan.expects(:update) | ||||
|             patch "/s/admin/plans/plan_12345.json", params: { metadata: { group_name: 'discourse-user-group-name' } } | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         describe "delete" do | ||||
|           it "deletes a plan" do | ||||
|             ::Stripe::Plan.expects(:delete).with('plan_12345') | ||||
|             delete "/s/admin/plans/plan_12345.json" | ||||
|             ::Stripe::Price.expects(:update) | ||||
|             patch "/s/admin/plans/plan_12345.json", params: { trial_period_days: '14', metadata: { group_name: 'discourse-user-group-name' } } | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  |  | |||
|  | @ -12,30 +12,30 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|     describe "index" do | ||||
|       it "lists the active plans" do | ||||
|         ::Stripe::Plan.expects(:list).with(active: true) | ||||
|         ::Stripe::Price.expects(:list).with(active: true) | ||||
|         get "/s/plans.json" | ||||
|       end | ||||
| 
 | ||||
|       it "lists the active plans for a product" do | ||||
|         ::Stripe::Plan.expects(:list).with(active: true, product: 'prod_3765') | ||||
|         ::Stripe::Price.expects(:list).with(active: true, product: 'prod_3765') | ||||
|         get "/s/plans.json", params: { product_id: 'prod_3765' } | ||||
|       end | ||||
| 
 | ||||
|       it "orders and serialises the plans" do | ||||
|         ::Stripe::Plan.expects(:list).returns( | ||||
|         ::Stripe::Price.expects(:list).returns( | ||||
|           data: [ | ||||
|             { id: 'plan_id123', amount: 1220, currency: 'aud', interval: 'year', metadata: {} }, | ||||
|             { id: 'plan_id234', amount: 1399, currency: 'usd', interval: 'year', metadata: {} }, | ||||
|             { id: 'plan_id678', amount: 1000, currency: 'aud', interval: 'week', metadata: {} } | ||||
|             { id: 'plan_id123', unit_amount: 1220, currency: 'aud', recurring: { interval: 'year' }, metadata: {} }, | ||||
|             { id: 'plan_id234', unit_amount: 1399, currency: 'usd', recurring: { interval: 'year' }, metadata: {} }, | ||||
|             { id: 'plan_id678', unit_amount: 1000, currency: 'aud', recurring: { interval: 'week' }, metadata: {} } | ||||
|           ] | ||||
|         ) | ||||
| 
 | ||||
|         get "/s/plans.json" | ||||
| 
 | ||||
|         expect(response.parsed_body).to eq([ | ||||
|           { "amount" => 1000, "currency" => "aud", "id" => "plan_id678", "interval" => "week" }, | ||||
|           { "amount" => 1220, "currency" => "aud", "id" => "plan_id123", "interval" => "year" }, | ||||
|           { "amount" => 1399, "currency" => "usd", "id" => "plan_id234", "interval" => "year" } | ||||
|           { "currency" => "aud", "id" => "plan_id123", "recurring" => { "interval" => "year" }, "unit_amount" => 1220 }, | ||||
|           { "currency" => "usd", "id" => "plan_id234", "recurring" => { "interval" => "year" }, "unit_amount" => 1399 }, | ||||
|           { "currency" => "aud", "id" => "plan_id678", "recurring" => { "interval" => "week" }, "unit_amount" => 1000 } | ||||
|         ]) | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ module DiscourseSubscriptions | |||
|   RSpec.describe SubscriptionsController do | ||||
|     context "not authenticated" do | ||||
|       it "does not create a subscription" do | ||||
|         ::Stripe::Plan.expects(:retrieve).never | ||||
|         ::Stripe::Price.expects(:retrieve).never | ||||
|         ::Stripe::Subscription.expects(:create).never | ||||
|         post "/s/subscriptions.json", params: { plan: 'plan_1234', customer: 'cus_1234' } | ||||
|       end | ||||
|  | @ -21,15 +21,19 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|       describe "create" do | ||||
|         it "creates a subscription" do | ||||
|           ::Stripe::Plan.expects(:retrieve).returns( | ||||
|           ::Stripe::Price.expects(:retrieve).returns( | ||||
|             product: 'product_12345', | ||||
|             metadata: { group_name: 'awesome' } | ||||
|             metadata: { | ||||
|               group_name: 'awesome', | ||||
|               trial_period_days: 0 | ||||
|             } | ||||
|           ) | ||||
| 
 | ||||
|           ::Stripe::Subscription.expects(:create).with( | ||||
|             customer: 'cus_1234', | ||||
|             items: [ plan: 'plan_1234' ], | ||||
|             items: [ price: 'plan_1234' ], | ||||
|             metadata: { user_id: user.id, username: user.username_lower }, | ||||
|             trial_period_days: 0 | ||||
|           ).returns(status: 'active') | ||||
| 
 | ||||
|           expect { | ||||
|  | @ -38,7 +42,7 @@ module DiscourseSubscriptions | |||
|         end | ||||
| 
 | ||||
|         it "creates a customer model" do | ||||
|           ::Stripe::Plan.expects(:retrieve).returns(metadata: {}) | ||||
|           ::Stripe::Price.expects(:retrieve).returns(metadata: {}) | ||||
|           ::Stripe::Subscription.expects(:create).returns(status: 'active') | ||||
| 
 | ||||
|           expect { | ||||
|  | @ -57,13 +61,13 @@ module DiscourseSubscriptions | |||
|           end | ||||
| 
 | ||||
|           it "does not add the user to the admins group" do | ||||
|             ::Stripe::Plan.expects(:retrieve).returns(metadata: { group_name: 'admins' }) | ||||
|             ::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: 'admins' }) | ||||
|             post "/s/subscriptions.json", params: { plan: 'plan_1234', customer: 'cus_1234' } | ||||
|             expect(user.admin).to eq false | ||||
|           end | ||||
| 
 | ||||
|           it "does not add the user to other group" do | ||||
|             ::Stripe::Plan.expects(:retrieve).returns(metadata: { group_name: 'other' }) | ||||
|             ::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: 'other' }) | ||||
|             post "/s/subscriptions.json", params: { plan: 'plan_1234', customer: 'cus_1234' } | ||||
|             expect(user.groups).to be_empty | ||||
|           end | ||||
|  | @ -71,7 +75,7 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|         context "plan has group in metadata" do | ||||
|           before do | ||||
|             ::Stripe::Plan.expects(:retrieve).returns(metadata: { group_name: group_name }) | ||||
|             ::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: group_name }) | ||||
|           end | ||||
| 
 | ||||
|           it "does not add the user to the group when subscription fails" do | ||||
|  |  | |||
|  | @ -51,8 +51,8 @@ module DiscourseSubscriptions | |||
|               id: "cus_23456", | ||||
|               subscriptions: { | ||||
|                 data: [ | ||||
|                   { id: "sub_1234", plan: { id: "plan_1" } }, | ||||
|                   { id: "sub_4567", plan: { id: "plan_2" } } | ||||
|                   { id: "sub_1234", items: { data: [price: { id: "plan_1" }] } }, | ||||
|                   { id: "sub_4567", items: { data: [price: { id: "plan_2" }] } } | ||||
|                 ] | ||||
|               }, | ||||
|             }] | ||||
|  | @ -60,7 +60,7 @@ module DiscourseSubscriptions | |||
|         end | ||||
| 
 | ||||
|         it "gets subscriptions" do | ||||
|           ::Stripe::Plan.expects(:list).with( | ||||
|           ::Stripe::Price.expects(:list).with( | ||||
|             expand: ['data.product'], | ||||
|             limit: 100 | ||||
|           ).returns(plans) | ||||
|  | @ -76,7 +76,8 @@ module DiscourseSubscriptions | |||
| 
 | ||||
|           expect(subscription).to eq( | ||||
|             "id" => "sub_1234", | ||||
|             "plan" => { "id" => "plan_1" }, | ||||
|             "items" => { "data" => [{ "price" => { "id" => "plan_1" } }] }, | ||||
|             "plan" => { "id" => "plan_1", "product" => { "name" => "ACME Subscriptions" } }, | ||||
|             "product" => { "name" => "ACME Subscriptions" } | ||||
|           ) | ||||
|         end | ||||
|  |  | |||
|  | @ -24,8 +24,16 @@ componentTest("Discourse Subscriptions payment options has content", { | |||
| 
 | ||||
|   beforeEach() { | ||||
|     this.set("plans", [ | ||||
|       { currency: "aud", interval: "year", amountDollars: "44.99" }, | ||||
|       { currency: "gdp", interval: "month", amountDollars: "9.99" } | ||||
|       { | ||||
|         currency: "aud", | ||||
|         recurring: { interval: "year" }, | ||||
|         amountDollars: "44.99" | ||||
|       }, | ||||
|       { | ||||
|         currency: "gdp", | ||||
|         recurring: { interval: "month" }, | ||||
|         amountDollars: "9.99" | ||||
|       } | ||||
|     ]); | ||||
| 
 | ||||
|     this.set("planTypeIsSelected", true); | ||||
|  |  | |||
|  | @ -4,9 +4,11 @@ QUnit.module("discourse-patrons:model:plan"); | |||
| 
 | ||||
| QUnit.test("subscriptionRate", assert => { | ||||
|   const plan = Plan.create({ | ||||
|     amount: "2399", | ||||
|     unit_amount: "2399", | ||||
|     currency: "aud", | ||||
|     interval: "month" | ||||
|     recurring: { | ||||
|       interval: "month" | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   assert.equal( | ||||
|  | @ -17,7 +19,7 @@ QUnit.test("subscriptionRate", assert => { | |||
| }); | ||||
| 
 | ||||
| QUnit.test("amountDollars", assert => { | ||||
|   const plan = Plan.create({ amount: 2399 }); | ||||
|   const plan = Plan.create({ unit_amount: 2399 }); | ||||
| 
 | ||||
|   assert.equal( | ||||
|     plan.get("amountDollars"), | ||||
|  | @ -29,5 +31,5 @@ QUnit.test("amountDollars", assert => { | |||
| QUnit.test("amount", assert => { | ||||
|   const plan = Plan.create({ amountDollars: "22.12" }); | ||||
| 
 | ||||
|   assert.equal(plan.get("amount"), 2212, "it returns the cents amount"); | ||||
|   assert.equal(plan.get("unit_amount"), 2212, "it returns the cents amount"); | ||||
| }); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue