Comments (13)
Hi @Benoit1980.
$customer_subscription_id = $payloadData['data']['subscription_id'];
This seems incorrect? You're trying to lookup a customer record by a subscription ID? Shouldn't it be:
$customer_subscription_id = $payloadData['data']['customer_id'];
from cashier-paddle.
Thanks I will check on this tonight and post back.
from cashier-paddle.
Hi @driesvints,
I have done a lot of testing.
And added these loggers here:
\vendor\laravel\cashier-paddle\src\Http\Controllers\WebhookController.php
The issue lies in the fact that the query "$billable->transactions()->create" never executes when a customer subscribes and pays via Paddle billing in the live environment, although it functions as expected in the billing sandbox.
The log entries for Logger('1') and Logger('2') are successfully recorded. However, Logger('3') is never triggered during live Paddle transactions. Consequently, the transaction records are not created, leading to subsequent request failures.
protected function handleTransactionCompleted(array $payload)
{
$data = $payload['data'];
logger('1');
if ($this->transactionExists($data['id'])) {
return;
}
logger('2');
if (! $billable = $this->findBillable($data['customer_id'])) {
return;
}
logger('3');
$transaction = $billable->transactions()->create([
'paddle_id' => $data['id'],
'paddle_subscription_id' => $data['subscription_id'],
'invoice_number' => $data['invoice_number'],
'status' => $data['status'],
'total' => $data['details']['totals']['total'],
'tax' => $data['details']['totals']['tax'],
'currency' => $data['currency_code'],
'billed_at' => Carbon::parse($data['billed_at'], 'UTC'),
]);
logger('4');
TransactionCompleted::dispatch($billable, $transaction, $payload);
logger('5');
}
I checked the payload the customer_id is there:
This is the part I am not understanding:
if (! $billable = $this->findBillable($data['customer_id'])) {
return;
}
What could be causing this code to fail?
Users are registering for my app without undergoing any trials or making payments initially. Subsequently, they input their email addresses in the Paddle popup to pay for their first subscription. Is it possible that this workflow might be causing compatibility issues with your package?
This is how they are being subscribed at the checkout:
$user = Auth::user();
$user->subscribe('pri_01xxxxxxxxxxxxxxxxxxxxxxjh7x', 'default')
->returnTo(route('dashboard.thankyou'));
This issue has been difficult, it's preventing the launch of my app. I am surprised for the live environment to encounter failures after successful testing in the sandbox.
Thanks again
Ben
from cashier-paddle.
This shouldn't be possible. The subscribe
will either fetch the customer from paddle or create them in paddle before starting the subscription. The record is definitely in the customers table after that. So it should be fine for the webhook to find the record in the database.
Which email is being attempted to register? Can you compare the id of the customer you find in production with the ID of the customer in the payload from above? Is it the same or not?
from cashier-paddle.
Hi @driesvints ,
I wanted to test it tonight but the Hsbc AIS is down tonight. I will retest in the morning.
Sorry about that!
Best,
Ben
from cashier-paddle.
Hi @driesvints ,
Let me detail all the steps clearly so we know exactly what is happening:
SANBOX TEST
When clicking on the Paddle "BUY NOW" subscription button, a POST request is generated to:
The payload contains:
customer['id'] = **ctm_01hm6tjcbgbq0k4r6rhcmn8nvw**
The paddle response from the POST request is "ctm_01hm6tjcbgbq0k4r6rhcmn8nvw"
email: [email protected]
Upon paying with the fake bank card and clicking on the "SUBSCRIBE" button, 3 tables are filled with records:
-transactions table
-subscriptions table
-subscription_items table
The paddle transaction.completed event returns:
"customer_id": "**ctm_01hm6tjcbgbq0k4r6rhcmn8nvw**",
So for the sandbox, everything works as it should
#####################################################################################
Now let's see with the live bank card:
LIVE TEST
When clicking on the Paddle "BUY NOW" subscription button, a POST request is generated to:
The payload contains:
customer['id'] = **ctm_01hm6tjcbgbq0k4r6rhcmn8nvw**
No paddle response like with the sandbox showing the customer ctm_number, but I see this in the messages array of the data object(but the user exist in the Paddle billing back end, in the customers area "https://vendors.paddle.com/customers-v2"):
"messages": [
{
"status": 404,
"code": "not-found",
"details": "Customer cannot be found by id.",
"source": {
"pointer": "\/data\/customer\/id"
}
},
{
"status": 400,
"code": "validation",
"details": "The selected theme is invalid.",
"source": {
"pointer": "\/data\/settings\/theme"
}
}
]
Upon paying with the real bank card and clicking on the "SUBSCRIBE" button, the 3 tables are NOT filled with records:
Now here is the weird part:
The paddle transaction.completed event returns:
"customer_id": "ctm_01htxa5c4cp1ph75rxyqqwg4fq", Which is different from the original customer['id']
I'm quite surprised to see that the customer's ctm_number before paying is identical for both live and sandbox Paddle requests. Although I used the same email for both tests, I anticipated that the ctm_numbers would be different.
I did an extra test, and went in Paddle billing >> Customers >> Click on "[email protected]"
And can see:
ctm_01htxa5c4cp1ph75rxyqqwg4fq
Which matches the customer_id from the transaction.completed but does not match the originator customer['id'].
Thanks,
Ben
from cashier-paddle.
When clicking on the Paddle "BUY NOW" subscription button, a POST request is generated to:
The payload contains:
customer['id'] = ctm_01hm6tjcbgbq0k4r6rhcmn8nvw
I'm gonna just note that this is impossible. A sandbox and live environment can't produce the same ID's. There's something very odd going on with your live installation that you're getting sandbox ID's for customers.
I suggest you contact Paddle because this is not something we can help with sorry.
from cashier-paddle.
Ok @driesvints , I will speak to them now and see what is going on.
Thanks again for your help.
from cashier-paddle.
Alright, I've understood the issue now. Upon Paddle's notification about the wrong continued use of the SandBox ctm_id, I found that the records were indeed in the database. Initially, I presumed that the ctm_id was fetched by your packages via a single API call using the user's email address. However, it appears that it's saved in the database just before the initial order.
Please check the "customers" table:
When testing the website with an email such as [email protected], and subsequently attempting a real purchase with the same email/user, the ctm_id fails to update with the live ctm_number. This limitation is why I could get the sandbox to function but not the live mode.
I believe a possible solution to address this issue is to introduce an additional column named "paddle_sandbox_id." When the ENV PADDLE_SANDBOX is set to true, this ID would be utilized during the following sandbox process:
$user->checkout('pri_01hm7xxxxxxxxxxxxxxxxxxx')
->returnTo(route('dashboard.thankyou'));
This feature would allow users of the package to seamlessly transition from a sandbox to a live environment.
What I also tried:
Removing the initial "ctm" entry in the database seems to be problematic for Paddle.
Additionally, attempts to delete the customer from the customers table also resulted in another Paddle issue. This arises when attempting to recreate a new user, as the "name" field sometimes lacks records. When inserting a record for an existing user in the customers table, a name is required(as shown below).
Integrity constraint violation: 1048 Column 'name' cannot be null (Connection: mysql, SQL: insert into customers
(billable_id
, billable_type
, paddle_id
, name
, email
, trial_ends_at
, updated_at
, created_at
) values (429, App\Models\User, ctm_01htxa5c4cp1ph75rxyqqwg4fq, ?, [email protected], ?, 2024-04-11 16:12:32, 2024-04-11 16:12:32))
I hope this will help other users who may encounter the same issue.
Thanks,
Ben
from cashier-paddle.
Hello,
I think you need to test this package in a local environment and not in production because you may run into problems.
Don't you think so?)
The word "sandbox" speaks for itself
from cashier-paddle.
Hi Movicat,
Oftentimes, when encountering significant issues, it becomes necessary to place your site under maintenance and conduct a fake purchase as an admin on your actual live account. This scenario has occurred frequently in my experience with gateways, working with numerous clients. Particularly in urgent situations where time is of the essence, it's not always feasible to undergo the entire testing sandbox process on a secondary account. Additionally, not all accounts on a server are identical. While one account may have the necessary web socket permissions (e.g., Account A), another account (e.g., Account B) might have firewall restrictions or encounter issues with services like Cloudflare or mod_security. Due to these variations, I never assume that a sandbox account will only be utilized for local environments only. I've encountered such situations on multiple occasions where problems had to be fixed in less than 1 hour and lucky we had a paypal sandbox that could work on the spot.
Thank you,
Ben
from cashier-paddle.
@Benoit1980 you're using sandbox data in your production database. That can never work. You need to use a clean database in production.
from cashier-paddle.
I'm used to working with various technologies like PrestaShop and WordPress, where transitioning from a sandbox to a live account is seamless. However, I understand that this package isn't tailored for such transitions.
No worries, thanks again and enjoy your week end!
from cashier-paddle.
Related Issues (20)
- Fix incrementQuantity() & decrementQuantity() Throwing Error HOT 5
- Notice in the docs about "default checkout URL" HOT 1
- [2.x] add end at of the subscription period HOT 1
- Fix nextPayment() total HOT 1
- returnTo function added to checkout does not redirect HOT 6
- Bill for non-catalog items HOT 6
- Issues with subscriptions "price_id must be a string" HOT 4
- Webhook duplicating the response statuses HOT 8
- Cashier::findBillable($customerId) not returning anythying HOT 2
- Get subscription payment method HOT 1
- Add support for authentication via client-side tokens HOT 1
- Paddle webhook handler doesnt work HOT 10
- Laravel cashier-paddle package conflict with passport Auth Header HOT 1
- Paddle with Passport giving: Authentication header included, but incorrectly formatted HOT 3
- Pausing Subscriptions HOT 1
- Applying a discount on checkout HOT 1
- Changing email on the payment screen HOT 5
- Activate subscription is not working. HOT 10
- Integrity constraint violation: 1048 Column 'billable_id' cannot be null HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cashier-paddle.