diff --git a/app/controllers/discourse_subscriptions/subscribe_controller.rb b/app/controllers/discourse_subscriptions/subscribe_controller.rb
index 476d551..c5dd55f 100644
--- a/app/controllers/discourse_subscriptions/subscribe_controller.rb
+++ b/app/controllers/discourse_subscriptions/subscribe_controller.rb
@@ -53,24 +53,31 @@ 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
recurring_plan = plan[:type] == 'recurring'
if recurring_plan
trial_days = plan[:metadata][:trial_period_days] if plan[:metadata] && plan[:metadata][:trial_period_days]
+ promo_code_id = promo_code[:id] if promo_code
+
transaction = ::Stripe::Subscription.create(
customer: customer[:id],
items: [{ price: params[:plan] }],
metadata: metadata_user,
- trial_period_days: trial_days
+ trial_period_days: trial_days,
+ promotion_code: promo_code_id
)
payment_intent = retrieve_payment_intent(transaction[:latest_invoice]) if transaction[:status] == 'incomplete'
else
+ coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] && promo_code[:coupon][:id]
invoice_item = ::Stripe::InvoiceItem.create(
customer: customer[:id],
- price: params[:plan]
+ price: params[:plan],
+ discounts: [{ coupon: coupon_id }]
)
invoice = ::Stripe::Invoice.create(
customer: customer[:id]
diff --git a/assets/javascripts/discourse/controllers/s-show.js.es6 b/assets/javascripts/discourse/controllers/s-show.js.es6
index 7a999fe..c79bc0f 100644
--- a/assets/javascripts/discourse/controllers/s-show.js.es6
+++ b/assets/javascripts/discourse/controllers/s-show.js.es6
@@ -6,6 +6,7 @@ import { not } from "@ember/object/computed";
export default Controller.extend({
selectedPlan: null,
+ promoCode: null,
isAnonymous: not("currentUser"),
init() {
@@ -32,6 +33,7 @@ export default Controller.extend({
const subscription = Subscription.create({
source: result.token.id,
plan: plan.get("id"),
+ promo: this.promoCode,
});
return subscription.save();
diff --git a/assets/javascripts/discourse/models/subscription.js.es6 b/assets/javascripts/discourse/models/subscription.js.es6
index 893ba61..f78ec93 100644
--- a/assets/javascripts/discourse/models/subscription.js.es6
+++ b/assets/javascripts/discourse/models/subscription.js.es6
@@ -12,6 +12,7 @@ const Subscription = EmberObject.extend({
const data = {
source: this.source,
plan: this.plan,
+ promo: this.promo,
};
return ajax("/s/create", { method: "post", data });
diff --git a/assets/javascripts/discourse/models/user-subscription.js.es6 b/assets/javascripts/discourse/models/user-subscription.js.es6
index 15baf02..7709ae3 100644
--- a/assets/javascripts/discourse/models/user-subscription.js.es6
+++ b/assets/javascripts/discourse/models/user-subscription.js.es6
@@ -19,6 +19,22 @@ const UserSubscription = EmberObject.extend({
}
},
+ @discourseComputed("discount")
+ discounted(discount) {
+ if (discount) {
+ const amount_off = discount.coupon.amount_off;
+ const percent_off = discount.coupon.percent_off;
+
+ if (amount_off) {
+ return `${parseFloat(amount_off * 0.01).toFixed(2)}`;
+ } else if (percent_off) {
+ return `${percent_off}%`;
+ }
+ } else {
+ return I18n.t("no_value");
+ }
+ },
+
destroy() {
return ajax(`/s/user/subscriptions/${this.id}`, {
method: "delete",
diff --git a/assets/javascripts/discourse/templates/s/show.hbs b/assets/javascripts/discourse/templates/s/show.hbs
index 41ae5a1..3d24d5d 100644
--- a/assets/javascripts/discourse/templates/s/show.hbs
+++ b/assets/javascripts/discourse/templates/s/show.hbs
@@ -33,6 +33,9 @@
{{else if isAnonymous}}
{{login-required}}
{{else}}
+
+ {{input type="text" name="promo_code" placeholderKey="discourse_subscriptions.subscribe.promo_code" value=promoCode}}
+
{{d-button
disabled=loading
diff --git a/assets/javascripts/discourse/templates/user/billing/subscriptions.hbs b/assets/javascripts/discourse/templates/user/billing/subscriptions.hbs
index c0890e7..297d803 100644
--- a/assets/javascripts/discourse/templates/user/billing/subscriptions.hbs
+++ b/assets/javascripts/discourse/templates/user/billing/subscriptions.hbs
@@ -4,6 +4,7 @@
{{i18n 'discourse_subscriptions.user.subscriptions.id'}} |
{{i18n 'discourse_subscriptions.user.plans.product'}} |
{{i18n 'discourse_subscriptions.user.plans.rate'}} |
+ {{i18n 'discourse_subscriptions.user.subscriptions.discounted'}} |
{{i18n 'discourse_subscriptions.user.subscriptions.status'}} |
{{i18n 'discourse_subscriptions.user.subscriptions.renews'}} |
{{i18n 'discourse_subscriptions.user.subscriptions.created_at'}} |
@@ -14,6 +15,7 @@
{{subscription.id}} |
{{subscription.product.name}} |
{{subscription.plan.subscriptionRate}} |
+ {{subscription.discounted}} |
{{subscription.status}} |
{{subscription.endDate}} |
{{format-unix-date subscription.created}} |
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b712a78..2a7cfcb 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -53,6 +53,7 @@ en:
subscriptions:
id: Subscription ID
status: Status
+ discounted: Discounted
renews: Renews
created_at: Created
cancel: cancel
@@ -68,6 +69,7 @@ en:
title: Payment
customer:
title: Customer Details
+ promo_code: Coupon
buttons:
subscribe: Subscribe
purchased: Purchased
diff --git a/spec/requests/subscribe_controller_spec.rb b/spec/requests/subscribe_controller_spec.rb
index e137353..0ad4287 100644
--- a/spec/requests/subscribe_controller_spec.rb
+++ b/spec/requests/subscribe_controller_spec.rb
@@ -128,7 +128,8 @@ module DiscourseSubscriptions
customer: 'cus_1234',
items: [ price: 'plan_1234' ],
metadata: { user_id: user.id, username: user.username_lower },
- trial_period_days: 0
+ trial_period_days: 0,
+ promotion_code: nil
).returns(status: 'active', customer: 'cus_1234')
expect {
@@ -170,6 +171,63 @@ module DiscourseSubscriptions
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
+
+ context "with promo code" do
+ before do
+ ::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns(
+ data: [{
+ id: 'promo123',
+ coupon: { id: 'c123' }
+ }]
+ )
+ 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
+ }
+ )
+
+ ::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')
+
+ post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
+
+ end
+
+ 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::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }])
+
+ ::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123')
+
+ ::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
+
+ ::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
+
+ ::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
+
+ ::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
+
+ post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
+ end
+ end
end
describe "#finalize strong customer authenticated transaction" do