nemiah / phpFinTS

PHP library to communicate with FinTS/HBCI servers
MIT License
130 stars 39 forks source link

GetStatement not working with decoupledTan for VR-Bank #407

Closed drssdnl closed 1 month ago

drssdnl commented 1 year ago

I've adapted the Browser.php Sample slightly to use in a Laravel Controller.

I added the getStatement logic from the statementOfAccount Sample.

It works just fine with Sparkasse, however I can't get it to work with VR-Bank. VR-Bank needs a tan for getStatement, I selected a decoupledTan.

At the point

if ($getStatement->needsTan()) { handleStrongAuthentication($getStatement); }

I get the following error at

if ($fints->getSelectedTanMode()->isDecoupled()) { handleDecoupled($action); } else { handleTan($action); }

in the

function handleStrongAuthentication(BaseAction $action): void

Error: "message": "Call to a member function getSelectedTanMode() on null"

I'm lost... Can someone please help me here?

lukas-staab commented 1 year ago

Can you give more info which object you wanted to call and was null unexpectedly?

Have you used the js parts of browser.php or are you doing php only? Have you used the persist string to re-init the FinTs class in the next request(s)? If you could give (excerpts of) your code it would make our lives probably easier.

drssdnl commented 1 year ago

I'm only using the PHP part of the browser.php where I added the getStatement and for now using Postman für the requests.

I store the FintTs Object in a database.

This is my getStatement Code:

`case 'getStatement': $getSepaAccounts = GetSEPAAccounts::create();

                if ($getSepaAccounts->needsTan()) {
                    handleStrongAuthentication($getSepaAccounts); // See login.php for the implementation.
                }

                try {
                    $fints->execute($getSepaAccounts);
                } catch (Exception $e) {
                    return response([
                        'result' => 'error', 'msg' => $e
                    ], Response::HTTP_OK);

                }

                $thisAccount = $getSepaAccounts->getAccounts()[0];

                $getStatement = GetStatementOfAccount::create($thisAccount);
                $fints->execute($getStatement);

                if ($getStatement->needsTan()) {

                    handleStrongAuthentication($getStatement);

                    $tanRequest = $getStatement->getTanRequest();

                    $persistedAction = serialize($getStatement);
                    $persistedFints = $fints->persist();

                    $sessionfile_fints = __DIR__ . "/session_files/permanent_state_$request->sessionid.data";
                    $sessionfile_persistedAction = __DIR__ . "/session_files/persistedAction_$request->sessionid.data";

                    file_put_contents($sessionfile_fints, serialize([$persistedFints]));
                    file_put_contents($sessionfile_persistedAction, serialize([$persistedAction]));

                    return ['result' => 'needsTan', 'challenge' => $tanRequest->getChallenge(), 'msg' => 'getStatement->needsTan'];
                }

                $soa = $getStatement->getStatement();
                $statementtext = '';
                foreach ($soa->getStatements() as $statement) {

                    {
                        $statementtext .= PHP_EOL;

                        $statementtext .= $statement->getDate()->format('Y-m-d') . ': Start Saldo: '
                            . ($statement->getCreditDebit() == Statement::CD_DEBIT ? '-' : '')
                            . $statement->getStartBalance() . PHP_EOL;
                        $statementtext .= 'Transactions:' . PHP_EOL;
                        $statementtext .= '=======================================' . PHP_EOL;

                        foreach ($statement->getTransactions() as $transaction) {

                            // BankStatement::create([
                                [...]
                            // ]);

                            $statementtext .= 'Amount      : ' . ($transaction->getCreditDebit() == Transaction::CD_DEBIT ? '-' : '') . floatval(str_replace(',', '.', $transaction->getAmount())) . PHP_EOL;
                            $statementtext .= 'Booking text: ' . $transaction->getBookingText() . PHP_EOL;
                            $statementtext .= 'Name        : ' . $transaction->getName() . PHP_EOL;
                            $statementtext .= 'Description : ' . $transaction->getMainDescription() . PHP_EOL;
                            $statementtext .= 'EREF        : ' . $transaction->getEndToEndID() . PHP_EOL;
                            $statementtext .= 'BookingDate        : ' . $transaction->getBookingDate()->format('Y-m-d_His') . PHP_EOL;
                            $statementtext .= 'ValutaDate        : ' . $transaction->getValutaDate()->format('Y-m-d_His') . PHP_EOL;

                        }
                    }
                }

                $statementfile = '/statements/statement_' . $thisAccount->getAccountNumber() . '_' . date('Ymd_His') . '_.txt';
                file_put_contents(__DIR__ . $statementfile, $statementtext);

                return ['result' => 'success', 'msg' => 'getStatement ok', 'txtFile' => $statementfile];`

