Skip to content

Commit

Permalink
Merge branch 'paddle-billing-updates' of github.com:deanpcmad/pay int…
Browse files Browse the repository at this point in the history
…o paddle-billing-updates

* 'paddle-billing-updates' of github.com:deanpcmad/pay:
  Paddle Billing Docs (pay-rails#873)
  Update 1_installation.md with Stripe version 10 (pay-rails#880)
  Add Rails 7.1 to tests and remove Ruby 2.7 as it's EOL (pay-rails#878)
  Fix issue with Paddle Billing Charges when there's no payment details (pay-rails#872)
  Merge session_id into return_url for Stripe Checkout
  Stripe v10
  Update github actions to use main branch (pay-rails#871)
  • Loading branch information
deanpcmad committed Oct 21, 2023
2 parents 6480ca5 + 0c4e46b commit 47ed987
Show file tree
Hide file tree
Showing 29 changed files with 629 additions and 112 deletions.
23 changes: 7 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@ on:
- '*'
push:
branches:
- master
- main
jobs:
sqlite:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2']
ruby: ['3.0', '3.1', '3.2']
gemfile:
- rails_6_1
- rails_7
- rails_7_1
- rails_main
exclude:
# Rails 7.1 requires Ruby 3.0 or higher
- ruby: '2.7'
gemfile: rails_main

env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
Expand Down Expand Up @@ -51,15 +48,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2']
ruby: ['3.0', '3.1', '3.2']
gemfile:
- rails_6_1
- rails_7
- rails_7_1
- rails_main
exclude:
# Rails 7.1 requires Ruby 3.0 or higher
- ruby: '2.7'
gemfile: rails_main
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
BUNDLE_PATH_RELATIVE_TO_CWD: true
Expand Down Expand Up @@ -96,15 +90,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2']
ruby: ['3.0', '3.1', '3.2']
gemfile:
- rails_6_1
- rails_7
- rails_7_1
- rails_main
exclude:
# Rails 7.1 requires Ruby 3.0 or higher
- ruby: '2.7'
gemfile: rails_main
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
BUNDLE_PATH_RELATIVE_TO_CWD: true
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
.bundle/
log/*.log
pkg/
test/dummy/db/*.sqlite3
test/dummy/db/*.sqlite3-journal
test/dummy/db/*.sqlite3*
test/dummy/log/*.log
test/dummy/tmp/
test/dummy/public/packs/
Expand Down
4 changes: 4 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ appraise "rails-7" do
gem "rails", "~> 7.0.0"
end

appraise "rails-7-1" do
gem "rails", "~> 7.1.0"
end

appraise "rails-main" do
gem "rails", github: "rails/rails", branch: "main"
end
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ gem "vcr"
gem "webmock"

gem "braintree", ">= 2.92.0"
gem "stripe", "~> 9.0"
gem "stripe", "~> 10.0"
gem "paddle_pay", "~> 0.2"
gem "paddle", "~> 2.1", ">= 2.1.1"

Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ GEM
stimulus-rails (1.3.0)
railties (>= 6.0.0)
stringio (3.0.8)
stripe (9.4.0)
stripe (10.0.0)
thor (1.2.2)
timeout (0.4.0)
ttfunk (1.7.0)
Expand Down Expand Up @@ -343,11 +343,11 @@ DEPENDENCIES
sqlite3 (~> 1.6.0.rc2)
standard
stimulus-rails
stripe (~> 9.0)
stripe (~> 10.0)
turbo-rails
vcr
web-console
webmock

BUNDLED WITH
2.4.19
2.4.21
12 changes: 12 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

Follow this guide to upgrade older Pay versions. These may require database migrations and code changes.

## **Pay 6.0 to Unreleased**

This version adds support for Paddle's new Billing APIs and renames the existing Paddle implementation to Paddle Classic.

If you were using Paddle before, you'll need to update existing Paddle customers to `paddle_classic`.

```ruby
Pay::Customer.where(processor: :paddle).update_all(processor: :paddle_classic)
```

You'll also need to update the Webhook endpoint from `/pay/webhooks/paddle` to `/pay/webhooks/paddle_classic`

## **Pay 5.0 to 6.0**
This version adds support for accessing the start and end of the current billing period of a subscription. This currently only works with Stripe subscriptions.

Expand Down
5 changes: 4 additions & 1 deletion docs/1_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ Add these lines to your application's Gemfile:
gem "pay", "~> 6.0"

# To use Stripe, also include:
gem "stripe", "~> 9.0"
gem "stripe", "~> 10.0"

# To use Braintree + PayPal, also include:
gem "braintree", "~> 4.7"

# To use Paddle, also include:
gem "paddle", "~> 2.1"

# To use Paddle Classic, also include:
gem "paddle_pay", "~> 0.2"

# To use Receipts gem for creating invoice and receipt PDFs, also include:
Expand Down
9 changes: 9 additions & 0 deletions docs/2_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ braintree:
public_key: yyyy
merchant_id: aaaa
environment: sandbox
paddle:
seller_id: 1111
api_key: yyyy
signing_secret: pdl_ntfset...
environment: sandbox
paddle_classic:
vendor_id: xxxx
vendor_auth_code: yyyy
Expand Down Expand Up @@ -55,6 +60,10 @@ Pay will also check environment variables for API keys:
* `BRAINTREE_PUBLIC_KEY`
* `BRAINTREE_PRIVATE_KEY`
* `BRAINTREE_ENVIRONMENT`
* `PADDLE_SELLER_ID`
* `PADDLE_API_KEY`
* `PADDLE_SIGNING_SECRET`
* `PADDLE_ENVIRONMENT`
* `PADDLE_CLASSIC_VENDOR_ID`
* `PADDLE_CLASSIC_VENDOR_AUTH_CODE`
* `PADDLE_CLASSIC_PUBLIC_KEY`
Expand Down
5 changes: 3 additions & 2 deletions docs/3_customers.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Before you can process payments, you need to assign a payment processor for the
@user.set_payment_processor :stripe
@user.set_payment_processor :braintree
@user.set_payment_processor :paddle
@user.set_payment_processor :paddle_classic
@user.set_payment_processor :fake_processor, allow_fake: true
```

Expand Down Expand Up @@ -56,9 +57,9 @@ If you need to access the API object directly from the payment processor like th
#=> #<Stripe::Customer>
```

##### Paddle:
##### Paddle Classic:

It is currently not possible to retrieve a Customer object through the Paddle API.
It is currently not possible to retrieve a Customer object through the Paddle Classic API.

## Next

Expand Down
27 changes: 27 additions & 0 deletions docs/4_payment_methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ This will add the payment method via the API and mark it as the default for futu

##### Paddle

For updating payment method details on Paddle, a transaction ID is required. This can be generated by using

```ruby
subscription = @user.payment_processor.subscription(name: "plan name")
transaction = subscription.payment_method_transaction
```

Once you have a transaction ID, you can then pass that through to Paddle.js like so

```html
<a href="#"
class="paddle_button"
data-display-mode="overlay"
data-theme="light"
data-locale="en"
data-transaction-id="<%= transaction.id %>"
>
Update Payment Details
</a>
```

This will then open the Paddle overlay and allow the user to update their payment details.

For more information, [see the Paddle documentation](https://developer.paddle.com/build/subscriptions/update-payment-details)

##### Paddle Classic

Paddle uses an [Update Payment Details URL](https://developer.paddle.com/guides/how-tos/subscriptions/update-payment-details) for each customer which allows them to update the payment method. This is stored on the `Pay::Subscription` record for easy access.

```ruby
Expand Down
14 changes: 12 additions & 2 deletions docs/5_charges.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ You may pass optional arguments that will be directly passed on to the payment p

On failure, a `Pay::Error` will be raised with details about the payment failure.

##### Paddle Charges
##### Paddle Classic Charges

When creating charges with Paddle, they need to be approved by the customer. This is done by
passing the Paddle Transaction ID to a Paddle.js checkout.
Expand Down Expand Up @@ -97,13 +97,23 @@ The details saved will vary depending upon the payment method used.

## Receipt URL

Paddle and Stripe provide a receipt URL for each payment.
Paddle Classic and Stripe provide a receipt URL for each payment.

```ruby
@charge.paddle_receipt_url
@charge.stripe_receipt_url
```

## Paddle Receipts

Paddle Billing doesn't provide a receipt URL like Paddle Classic did.

In order to retrieve a PDF invoice for a transaction, an API request is required. This will return a URL to the PDF invoice. This URL is not permanent and will expire after a short period of time.

```ruby
Paddle::Transaction.invoice(id: @charge.processor_id)
```

## Next

See [Subscriptions](6_subscriptions.md)
2 changes: 1 addition & 1 deletion docs/6_subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ You can set this to another option as shown below.
@user.payment_processor.subscription.pause(behavior: "mark_uncollectible", resumes_at: 1.month.from_now)
```

##### Pause a Paddle Subscription
##### Pause a Paddle Classic Subscription

Paddle will pause payments at the end of the period. The status remains `active` until the period ends with a `paused_from` value to denote when the subscription pause will take effect. When the status becomes `paused` the subscription is no longer active.

Expand Down
4 changes: 3 additions & 1 deletion docs/7_webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ To configure webhooks on your payment processor, use the following URLs (with yo
* **Stripe** - `https://example.org/pay/webhooks/stripe`
* **Braintree** - `https://example.org/pay/webhooks/braintree`
* **Paddle** - `https://example.org/pay/webhooks/paddle`
* **Paddle Classic** - `https://example.org/pay/webhooks/paddle_classic`

#### Mount path

Expand Down Expand Up @@ -50,7 +51,8 @@ Since we support multiple payment providers, each event type is prefixed with th
```ruby
"stripe.charge.succeeded"
"braintree.subscription_charged_successfully"
"paddle.subscription_created"
"paddle.subscription.created"
"paddle_classic.subscription_created"
```

## Custom Webhook Listeners
Expand Down
71 changes: 40 additions & 31 deletions docs/paddle/1_overview.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,61 @@
# Using Pay with Paddle

Paddle works differently than most of the other payment processors so it comes with some limitations and differences.
Paddle Billing is Paddle's new subscription billing platform. It differs quite a bit
from Paddle Classic. This guide will help you get started with implementing it in your
Rails application.

* You cannot create a Customer from the API
* Checkout only happens via iFrame or hosted page
* Cancelling a subscription cannot be resumed
* Payment methods can only be updated while a subscription is active
* Paddle customers are not reused when a user re-subscribes

## Paddle Sandbox
## Creating Customers

The [Paddle Sandbox](https://developer.paddle.com/getting-started/sandbox) can be used for testing your Paddle integration.
Paddle now works similar to Stripe. You create a customer, which subscriptions belong to.

```html
<script src="https://cdn.paddle.com/paddle/paddle.js"></script>
<script type="text/javascript">
Paddle.Environment.set('sandbox');
Paddle.Setup({ vendor: <%= Pay::Paddle.vendor_id %> });
</script>
```ruby
# Set the payment processor
@user.set_payment_processor :paddle

# Create the customer on Paddle
@user.payment_processor.customer
```
## Paddle Public Key

Paddle uses public/private keys for webhook verification. You can find
your public key [here for Production](https://vendors.paddle.com/public-key)
and [here for Sandbox](https://sandbox-vendors.paddle.com/public-key).
## Prices & Plans

There are 3 ways that you can set the public key in Pay.
Paddle introduced Products & Prices to support more payment options. Previously,
they Products and Plans separated.

In either example, you can set the environment variable or in Rails credentials.
## Subscriptions

### File
Paddle subscriptions are not created through the API, but through Webhooks. When a
subscription is created, Paddle will send a webhook to your application. Pay will
automatically create the subscription for you.

You can download the public key from the link above and save it to a location which your Rails application
can access. Then set the `PADDLE_PUBLIC_KEY_FILE` to the location of the file.
## Configuration

### Key
### Paddle API Key

Set the `PADDLE_PUBLIC_KEY` environment variable with your public key. Replace any spaces with `\n` otherwise
you may get a `OpenSSL::PKey::RSAError` error.
You can generate an API key [here for Production](https://vendors.paddle.com/authentication)
or [here for Sandbox](https://sandbox-vendors.paddle.com/authentication)

### Base64 Encoded Key
### Paddle Environment

Or you can set a Base64 encoded version of the key. To do this, download a copy of your public key
then open a `rails console` and enter the following:
Paddle has two environments: Sandbox and Production. To use the Sandbox environment,
set the Environment value to `sandbox`. By default, this is set to `production`.

```ruby
paddle_public_key = OpenSSL::PKey::RSA.new(File.read("paddle.pem"))
Base64.encode64(paddle_public_key.to_der)
```
### Paddle Signing Secret

Paddle uses a signing secret to verify that webhooks are coming from Paddle. You can find
this after creating a webhook in the Paddle dashboard. You'll find this page
[here for Production](https://vendors.paddle.com/notifications) or
[here for Sandbox](https://sandbox-vendors.paddle.com/notifications).

### Environment Variables

Pay will automatically look for the following environment variables, or the equivalent
Rails credentials:

Copy what's displayed and set the `PADDLE_PUBLIC_KEY_BASE64` environment variable.
- `PADDLE_SELLER_ID`
- `PADDLE_ENVIRONMENT`
- `PADDLE_API_KEY`
- `PADDLE_SIGNING_SECRET`
Loading

0 comments on commit 47ed987

Please sign in to comment.