diff --git a/app/controllers/discourse_subscriptions/subscribe_controller.rb b/app/controllers/discourse_subscriptions/subscribe_controller.rb index 34a7467..6c3624e 100644 --- a/app/controllers/discourse_subscriptions/subscribe_controller.rb +++ b/app/controllers/discourse_subscriptions/subscribe_controller.rb @@ -65,8 +65,13 @@ module DiscourseSubscriptions begin customer = create_customer(params[:source]) plan = ::Stripe::Price.retrieve(params[:plan]) - promo_code = ::Stripe::PromotionCode.list({ code: params[:promo] }) if params[:promo].present? - promo_code = promo_code[:data][0] if promo_code && promo_code[:data] # we assume promo codes have a unique name + + if params[:promo].present? + promo_code = ::Stripe::PromotionCode.list({ code: params[:promo] }) + promo_code = promo_code[:data][0] # we assume promo codes have a unique name + + return render_json_error I18n.t("js.discourse_subscriptions.subscribe.invalid_coupon") if promo_code.blank? + end recurring_plan = plan[:type] == 'recurring' diff --git a/assets/javascripts/discourse/controllers/s-show.js.es6 b/assets/javascripts/discourse/controllers/s-show.js.es6 index 32cf5dc..45a91d5 100644 --- a/assets/javascripts/discourse/controllers/s-show.js.es6 +++ b/assets/javascripts/discourse/controllers/s-show.js.es6 @@ -121,7 +121,9 @@ export default Controller.extend({ } }) .catch((result) => { - bootbox.alert(result.errorThrown); + bootbox.alert( + result.jqXHR.responseJSON.errors[0] || result.errorThrown + ); this.set("loading", false); }); }, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0b23a45..a53eca3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -100,6 +100,7 @@ en: view_past: View past purchases no_products: There are currently no products available. unauthenticated: Log in or create an account to subscribe. + invalid_coupon: You entered an invalid coupon code. Please try again. card: title: Payment customer: diff --git a/spec/requests/subscribe_controller_spec.rb b/spec/requests/subscribe_controller_spec.rb index ffd23aa..b06b5a2 100644 --- a/spec/requests/subscribe_controller_spec.rb +++ b/spec/requests/subscribe_controller_spec.rb @@ -219,59 +219,87 @@ module DiscourseSubscriptions end context "with promo code" do - before do - ::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns( - data: [{ - id: 'promo123', - coupon: { id: 'c123' } - }] - ) + context "invalid code" do + it "prevents use of invalid coupon codes" do + ::Stripe::Price.expects(:retrieve).returns( + type: 'recurring', + product: 'product_12345', + metadata: { + group_name: 'awesome', + trial_period_days: 0 + } + ) + + ::Stripe::PromotionCode.expects(:list).with({ code: 'invalid' }).returns( + data: [] + ) + + post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: 'invalid' } + + data = response.parsed_body + expect(data["errors"]).not_to be_blank + end end - it "applies promo code to recurring subscription" do - ::Stripe::Price.expects(:retrieve).returns( - type: 'recurring', - product: 'product_12345', - metadata: { - group_name: 'awesome', - trial_period_days: 0 - } - ) + context "valid code" do + before do + ::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns( + data: [{ + id: 'promo123', + coupon: { id: 'c123' } + }] + ) + end - ::Stripe::Subscription.expects(:create).with( - customer: 'cus_1234', - items: [ price: 'plan_1234' ], - metadata: { user_id: user.id, username: user.username_lower }, - trial_period_days: 0, - promotion_code: 'promo123' - ).returns(status: 'active', customer: 'cus_1234') + it "applies promo code to recurring subscription" do + ::Stripe::Price.expects(:retrieve).returns( + type: 'recurring', + product: 'product_12345', + metadata: { + group_name: 'awesome', + trial_period_days: 0 + } + ) - post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' } + ::Stripe::Subscription.expects(:create).with( + customer: 'cus_1234', + items: [ price: 'plan_1234' ], + metadata: { user_id: user.id, username: user.username_lower }, + trial_period_days: 0, + promotion_code: 'promo123' + ).returns(status: 'active', customer: 'cus_1234') - end + expect { + post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' } + }.to change { DiscourseSubscriptions::Customer.count } - it "applies promo code to one time purchase" do - ::Stripe::Price.expects(:retrieve).returns( - type: 'one_time', - product: 'product_12345', - metadata: { - group_name: 'awesome' - } - ) + end - ::Stripe::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }]) + it "applies promo code to one time purchase" do + ::Stripe::Price.expects(:retrieve).returns( + type: 'one_time', + product: 'product_12345', + metadata: { + group_name: 'awesome' + } + ) - ::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123') + ::Stripe::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }]) - ::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123') + ::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123') - ::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123') + ::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123') - ::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful') + ::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123') - ::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234') + ::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful') - post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' } + ::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234') + + expect { + post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' } + }.to change { DiscourseSubscriptions::Customer.count } + end end end end