mollie / mollie-api-php

Mollie API client for PHP
http://www.mollie.com
BSD 2-Clause "Simplified" License
552 stars 191 forks source link

Non-existent query parameter "testmode" for this API call #437

Closed bobbybouwmann closed 1 year ago

bobbybouwmann commented 4 years ago

Specifications

Describe the issue

I'm trying to revoke an existing mandate using the revoke method on the mandate resource I get back from the API. According to the documentation, the testmode parameter should be send along: https://docs.mollie.com/reference/v2/mandates-api/revoke-mandate#parameters

However, I get the following error back

"Error executing API call (422: Unprocessable Entity): Non-existent query parameter "testmode" for this API call.. Field: testmode. Documentation: https://docs.mollie.com/guides/handling-errors"

My code looks like this.

$mandates = $this->mollieApiClient->mandates->listForId($customerId, null, null, [
    'testmode' => $this->testmode,
]);

foreach ($mandates as $mandate) {
    $mandate->revoke();
}

Fetching the mandates works as expected. As you can see I call the invoke method on the Mandate resource. This method looks like this:

public function revoke()
{
    if (!isset($this->_links->self->href)) {
        return $this;
    }

    $body = null;
    if($this->client->L()) {
        $body = json_encode([
            "testmode" => $this->mode === "test" ? true : false
        ]);
    }

    $result = $this->client->performHttpCallToFullUrl(
        MollieApiClient::HTTP_DELETE,
        $this->_links->self->href,
        $body
    );

    return $result;
}

Should all be good, but I still get above mentioned error.

Any clues of what's going on?

sandervanhooft commented 4 years ago

Can you dump the mandate contents here?

sandervanhooft commented 4 years ago

Right now my best guess is the testmode parameter should not be set on the request body (bug in revoke method). Also, it should already be included on the self link in the mandate response.

bobbybouwmann commented 4 years ago

So the problem is that this is a DELETE route. Because of that, we need to post the testmode in the body. Like you said, the ?testmode=true is appended to the URL, which is not allowed according to the error message for this endpoint.

Right now we have a URL that looks like this

https://api.mollie.com/v2/customers/cst_R9r23aF7Ku/mandates/mdt_Av5nsfq23G?testmode=true

And then with the revoke method, we DELETE the resource also appending the testmode stuff.

So now, we need to strip the testmode=true from the URL ourselves. I can't imagine that we are the only one doing this and that there are no tests for this 🤔

Possible solutions are accepting the testmode in the URL or the library should strip of this testmode=true for this specific endpoint.

sandervanhooft commented 4 years ago

@willemstuursma can you weigh in on this?

bobbybouwmann commented 4 years ago

@sandervanhooft Thanks for the quick reply! Really appreciated

crnkovic commented 4 years ago

Same thing with the update method on the Payment resource.

I want to update a description of the payment, but the following code fails with the exact same error:

$payment = $this->client->payments->get('some-payment-id', [
    'testmode' => true,
]);

// payment is found...

$payment->description = 'updated description';
$payment->update(); // this fails...
sandervanhooft commented 4 years ago

Mollie is investigating it on their end.

sandervanhooft commented 4 years ago

Possible solutions are accepting the testmode in the URL or the library should strip of this testmode=true for this specific endpoint.

Discussed it with @willemstuursma , primary part of the solution will be Mollie accepting testmode on these urls.

sandervanhooft commented 4 years ago

Looking into it, writing a whole new set of integration tests for this.

@bobbybouwmann consider using this for now (confirmed to work):

$customer->revokeMandate($mandate->id);
bobbybouwmann commented 4 years ago

@sandervanhooft Awesome! Thanks for all the work you put into this!

sandervanhooft commented 4 years ago

Integration tested all(!) endpoints with OAuth (Organization Access Token) today. 😅

The goal was to find out what calls are breaking with OAuth, or could do without having to pass in the testmode setting manually.

Working on a PR here: #443 .

The client still breaks using some endpoints in test mode because the _links.self includes the test mode query parameter. These are:

sandervanhooft commented 4 years ago

☝️ @willemstuursma I'll release the PR tomorrow. Let me know if you need my help on the above.

sandervanhooft commented 4 years ago

Additionally, Order Line PATCH will require some API changes as well:

ronaldtb commented 3 years ago

I see that the PR has already been merged, but the same problem seems to occur when calling cancel on a subscription that was created with testmode set to true.

$subscription = $mollie->subscriptions->getForId($mollieCustomerId, $mollieSubscriptionId, ['testmode' => $mollieSettings->isTestMode()]);
$cancelledSubscription = $subscription->cancel();

The code above also results in an Error executing API call (422: Unprocessable Entity): Non-existent query parameter "testmode" for this API call.. Field: testmode. exception.

boryn commented 3 years ago

When operating in the testmode using OAuth, remember to setAccessToken() before issuing other commands.

Loots-it commented 3 years ago

Error executing API call (422: Unprocessable Entity): The payment cannot be cancelled. Documentation: https://docs.mollie.com/guides/handling-errors

I get this error when I try to delete a payment (a payment that is cancelable):

        if ($payment && $payment->isCancelable)
        {
            $api->payments->cancel($paymentId, ['testmode' => !runningAppInProduction()]);
        }

The weird thing is, the payment is actually cancelled, so there shouldn't be any exception.

I'm using v2.31.1

sandervanhooft commented 3 years ago

@Loots-it that's a different topic.

Please open a separate ticket in this repository or contact Mollie support with a description of the issue, your account id, profile id and the payment id being used.