Coder Social home page Coder Social logo

Comments (13)

driesvints avatar driesvints commented on July 28, 2024

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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

Thanks I will check on this tonight and post back.

from cashier-paddle.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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:
image

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.

driesvints avatar driesvints commented on July 28, 2024

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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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]"
image

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.

driesvints avatar driesvints commented on July 28, 2024

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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

Ok @driesvints , I will speak to them now and see what is going on.

Thanks again for your help.

from cashier-paddle.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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:
image

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.

movicat avatar movicat commented on July 28, 2024

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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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.

driesvints avatar driesvints commented on July 28, 2024

@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.

Benoit1980 avatar Benoit1980 commented on July 28, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.