/* global Stripe */ import Controller from "@ember/controller"; import { not } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import discourseComputed from "discourse-common/utils/decorators"; import I18n from "I18n"; import Subscription from "discourse/plugins/discourse-subscriptions/discourse/models/subscription"; import Transaction from "discourse/plugins/discourse-subscriptions/discourse/models/transaction"; export default Controller.extend({ dialog: service(), router: service(), selectedPlan: null, promoCode: null, cardholderName: null, cardholderAddress: { line1: null, city: null, state: null, country: null, postalCode: null, }, isAnonymous: not("currentUser"), isCountryUS: false, isCountryCA: false, init() { this._super(...arguments); this.set( "stripe", Stripe(this.siteSettings.discourse_subscriptions_public_key) ); const elements = this.get("stripe").elements(); this.set("cardElement", elements.create("card", { hidePostalCode: true })); this.set("isCountryUS", this.cardholderAddress.country === "US"); this.set("isCountryCA", this.cardholderAddress.country === "CA"); }, alert(path) { this.dialog.alert(I18n.t(`discourse_subscriptions.${path}`)); }, @discourseComputed("model.product.repurchaseable", "model.product.subscribed") canPurchase(repurchaseable, subscribed) { if (!repurchaseable && subscribed) { return false; } return true; }, createSubscription(plan) { return this.stripe .createToken(this.get("cardElement"), { name: this.cardholderName, // Recommended by Stripe address_line1: this.cardholderAddress.line1 ?? "", address_city: this.cardholderAddress.city ?? "", address_state: this.cardholderAddress.state ?? "", address_zip: this.cardholderAddress.postalCode ?? "", address_country: this.cardholderAddress.country, // Recommended by Stripe }) .then((result) => { if (result.error) { this.set("loading", false); return result; } else { const subscription = Subscription.create({ source: result.token.id, plan: plan.get("id"), promo: this.promoCode, cardholderName: this.cardholderName, cardholderAddress: this.cardholderAddress, }); return subscription.save(); } }); }, handleAuthentication(plan, transaction) { return this.stripe .confirmCardPayment(transaction.payment_intent.client_secret) .then((result) => { if ( result.paymentIntent && result.paymentIntent.status === "succeeded" ) { return result; } else { this.set("loading", false); this.dialog.alert(result.error.message || result.error); return result; } }); }, _advanceSuccessfulTransaction(plan) { this.alert("plans.success"); this.set("loading", false); this.router.transitionTo( plan.type === "recurring" ? "user.billing.subscriptions" : "user.billing.payments", this.currentUser.username.toLowerCase() ); }, actions: { changeCountry(country) { this.set("cardholderAddress.country", country); this.set("isCountryUS", country === "US"); this.set("isCountryCA", country === "CA"); }, changeState(stateOrProvince) { this.set("cardholderAddress.state", stateOrProvince); }, stripePaymentHandler() { this.set("loading", true); const plan = this.get("model.plans") .filterBy("id", this.selectedPlan) .get("firstObject"); const cardholderAddress = this.cardholderAddress; const cardholderName = this.cardholderName; if (!plan) { this.alert("plans.validate.payment_options.required"); this.set("loading", false); return; } if (!cardholderName) { this.alert("subscribe.invalid_cardholder_name"); this.set("loading", false); return; } if (!cardholderAddress.country) { this.alert("subscribe.invalid_cardholder_country"); this.set("loading", false); return; } if (cardholderAddress.country === "US" && !cardholderAddress.state) { this.alert("subscribe.invalid_cardholder_state"); this.set("loading", false); return; } if (cardholderAddress.country === "CA" && !cardholderAddress.state) { this.alert("subscribe.invalid_cardholder_province"); this.set("loading", false); return; } let transaction = this.createSubscription(plan); transaction .then((result) => { if (result.error) { this.dialog.alert(result.error.message || result.error); } else if ( result.status === "incomplete" || result.status === "open" ) { const transactionId = result.id; const planId = this.selectedPlan; this.handleAuthentication(plan, result).then( (authenticationResult) => { if (authenticationResult && !authenticationResult.error) { return Transaction.finalize(transactionId, planId).then( () => { this._advanceSuccessfulTransaction(plan); } ); } } ); } else { this._advanceSuccessfulTransaction(plan); } }) .catch((result) => { this.dialog.alert( result.jqXHR.responseJSON.errors[0] || result.errorThrown ); this.set("loading", false); }); }, }, });