laravel / cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.
https://laravel.com/docs/cashier-paddle
MIT License
238 stars 57 forks source link

Bill for non-catalog items #263

Closed AcTiv3MineD closed 2 months ago

AcTiv3MineD commented 3 months ago

This PR covers the functionality needed on this issue: https://github.com/laravel/cashier-paddle/issues/230

NEW PR DESCRIPTION

Product Checkout

// Charges 10.00
$user->charge(1000, 'T-shirt');

Specify quantity

// Charges 30.00 (10 * 3)
$user->charge(1000, 'T-shirt', ['quantity' => 3]);

Product subscription

// Charges 30.00 (10 * 3 seats) each year
$user->newSubscription(1000, 'Gym subscription')
    ->yearly()
    ->quantity(3) // Seats
    ->checkout();

The default currency is USD, to change it, you can either: 1 - Set CASHIER_CURRENCY=currency on your .env 2 - Pass currency as an option, ex:

// Charges 50.00 (10 * 5)
$user->charge(1000, 'T-shirt', ['price' => ['unit_price' => ['currency_code' => 'EUR']], 'quantity' => 5]);

OLD PR DESCRIPTION

Notes:

1- Right now, only the option of calling the create transaction api is supported, adding the new structure of items as a attribute on the html does not work. I have contacted Paddle's team and they say that they don't have a date set for this functionality.

This has a drawback, as: A- Every time we render the button, it creates an incomplete transaction on Paddle. B- Each time we call the button component, an api request is made to paddle, thus, it would slow the rendering time.

2-This solution allows to use the exiting cashier functionality, plus create custom transactions, allowing to create custom pricing subscriptions and checkout, ex:

<?php

Route::get('/buy', function (Request $request) {
    $checkout = $request->user()->checkoutFromTransaction([
               'items' => [
                    [
                        'price' => [
                            'description' => 'New custom product price',
                            'name' => 'My custom price',
                            'unit_price' => [
                                'amount' => '1099',
                                'currency_code' => 'USD',
                            ],
                            'product' => [
                                'name' => 'Custom product',
                                'tax_category' => 'standard',
                                'description' => 'Start the game with 20 extra seconds play time!',
                            ],
                        ],
                        'quantity' => 1,
                    ],
                ],
        ])
        ->returnTo(route('dashboard'));

    return view('buy', ['checkout' => $checkout]);
})->name('checkout');
github-actions[bot] commented 3 months ago

Thanks for submitting a PR!

Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

driesvints commented 2 months ago

Thanks @AcTiv3MineD. Drafting this until I get a chance to review.

driesvints commented 2 months ago

@AcTiv3MineD finally found some time. I adjusted the API a little bit. Now you can do like in previous Cashier Paddle v1:

$user->charge(1000, 'T-shirt', ['quantity' => 5]);

I didn't test this and will need your help verifying this will work.

AcTiv3MineD commented 2 months ago

@driesvints Thanks for the changes, I like the new structure, I will be testing it during the week.

I have 2 comments about the new changes:

1 - About the charge name, I think it might create confusion with the existing method on src/Subscription.php. Would you agree to find a different name?

2 - These changes remove the option of creating subscriptions for non-catalog items. Looking at the code there is a workaround by using chargeMany which gives complete control over the array structure, allowing to specify billing_cycle key on the item's price.

Should we add a method called nonCatalogSubscription() to allow for subscriptions?

Let me know if it is a good idea, or maybe the subscription part should be addressed in a different PR as we would need more testing for compatibility for swap, pause, cancel, etc.. or maybe document that some subscription operations might not be compatible with standard subscription model.

driesvints commented 2 months ago

@AcTiv3MineD

  1. No I think this is fine. It's the same as in Cashier Paddle v1 and in Cashier Stripe.
  2. I re-added this with a brand new API. Here's an example:
$user->newSubscription(1000, 'Gym subscription')
    ->yearly()
    ->quantity(3) // Seats
    ->checkout();

Could you try this all out and let me know if it works?

AcTiv3MineD commented 2 months ago

@driesvints Did some minor fixes.

1 - Price description is required and must be filled 2 - Transaction was missing the ['data'] key on the button

I have tested locally both subscription and one-off. It works as expected.

driesvints commented 2 months ago

Thanks @AcTiv3MineD. I've further refined this and made the API a bit more simpler. Description is now optional again. Here's your updated description:

Product Checkout

// Charges 10.00
$user->charge(1000, 'T-shirt', ['quantity' => 5]);

Product subscription

// Charges 10.00 each year
$user->newSubscription(1000, 'Gym subscription')
    ->yearly()
    ->quantity(3) // Seats
    ->checkout();

The default currency is USD, to change it, you can either:

1 - Set CASHIER_CURRENCY=currency on your .env 2 - Pass currency as an option, ex:

// Charges 10.00
$user->charge(1000, 'T-shirt', ['price' => ['unit_price' => ['currency_code' => 'EUR']]], quantity' => 5]);
driesvints commented 2 months ago

I tested this and it works fine. Let me know if you have any further thoughts @AcTiv3MineD.

AcTiv3MineD commented 2 months ago

@driesvints Just tested on my side, looks good to me 👍

driesvints commented 2 months ago

Released now. Thanks a bunch for your help @AcTiv3MineD. If you're up for it, we'd also appreciate a PR to the docs!

AcTiv3MineD commented 2 months ago

Sure!, I can work on that @driesvints

AcTiv3MineD commented 2 months ago

The documentation is ready for review: https://github.com/laravel/docs/pull/9749

@driesvints