laravel / cashier-paddle

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

Allow reusing an existing customer through `PerformsCharges::subscribe()` #218

Closed supriyo-biswas closed 10 months ago

supriyo-biswas commented 11 months ago

At present, calling PerformsCharges::subscribe() calls ManagesCustomer::createAsCustomer() to create a new customer entry in the Paddle account and create a new customer entry in Paddle.

However, when the user already exists, the ManagesCustomer::createAsCustomer() method fails to create a customer with the same email address, throwing a PaddleException.

While this is an expected behavior from Paddle's end, this causes issues when there are multiple applications using the same Paddle account, or during development, when performing php artisan migrate:fresh followed by trying to register an already registered account triggers the condition.

Therefore, I would like a modification to the current behavior, where, should a user already exist on Paddle's end, Paddle simply fetches the customer's information by using the GetCustomer API and registers it in the customers table.

I can send in a PR for this feature, if interested.

driesvints commented 11 months ago

However, when the user already exists, the ManagesCustomer::createAsCustomer() method fails to create a customer with the same email address, throwing a PaddleException.

That's not possible. The method already checks if the billable has a customer attached here:

https://github.com/laravel/cashier-paddle/blob/163ef33e6080269b2af06aa2909a0dab8e1d4d8b/src/Concerns/ManagesCustomer.php#L17

So I don't see how it's possible Cashier attempts to create a customer twice for the same billable for you?

supriyo-biswas commented 11 months ago

Hello @driesvints,

I'm sorry I haven't explained properly. I meant to say this instead:

However, when the user already exists on Paddle's end but not in the database, the ManagesCustomer::createAsCustomer() method fails to create a customer with the same email address, throwing a PaddleException.

In other words, this is how it can happen:

  1. I have an existing Customer entity, linked to a billable User entity, with the email of user@example.com.
  2. Due to whatever reason, I run php artisan migrate:fresh. This recreates all the tables.
  3. I try to create the user with the same email address of user@example.com. Since there is no Customer entity attached to the user, $customer = $this->customer fails, and ManagesCustomer::createAsCustomer() proceeds with user creation.
  4. Since a user already exists, the Paddle API returns an error stating that said user already exists.

This can also happen if two separate applications using laravel/cashier-paddle are using the same Paddle account. One of them might not have a Customer entity linked, and therefore encounter the aforementioned error when it tries to create what it thinks is a new user, but it already exists on Paddle's end.

driesvints commented 10 months ago

I'm afraid this is impossible. It's not possible to use Cashier Paddle with existing Paddle accounts and customers, only new ones. This is because there's no way from Paddle's side to retrieve a customer by email address.

This can also happen if two separate applications using laravel/cashier-paddle are using the same Paddle account.

This also is impossible to do. You should never try to use two Laravel apps with the same Paddle account.

If there was a way from Paddle to retrieve customers by email address we could attempt to retrieve the customer before creating them and then sync them in through the createAsCustomer method.

driesvints commented 10 months ago

I've tried explaining it here: https://github.com/laravel/docs/pull/9189

driesvints commented 10 months ago

Wait, apparently it is possible to search for a customer by email: https://github.com/laravel/docs/pull/9189. I'll try to see what I can do here.

supriyo-biswas commented 10 months ago

Wait, apparently it is possible to search for a customer by email

There is no need to search the customer email by ID in this case, since the error message from Paddle itself returns the conflicting customer ID, and that can be passed on to the GetCustomer API, as I mentioned above.

This also is impossible to do. You should never try to use two Laravel apps with the same Paddle account.

The only issue that I see is the lack of separation of transactions would lead to notifications being sent through the webhook that are not relevant for one application. That discussion is for another issue though, and I could work around that by filtering the product IDs myself, in my own webhook handlers.

driesvints commented 10 months ago

Thanks. Continuing the discussion in https://github.com/laravel/cashier-paddle/issues/219

driesvints commented 10 months ago

I've sent in a fix for this: https://github.com/laravel/cashier-paddle/pull/220