Skip to content

Commit 10e3721

Browse files
authored
Merge pull request #513 from Philipp91/vop
Support for Verification of Payee with APIs in FinTs
2 parents fec22a6 + a1b3f9d commit 10e3721

15 files changed

+1071
-30
lines changed

lib/Fhp/BaseAction.php

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44

55
namespace Fhp;
66

7+
use Fhp\Model\PollingInfo;
78
use Fhp\Model\TanRequest;
9+
use Fhp\Model\VopConfirmationRequest;
810
use Fhp\Protocol\ActionIncompleteException;
11+
use Fhp\Protocol\ActionPendingException;
912
use Fhp\Protocol\BPD;
1013
use Fhp\Protocol\Message;
1114
use Fhp\Protocol\TanRequiredException;
1215
use Fhp\Protocol\UnexpectedResponseException;
1316
use Fhp\Protocol\UPD;
17+
use Fhp\Protocol\VopConfirmationRequiredException;
1418
use Fhp\Segment\BaseSegment;
1519
use Fhp\Segment\HIRMS\Rueckmeldung;
1620
use Fhp\Segment\HIRMS\Rueckmeldungscode;
@@ -48,6 +52,12 @@ abstract class BaseAction implements \Serializable
4852
/** If set, the last response from the server regarding this action asked for a TAN from the user. */
4953
protected ?TanRequest $tanRequest = null;
5054

55+
/** If set, this action is currently waiting for a long-running operation on the server to complete. */
56+
protected ?PollingInfo $pollingInfo = null;
57+
58+
/** If set, this action needs the user's confirmation to be completed. */
59+
protected ?VopConfirmationRequest $vopConfirmationRequest = null;
60+
5161
protected bool $isDone = false;
5262

5363
/**
@@ -61,8 +71,7 @@ abstract class BaseAction implements \Serializable
6171
*
6272
* NOTE: A common mistake is to call this function directly. Instead, you probably want `serialize($instance)`.
6373
*
64-
* An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
65-
* present yet.
74+
* An action can only be serialized before it was completed.
6675
* If a sub-class overrides this, it should call the parent function and include it in its result.
6776
* @return string The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
6877
*/
@@ -72,22 +81,23 @@ public function serialize(): string
7281
}
7382

7483
/**
75-
* An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
76-
* present yet.
84+
* An action can only be serialized before it was completed.
7785
* If a sub-class overrides this, it should call the parent function and include it in its result.
7886
*
7987
* @return array The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
8088
* Note that this is not necessarily valid UTF-8, so you should store it as a BLOB column or raw bytes.
8189
*/
8290
public function __serialize(): array
8391
{
84-
if (!$this->needsTan()) {
85-
throw new \RuntimeException('Cannot serialize this action, because it is not waiting for a TAN.');
92+
if ($this->isDone()) {
93+
throw new \RuntimeException('Completed actions cannot be serialized.');
8694
}
8795
return [
8896
$this->requestSegmentNumbers,
8997
$this->tanRequest,
9098
$this->needTanForSegment,
99+
$this->pollingInfo,
100+
$this->vopConfirmationRequest,
91101
];
92102
}
93103

@@ -108,7 +118,9 @@ public function __unserialize(array $serialized): void
108118
$this->requestSegmentNumbers,
109119
$this->tanRequest,
110120
$this->needTanForSegment,
111-
) = $serialized;
121+
$this->pollingInfo,
122+
$this->vopConfirmationRequest,
123+
) = array_pad($serialized, 5, null);
112124
}
113125

114126
/**
@@ -140,25 +152,54 @@ public function getTanRequest(): ?TanRequest
140152
return $this->tanRequest;
141153
}
142154

155+
public function needsPollingWait(): bool
156+
{
157+
return !$this->isDone() && $this->pollingInfo !== null;
158+
}
159+
160+
public function getPollingInfo(): ?PollingInfo
161+
{
162+
return $this->pollingInfo;
163+
}
164+
165+
public function needsVopConfirmation(): bool
166+
{
167+
return !$this->isDone() && $this->vopConfirmationRequest !== null;
168+
}
169+
170+
public function getVopConfirmationRequest(): ?VopConfirmationRequest
171+
{
172+
return $this->vopConfirmationRequest;
173+
}
174+
143175
/**
144176
* Throws an exception unless this action has been successfully executed, i.e. in the following cases:
145177
* - the action has not been {@link FinTs::execute()}-d at all or the {@link FinTs::execute()} call for it threw an
146178
* exception,
147-
* - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()}.
179+
* - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()},
180+
* - the action is pending a long-running operation on the bank server ({@link BaseAction::needsPollingWait()}),
181+
* - the action is awaiting the user's confirmation of the Verification of Payee result (as per
182+
* {@link BaseAction::needsVopConfirmation()}).
148183
*
149184
* After executing an action, you can use this function to make sure that it succeeded. This is especially useful
150185
* for actions that don't have any results (as each result getter would call {@link ensureDone()} internally).
151186
* On the other hand, you do not need to call this function if you make sure that (1) you called
152-
* {@link FinTs::execute()} and (2) you checked {@link needsTan()} and, if it returned true, supplied a TAN by
153-
* calling {@ink FinTs::submitTan()}. Note that both exception types thrown from this method are sub-classes of
154-
* {@link \RuntimeException}, so you shouldn't need a try-catch block at the call site for this.
187+
* {@link FinTs::execute()} and (2) you checked and resolved all other special outcome states documented there.
188+
* Note that both exception types thrown from this method are sub-classes of {@link \RuntimeException}, so you
189+
* shouldn't need a try-catch block at the call site for this.
155190
* @throws ActionIncompleteException If the action hasn't even been executed.
191+
* @throws ActionPendingException If the action is pending a long-running server operation that needs polling.
192+
* @throws VopConfirmationRequiredException If the action requires the user's confirmation for VOP.
156193
* @throws TanRequiredException If the action needs a TAN.
157194
*/
158-
public function ensureDone()
195+
public function ensureDone(): void
159196
{
160197
if ($this->tanRequest !== null) {
161198
throw new TanRequiredException($this->tanRequest);
199+
} elseif ($this->pollingInfo !== null) {
200+
throw new ActionPendingException($this->pollingInfo);
201+
} elseif ($this->vopConfirmationRequest !== null) {
202+
throw new VopConfirmationRequiredException($this->vopConfirmationRequest);
162203
} elseif (!$this->isDone()) {
163204
throw new ActionIncompleteException();
164205
}
@@ -249,4 +290,16 @@ final public function setTanRequest(?TanRequest $tanRequest): void
249290
{
250291
$this->tanRequest = $tanRequest;
251292
}
293+
294+
/** To be called only by the FinTs instance that executes this action. */
295+
final public function setPollingInfo(?PollingInfo $pollingInfo): void
296+
{
297+
$this->pollingInfo = $pollingInfo;
298+
}
299+
300+
/** To be called only by the FinTs instance that executes this action. */
301+
final public function setVopConfirmationRequest(?VopConfirmationRequest $vopConfirmationRequest): void
302+
{
303+
$this->vopConfirmationRequest = $vopConfirmationRequest;
304+
}
252305
}

0 commit comments

Comments
 (0)