When using the Stripe Pricing Table for one-off purchases
(non-subscription) stripe doesn't automatically create a customer
record. This was causing the pricing table webhook
endpoint to end prematurely and not add users to their appropriate
group after purchase. Now if we detect that there is no customer record
we will make an api call to Stripe to create one.
To aid in debugging I'm adding a verbose logging site setting. I'm
adding this because I'm currently getting some errors in production that
I'm unable to replicate locally.
See: https://meta.discourse.org/t/323450/4
When using the Stripe Pricing table for one-off purchases
(non-subscriptions) the webhook was encountering an error because it was
expecting subscription information which does not exist for one-off
purchases. This fix addresses that issue ensuring that no errors occur,
that users are added to the appropriate group, and that uses can see
their purchase on the billing page.
Depending on the invoices in stripe there could be some nil values for
things so we need to account for those in this job or an exception will
be thrown causing the job to fail.
FEATURE: Site Setting to enable automatic tax
There is now a new site setting called
`discourse_subscriptions_enable_automatic_tax` that can be enabled if
you would like to automatically compute tax rates on all new
subscriptions.
Instead of deleting customers on cancel we will now update the
subscription status to canceled. This way we can have some visibility on
which users have canceled.
Likely there was an API change at some point now that we are using the
latest version of the stripe API. When the
`customer.subscription.updated` webhook is called we should also accept
the status of "active".
This commit adds an optional new stripe based pricing table.
If the user is logged in, the email field will be prepopulated with the users email.
The pricing table can be configured in the stripe dashboard.
Once the discourse_subscriptions_pricing_table setting is filled with the pricing table embed code from the stripe dashboard,
the pricing table will be displayed on /s/subscriptions
For more details see https://stripe.com/docs/payments/checkout/pricing-table
---------
Co-authored-by: spirobel <spirobel@protonmail.com>
- Adds the following fields to the subscription payment form:
- Cardholder Name
- Country
- Postal Code
- Address Line 1
- City
- State or Province
- Stripe recommends Cardholder Name & Country for verification; Cardholder Name, Country, and State/Province for US/Canada selections are required fields
- All fields are passed to Stripe for verification on submit
- Fields are also captured on the customer record in Stripe, under Billing Details
* add new route for card update
* create backend route
* update label
* basic functionality working
* ran rubocop
* added rspec tests for functionality
* make payment_method param compulsory
* fixed js linting
* improve client side error handling
* improve server side error handling
* improved update card page UI
* improve button UI for user subscriptions page
* give feedback to user about save status
* remove heading from last column
* fix padding on edit/delete buttons for update table
Co-authored-by: Blake Erickson <o.blakeerickson@gmail.com>
Duplicate payments were showing up in the discourse ui for users. Actual
transactions in stripe were not being duplicated. This fix ensures that
when parsing the api response we don't append any duplicates. Added a
duplicate entry to the specs to test for this.
I do think there can be some improvements made to this controller
endpoint, but I'd like to save those for a different and larger PR and
just get this fix out first.
* FIX: Include one-time purchases in campaign total
On the subscription banner that shows on the top of the forum it shows
the total amount raised toward a goal. But the amount shown was not
including one-time purchases. It was only showing subscriptions.
This change updates the sync with stripe logic so that it also includes
one-time purchases.
See: https://meta.discourse.org/t/-/209591
* rubocop: remove extra blank line
`.dig` isn't valid for stripe objects. This commit fixes this 500 error
you get when trying to edit a pricing plan:
```
NoMethodError (undefined method `dig' for #<Stripe::Price:0x....)
```
The interval field was missing in the Ember object since it was only available inside the nested object.
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Meta topic: https://meta.discourse.org/t/subscriptions-add-pagination-to-admin-subscriptions-view/172500
This adds support for pagination using our `{{load-more}}` component in core. Implementation on the backend was a bit tricky because we don't return all results from Stripe, only those that match local subscriptions stored in the `DiscourseSubscriptions::Subscription` model.
Feature requested here: https://meta.discourse.org/t/subscriptions-allow-users-to-purchase-one-time-products-multiple-times/173732/
There may be cases where a site admin wants to allow the repurchasing of a product. This implements the functionality by adding a repurchaseable toggle in the admin screen when creating a product. This saves an attribute to the Stripe product metadata.
When a user has already purchased an item with this toggle enabled, they will be able to purchase it again when browsing to `/s`.
Adds full support to create coupon/promo codes in the Admin > Plugins > Subscriptions section of the plugin. The Create Coupon button opens a form on the same page, and the active checkboxes toggle the active status of the coupon code.
This adds support for Stripe Promo Codes in the user checkout process.
Also adds a discounted field to User > Billing > Subscriptions to show the amount or percent discounted.
This does not currently add in support for creating promo codes in the Subscriptions interface (that will come at a later point in time). Instead a coupon can be created with a promo code right from the Stripe dashboard.
An implementation of refunds from the Admin dashboard. To refund, go to Plugins > Subscriptions > Subscriptions then click the `Cancel` button. You'll be presented with a modal. If you wish to refund only the most recent payment, check the box.
This only implements refunds for Subscriptions, not One Time Payments. One Time Payments will still need to be handled manually at this time.
Improves the subscription flow for anonymous users by making the routes available, and showing a login button. Clicking login from this page will save a `destination_url` cookie so that when logging in they're redirected back to the subscription page they were at.
The code in the plugin needed a dramatic cleanup. This refactor collapses the Plan/Product/Subscription controllers on the backend into one new controller: `SubscribeController`.
This reduces N+1 calls to the back end during the subscription process and simplifies use of the code.
I've also removed a bunch of dead code and refactored some logic into methods for easier readability. No feature/functionality changes in this commit; only refactoring. However, refactoring will allow for implementation of better anonymous user handling, so this is largely a foundation to enable making that change.
Previously, when a user canceled a subscription, the access would revoke
immediately on Discourse vs. at the end of the billing period. This
commit changes the behavior to remove membership at the end of the
billing period using Stripe's `cancel_at_period_end` attribute on the
Subscription object.
This commit now requires the setup of webhooks for subscription
processing to occur correctly.
Building off the foundation of using the Prices API, this PR adds the ability to create a one-time purchase plan for any product, which then can add a user to the specified plan group.
Some things to be aware of:
One-time purchases cannot have trials.
One-time purchases use the Invoice API instead of Subscriptions. Invoices are created then charged immediately.
Users should receive emails for these invoices directly from Stripe just like subscriptions.
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.