|
2 | 2 |
|
3 | 3 | namespace Fhp\Action; |
4 | 4 |
|
| 5 | +use Fhp\CAMT\CAMT; |
5 | 6 | use Fhp\Model\SEPAAccount; |
6 | 7 | use Fhp\Model\StatementOfAccount\StatementOfAccount; |
7 | 8 | use Fhp\MT940\Dialect\PostbankMT940; |
@@ -47,6 +48,10 @@ class GetStatementOfAccount extends PaginateableAction |
47 | 48 | /** @var string */ |
48 | 49 | private $bankName; |
49 | 50 |
|
| 51 | + // Internal action for XML fallback |
| 52 | + /** @var GetStatementOfAccountXML|null */ |
| 53 | + private $xmlAction; |
| 54 | + |
50 | 55 | // Response |
51 | 56 | /** @var string */ |
52 | 57 | private $rawMT940 = ''; |
@@ -151,29 +156,47 @@ protected function createRequest(BPD $bpd, ?UPD $upd) |
151 | 156 | { |
152 | 157 | $this->bankName = $bpd->getBankName(); |
153 | 158 |
|
154 | | - /** @var HIKAZS $hikazs */ |
155 | | - $hikazs = $bpd->requireLatestSupportedParameters('HIKAZS'); |
156 | | - if ($this->allAccounts && !$hikazs->getParameter()->getAlleKontenErlaubt()) { |
157 | | - throw new \InvalidArgumentException('The bank do not permit the use of allAccounts=true'); |
158 | | - } |
159 | | - switch ($hikazs->getVersion()) { |
160 | | - case 4: |
161 | | - return HKKAZv4::create(Kto::fromAccount($this->account), $this->from, $this->to); |
162 | | - case 5: |
163 | | - return HKKAZv5::create(KtvV3::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
164 | | - case 6: |
165 | | - return HKKAZv6::create(KtvV3::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
166 | | - case 7: |
167 | | - return HKKAZv7::create(Kti::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
168 | | - default: |
169 | | - throw new UnsupportedException('Unsupported HKKAZ version: ' . $hikazs->getVersion()); |
| 159 | + // Try to use MT940 format (HIKAZS) if supported |
| 160 | + try { |
| 161 | + /** @var HIKAZS $hikazs */ |
| 162 | + $hikazs = $bpd->requireLatestSupportedParameters('HIKAZS'); |
| 163 | + if ($this->allAccounts && !$hikazs->getParameter()->getAlleKontenErlaubt()) { |
| 164 | + throw new \InvalidArgumentException('The bank do not permit the use of allAccounts=true'); |
| 165 | + } |
| 166 | + switch ($hikazs->getVersion()) { |
| 167 | + case 4: |
| 168 | + return HKKAZv4::create(Kto::fromAccount($this->account), $this->from, $this->to); |
| 169 | + case 5: |
| 170 | + return HKKAZv5::create(KtvV3::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
| 171 | + case 6: |
| 172 | + return HKKAZv6::create(KtvV3::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
| 173 | + case 7: |
| 174 | + return HKKAZv7::create(Kti::fromAccount($this->account), $this->allAccounts, $this->from, $this->to); |
| 175 | + default: |
| 176 | + throw new UnsupportedException('Unsupported HKKAZ version: ' . $hikazs->getVersion()); |
| 177 | + } |
| 178 | + } catch (UnexpectedResponseException | UnsupportedException $e) { |
| 179 | + // MT940 format not supported, fall back to XML format (HICAZS) |
| 180 | + $this->xmlAction = GetStatementOfAccountXML::create($this->account, $this->from, $this->to, null, $this->allAccounts); |
| 181 | + return $this->xmlAction->createRequest($bpd, $upd); |
170 | 182 | } |
171 | 183 | } |
172 | 184 |
|
173 | 185 | public function processResponse(Message $response) |
174 | 186 | { |
175 | 187 | parent::processResponse($response); |
176 | 188 |
|
| 189 | + // If we're using XML fallback, delegate to the XML action |
| 190 | + if ($this->xmlAction !== null) { |
| 191 | + $this->xmlAction->processResponse($response); |
| 192 | + |
| 193 | + // Parse XML and convert to StatementOfAccount once all pages are received |
| 194 | + if (!$this->hasMorePages()) { |
| 195 | + $this->parseXml(); |
| 196 | + } |
| 197 | + return; |
| 198 | + } |
| 199 | + |
177 | 200 | // Banks send just 3010 and no HIKAZ in case there are no transactions. |
178 | 201 | $isUnavailable = $response->findRueckmeldung(Rueckmeldungscode::NICHT_VERFUEGBAR) !== null; |
179 | 202 | $responseHikaz = $response->findSegments(HIKAZ::class); |
@@ -218,4 +241,26 @@ private function parseMt940() |
218 | 241 | throw new \InvalidArgumentException('Invalid MT940 data', 0, $e); |
219 | 242 | } |
220 | 243 | } |
| 244 | + |
| 245 | + private function parseXml() |
| 246 | + { |
| 247 | + if ($this->xmlAction === null) { |
| 248 | + throw new \RuntimeException('XML action not initialized'); |
| 249 | + } |
| 250 | + |
| 251 | + $xmlStrings = $this->xmlAction->getBookedXML(); |
| 252 | + if (empty($xmlStrings)) { |
| 253 | + // No transactions available |
| 254 | + $this->statement = new StatementOfAccount(); |
| 255 | + return; |
| 256 | + } |
| 257 | + |
| 258 | + try { |
| 259 | + $parser = new CAMT(); |
| 260 | + $parsedCAMT = $parser->parse($xmlStrings); |
| 261 | + $this->statement = StatementOfAccount::fromCAMTArray($parsedCAMT); |
| 262 | + } catch (\Exception $e) { |
| 263 | + throw new \InvalidArgumentException('Invalid CAMT XML data', 0, $e); |
| 264 | + } |
| 265 | + } |
221 | 266 | } |
0 commit comments