Conversation
|
@nemiah PR ist ready für's Review |
|
It probably won't break something and doesn't look too verbose for me. I'll merge it if your human takes responsibility |
Have you considered augmenting what |
|
Good point, agreed. Exposing the whole I'll rework this PR along those lines: One subtlety: HKSPA is TAN-gated at some banks, so the UPD has to survive the action's serialization round trip while the application waits for the TAN. I'll serialize it with the action (backwards compatible with previously serialized actions) and cover that with a test. If someone later needs the permitted business transactions per account, they can be added the same way as a plain list of segment names. @nemiah please hold the merge until the rework is pushed. |
4179307 to
9b1040d
Compare
|
Reworked as discussed (force-pushed, single commit):
Description updated accordingly. @Philipp91 does that match what you had in mind? |
| * | ||
| * @return string|null The joined account holder name, or null if the segment carries none. | ||
| */ | ||
| public static function accountHolderName(HIUPD $hiupd): ?string |
There was a problem hiding this comment.
Should this be a member function of HIUPD instead?
There was a problem hiding this comment.
Yes, that's the better home for it. It's now HIUPD::getAccountHolderName(), implemented once in AccountHolderNameTrait for v4 and v6 (the way FindRueckmeldungTrait implements RueckmeldungContainer). UPD::accountHolderName() is gone, both actions call it on the segment, and HIUPDTest covers both versions. (300ae4e)
| * Copies the descriptive fields of the account's HIUPD segment, if the bank sent one. HISPA and HIUPD describe the | ||
| * same accounts, but only the latter carries names, currency and type. | ||
| */ | ||
| private function annotateFromUpd(SEPAAccount $account): void |
There was a problem hiding this comment.
Any reason this is a separate function and not just if ($hiupd = $this->upd?->findHiupd($account)) { ... } in the function above?
There was a problem hiding this comment.
No good reason – inlined as you suggested. (300ae4e)
| return new GetSEPAAccounts(); | ||
| } | ||
|
|
||
| /** |
There was a problem hiding this comment.
Just thinking out loud, another solution would be to pass BPD and ?UPD to processResponse() as well. Then we wouldn't need this whole serialization business here, we'd always get the freshest data and the serialized action would be smaller. It would mean that all action implementations would need to have their signature updated and most of them would then receive an argument they never use. But that seems fine (it's not like ?UPD especially is used in all createRequest() implementations either).
There was a problem hiding this comment.
I looked into it, and I think it would lose the data in exactly the case the serialization is there for. persist(true) is documented for completing an outstanding TAN and leaves out BPD and UPD. After FinTs::new(..., $minimalPersist), submitTan()/checkDecoupledSubmission() still work (the resolved TanMode is persisted, and buildMessage() doesn't need the BPD), but $this->bpd and $this->upd are null when processActionResponse() runs, and neither can be fetched again while the dialog is open: the UPD only arrives with the dialog initialization, and ensureBpdAvailable() throws Cannot init another dialog. So a TAN-gated HKSPA would come back unannotated for applications that use the minimal persist. As far as I can tell, that's also why GetStatementOfAccount captures $bankName from the BPD in createRequest() and serializes it, rather than reading the BPD later.
Changing BaseAction::processResponse() would also break applications that subclass an action and override processResponse(Message $response) – PHP refuses to load an override with fewer parameters than the parent.
So I kept the copy and put the reason into the comment on $upd (300ae4e). Size-wise, the serialized UPD of the banks recorded in Tests/Unit/Integration ranges from 0.6 KB (ING) to 3.3 KB (GLS).
…pe from the UPD Applications need the per-account information from the HIUPD segments to label the accounts that GetSEPAAccounts returns (nemiah#467, nemiah#573). Instead of exposing the UPD itself, GetSEPAAccounts keeps the UPD it receives in createRequest() and copies the descriptive fields of the matching HIUPD onto each SEPAAccount in processResponse(): holder name (name1 + name2), product name, currency and account type, mirroring the fields CreditCardAccount got in nemiah#574. The name join moves to UPD::accountHolderName() so both actions share it. Some banks require a TAN for HKSPA and applications serialize the action while waiting for it, so the UPD is serialized with the action. Actions serialized by earlier versions (PaginateableAction state only) still unserialize.
…eviewed - HIUPD::getAccountHolderName() replaces the static UPD::accountHolderName(); a trait implements it once for HIUPDv4 and HIUPDv6, the way FindRueckmeldungTrait does for RueckmeldungContainer. - GetSEPAAccounts annotates the accounts inline instead of in a separate method, and the comment on the kept UPD names the reason: the FinTs instance completing a TAN may come from persist(true), which has no UPD. - GetSEPAAccountsTest uses ActionTestCase (nemiah#591) and unserializes a blob recorded with dd2a7f2 instead of building one by hand; HIUPDTest covers the name join for v4 and v6.
9b1040d to
300ae4e
Compare
|
Addressed in 300ae4e (rebased onto master first, so the test can use
@Philipp91 ready for another look. |
Problem
Applications need the per-account information from the HIUPD segments — holder name, product name, currency, account type — to label the accounts that
GetSEPAAccountsreturns (see #467, #573).FinTs::$updis private, so the only way was reflection:Both of our applications do exactly that in production.
Change
Following the review discussion below, the UPD stays internal. Instead,
GetSEPAAccountskeeps the UPD it receives increateRequest()and, inprocessResponse(), copies the descriptive fields of the matching HIUPD (UPD::findHiupd()) onto eachSEPAAccount:These are the same fields
CreditCardAccountgot in #574, so both account kinds read alike; the name join isHIUPD::getAccountHolderName()(implemented once for v4 and v6) and used by both actions. Accounts without a matching HIUPD keepnullin these fields, and aSEPAAccountan application constructs itself is unaffected.Some banks require a TAN for HKSPA and applications serialize the action while waiting for it. The
FinTsinstance that completes the TAN may have been restored frompersist(true), which leaves out BPD and UPD and cannot fetch them again while the dialog is open, so the action keeps its own copy of the UPD and serializes it (__serialize()/__unserialize()). Actions serialized by earlier versions (PaginateableAction state only) still unserialize.Tests
Tests/Unit/Integration/DKB/GetSEPAAccountsTest.php: the recorded DKB dialog now also asserts name, product name, currency and type from the login response's HIUPD.Tests/Unit/Action/GetSEPAAccountsTest.php(onActionTestCasefrom Keep the XML fallback of GetStatementOfAccount across serialization (#553) #591): annotation via IBAN and via Kontonummer (HIUPD without IBAN), accounts without HIUPD, no UPD at all, UPD surviving the serialization round trip, and unserialization of a blob recorded with dd2a7f2.Tests/Unit/Segment/HIUPDTest.php:getAccountHolderName()for v4 (single name field) and v6 (both fields).Note on authorship
Developed with AI assistance (Cursor) and reviewed by the submitting human; the vouching statement per #586 will be added by the author once the review is complete.