In this step I get the error at handleStrongAuthentication($getStatement);:

`if ($getStatement->needsTan()) {

                    handleStrongAuthentication($getStatement);

                    $tanRequest = $getStatement->getTanRequest();

                    $persistedAction = serialize($getStatement);
                    $persistedFints = $fints->persist();

                    $sessionfile_fints = __DIR__ . "/session_files/permanent_state_$request->sessionid.data";
                    $sessionfile_persistedAction = __DIR__ . "/session_files/persistedAction_$request->sessionid.data";

                    file_put_contents($sessionfile_fints, serialize([$persistedFints]));
                    file_put_contents($sessionfile_persistedAction, serialize([$persistedAction]));

                    return ['result' => 'needsTan', 'challenge' => $tanRequest->getChallenge(), 'msg' => 'getStatement->needsTan'];
                }`

Precisely here when calling $fints->getSelectedTanMode()->isDecoupled() in the if-clause:

`function handleStrongAuthentication(BaseAction $action): void { global $fints;

        if ($fints->getSelectedTanMode()->isDecoupled()) {
            handleDecoupled($action);
        } else {
            handleTan($action);
        }
    } `

That's where I get this error:

"message": "Call to a member function getSelectedTanMode() on null", "exception": "Error", "trace": [ "function": "App\Http\Controllers\Banking\handleStrongAuthentication" "function": "App\Http\Controllers\Banking\handleRequest" ...

I hope this makes your life easer helping me :) and thanks for your effort!

drssdnl commented 1 year ago

I fixed this by adding the FinTS instance to function handleStrongAuthentication(BaseAction $action, FinTs $fints): void

drssdnl commented 1 year ago

Had to reopen, I'm a step closer, but I still don't get my getStatement to work properly.

This is my Response, more precise the error I get, when calling the getStatement-endpoint. I am using the getStatement Sample code which I call via Postman.

in the getStatement function I jump into handleStrongAuthentication and then into handleDecoupled($action, $fints) at this point:

` if ($getStatement->needsTan()) {

        $this->handleStrongAuthentication($getStatement, $fints);`

The request is still running and once I accept the Request on my phone this is the error response:

`Still waiting... Still waiting... Still waiting... Still waiting... Still waiting... Confirmed with UnexpectedResponseException: Fhp\Protocol\UnexpectedResponseException: Got neither 3956 nor HITAN with tanProzess=2 in /Users/U723761/Documents/9_Developement/vendor/nemiah/php-fints/lib/Fhp/FinTs.php:490 Stack trace:

0

/Users/U723761/Documents/9_Developement/app/Http/Controllers/Banking/BankingController.php(1022): Fhp\FinTs->checkDecoupledSubmission(Object(Fhp\Action\GetStatementOfAccount))

1

/Users/U723761/Documents/9_Developement/app/Http/Controllers/Banking/BankingController.php(959): App\Http\Controllers\Banking\BankingController->handleDecoupled(Object(Fhp\Action\GetStatementOfAccount), Object(Fhp\FinTs))

2

/Users/U723761/Documents/9_Developement/app/Http/Controllers/Banking/BankingController.php(749): App\Http\Controllers\Banking\BankingController->handleStrongAuthentication(Object(Fhp\Action\GetStatementOfAccount), Object(Fhp\FinTs))

3

/Users/U723761/Documents/9_Developement/app/Http/Controllers/Banking/BankingController.php(487): App\Http\Controllers\Banking\BankingController->getStatement(Object(Fhp\FinTs), 2)

4`

I did log the request and in the logs I actually find my statements - sort of. I can't really read them properly I can't save them.

The very same code works fine with Sparkasse.

All help is highly appreciated!

witschko commented 1 year ago

Hey everybody,

are there any news on this issue? I can reproduce this problem and have also posted some logs here: https://github.com/nemiah/phpFinTS/issues/374#issuecomment-1642160011

Any help or hints are very appreciated.

driessd commented 1 year ago

i solved it by commenting out the UnexpectedResponseException.

in the last if-clause in public function checkDecoupledSubmission(BaseAction $action) it now looks like this:

else {
            if ($outstanding === null) {
                $action->setTanRequest(null);
                // Process the response normally, and maybe keep going for more pages.
                $this->processActionResponse($action, $response->filterByReferenceSegments($action->getRequestSegmentNumbers()));

                if ($action instanceof PaginateableAction && $action->hasMorePages()) {
                    $this->execute($action);
                }
                return true;
                // throw new UnexpectedResponseException('Got neither 3956 nor HITAN with tanProzess=2');
            }
            $action->setTanRequest($hitanProcessS);
        }
Philipp91 commented 1 year ago

Then this sounds like a duplicate of #412.