Passed
Pull Request — master (#97)
by
unknown
06:38
created

FinTs::setDialogProductInformation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 4
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 2
1
<?php
2
3
namespace Fhp;
4
5
use Fhp\Adapter\AdapterInterface;
6
use Fhp\Adapter\Curl;
7
use Fhp\DataTypes\Kik;
8
use Fhp\DataTypes\Kti;
9
use Fhp\DataTypes\Ktv;
10
use Fhp\Dialog\Dialog;
11
use Fhp\Message\AbstractMessage;
12
use Fhp\Message\Message;
13
use Fhp\Model\SEPAAccount;
14
use Fhp\Response\GetAccounts;
15
use Fhp\Response\GetSaldo;
16
use Fhp\Response\GetSEPAAccounts;
17
use Fhp\Response\GetStatementOfAccount;
18
use Fhp\Segment\HKKAZ;
19
use Fhp\Segment\HKSAL;
20
use Fhp\Segment\HKSPA;
21
use Fhp\Segment\HKVVB;
22
use Psr\Log\LoggerInterface;
23
use Psr\Log\NullLogger;
24
25
/**
26
 * Class FinTs.
27
 *
28
 * @package Fhp
29
 */
30
class FinTs
31
{
32
    const DEFAULT_COUNTRY_CODE = 280;
33
34
    /** @var LoggerInterface */
35
    protected $logger;
36
    /** @var  string */
37
    protected $server;
38
    /** @var int */
39
    protected $port;
40
    /** @var string */
41
    protected $bankCode;
42
    /** @var string */
43
    protected $username;
44
    /** @var string */
45
    protected $pin;
46
    /** @var  Connection */
47
    protected $connection;
48
    /** @var  AdapterInterface */
49
    protected $adapter;
50
    /** @var int */
51
    protected $systemId = 0;
52
    /** @var string */
53
    protected $bankName;
54
    /** @var string  */
55
    protected $dialogProductName = HKVVB::DEFAULT_PRODUCT_NAME;
56
    /** @var string  */
57
    protected $dialogProductVersion = HKVVB::DEFAULT_PRODUCT_VERSION;
58
59
    /**
60
     * FinTs constructor.
61
     * @param string $server
62
     * @param int $port
63
     * @param string $bankCode
64
     * @param string $username
65
     * @param string $pin
66
     * @param LoggerInterface|null $logger
67
     */
68
    public function __construct(
69
        $server,
70
        $port,
71
        $bankCode,
72
        $username,
73
        $pin,
74
        LoggerInterface $logger = null
75
    ) {
76
        $this->server = $server;
77
        $this->port = $port;
78
        $this->logger = null == $logger ? new NullLogger() : $logger;
79
80
        // escaping of bank code not really needed here as it should
81
        // never have special chars. But we just do it to ensure
82
        // that the request will not get messed up and the user
83
        // can receive a valid error response from the HBCI server.
84
        $this->bankCode = $this->escapeString($bankCode);
85
86
        // Here, escaping is needed for usernames or pins with
87
        // HBCI special chars.
88
        $this->username = $this->escapeString($username);
89
        $this->pin = $this->escapeString($pin);
90
91
        $this->adapter = new Curl($this->server, $this->port);
92
        $this->connection = new Connection($this->adapter);
93
    }
94
95
    /**
96
     * Sets the adapter to use.
97
     *
98
     * @param AdapterInterface $adapter
99
     */
100
    public function setAdapter(AdapterInterface $adapter)
101
    {
102
        $this->adapter = $adapter;
103
        $this->connection = new Connection($this->adapter);
104
    }
105
106
    /**
107
     * Sets the product information, used in Dialog/HKVVB
108
     *
109
     * @param $name
110
     * @param $version
111
     */
112
    public function setDialogProductInformation($name, $version) {
113
114
        $this->dialogProductName = $name;
115
        $this->dialogProductVersion = $version;
116
    }
117
118
    /**
119
     * Gets array of all accounts.
120
     *
121
     * @return Model\Account[]
122
     */
123
    public function getAccounts()
124
    {
125
        $dialog = $this->getDialog();
126
        $result = $dialog->syncDialog($this->dialogProductName, $this->dialogProductVersion);
127
        $this->bankName = $dialog->getBankName();
128
        $accounts = new GetAccounts($result);
129
130
        return $accounts->getAccountsArray();
131
    }
132
133
    /**
134
     * Gets array of all SEPA Accounts.
135
     *
136
     * @return Model\SEPAAccount[]
137
     * @throws Adapter\Exception\AdapterException
138
     * @throws Adapter\Exception\CurlException
139
     */
140
    public function getSEPAAccounts()
141
    {
142
        $dialog = $this->getDialog();
143
        $dialog->syncDialog($this->dialogProductName, $this->dialogProductVersion);
144
        $dialog->initDialog($this->dialogProductName, $this->dialogProductVersion);
145
146
        $message = $this->getNewMessage(
147
            $dialog,
148
            array(new HKSPA(3)),
149
            array(AbstractMessage::OPT_PINTAN_MECH => $dialog->getSupportedPinTanMechanisms())
150
        );
151
152
        $result = $dialog->sendMessage($message);
153
        $dialog->endDialog();
154
        $sepaAccounts = new  GetSEPAAccounts($result->rawResponse);
155
156
        return $sepaAccounts->getSEPAAccountsArray();
157
    }
158
159
    /**
160
     * Gets the bank name.
161
     *
162
     * @return string
163
     */
164
    public function getBankName()
165
    {
166
        if (null == $this->bankName) {
167
            $this->getDialog()->syncDialog($this->dialogProductName, $this->dialogProductVersion);
168
        }
169
170
        return $this->bankName;
171
    }
172
173
    /**
174
     * Gets statement of account.
175
     *
176
     * @param SEPAAccount $account
177
     * @param \DateTime $from
178
     * @param \DateTime $to
179
     * @return Model\StatementOfAccount\StatementOfAccount|null
180
     * @throws \Exception
181
     */
182
    public function getStatementOfAccount(SEPAAccount $account, \DateTime $from, \DateTime $to)
183
    {
184
        $responses = array();
185
186
        $this->logger->info('Start fetching statement of account results');
187
        $this->logger->info('Start date: ' . $from->format('Y-m-d'));
188
        $this->logger->info('End date  : ' . $to->format('Y-m-d'));
189
190
        $dialog = $this->getDialog();
191
        $dialog->syncDialog($this->dialogProductName, $this->dialogProductVersion);
192
        $dialog->initDialog($this->dialogProductName, $this->dialogProductVersion);
193
194
        $message = $this->createStateOfAccountMessage($dialog, $account, $from, $to, null);
195
        $response = $dialog->sendMessage($message);
196
        $touchdowns = $response->getTouchdowns($message);
197
        $soaResponse = new GetStatementOfAccount($response->rawResponse);
198
        $responses[] = $soaResponse->getRawMt940();
199
200
        $touchdownCounter = 1;
201
        while (isset($touchdowns[HKKAZ::NAME])) {
202
            $this->logger->info('Fetching more statement of account results (' . $touchdownCounter++ . ') ...');
203
            $message = $this->createStateOfAccountMessage(
204
                $dialog,
205
                $account,
206
                $from,
207
                $to,
208
                $touchdowns[HKKAZ::NAME]
209
            );
210
211
            $r = $dialog->sendMessage($message);
212
            $touchdowns = $r->getTouchDowns($message);
213
            $soaResponse = new GetStatementOfAccount($r->rawResponse);
214
            $responses[] = $soaResponse->getRawMt940();
215
        }
216
217
        $this->logger->info('Fetching of ' . $touchdownCounter . ' pages done.');
218
        $this->logger->debug('HKKAZ response:');
219
220
        $dialog->endDialog();
221
222
        return GetStatementOfAccount::createModelFromRawMt940(implode('', $responses));
223
    }
224
225
    /**
226
     * Helper method to create a "Statement of Account Message".
227
     *
228
     * @param Dialog $dialog
229
     * @param SEPAAccount $account
230
     * @param \DateTime $from
231
     * @param \DateTime $to
232
     * @param string|null $touchdown
233
     * @return Message
234
     * @throws \Exception
235
     */
236
    protected function createStateOfAccountMessage(
237
        Dialog $dialog,
238
        SepaAccount $account,
239
        \DateTime $from,
240
        \DateTime $to,
241
        $touchdown = null
242
    ) {
243
        // version 4, 5, 6, 7
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
244
245
        // version 5
246
        /*
247
            1 Segmentkopf                   DEG         M 1
248
            2 Kontoverbindung Auftraggeber  DEG ktv #   M 1
249
            3 Alle Konten                   DE  jn  #   M 1
250
            4 Von Datum                     DE dat  #   K 1
251
            5 Bis Datum                     DE dat  #   K 1
252
            6 Maximale Anzahl Einträge      DE num ..4  K 1 >0
253
            7 Aufsetzpunkt                  DE an ..35  K 1
254
         */
255
256
        // version 6
257
        /*
258
            1 Segmentkopf                   1 DEG           M 1
259
            2 Kontoverbindung Auftraggeber  2 DEG ktv #     M 1
260
            3 Alle Konten                   1 DE jn #       M 1
261
            4 Von Datum                     1 DE dat #      O 1
262
            5 Bis Datum                     1 DE dat #      O 1
263
            6 Maximale Anzahl Einträge      1 DE num ..4    C 1 >0
264
            7 Aufsetzpunkt                  1 DE an ..35    C 1
265
         */
266
267
        // version 7
268
        /*
269
            1 Segmentkopf                   1 DEG       M 1
270
            2 Kontoverbindung international 1 DEG kti # M 1
271
            3 Alle Konten                   1 DE jn #   M 1
272
            4 Von Datum                     1 DE dat #  O 1
273
            5 Bis Datum                     1 DE dat #  O 1
274
            6 Maximale Anzahl Einträge      1 DE num ..4 C 1 >0
275
            7 Aufsetzpunkt                  1 DE an ..35 C 1
276
         */
277
278
        switch ($dialog->getHkkazMaxVersion()) {
279
            case 4:
280
            case 5:
281
                $konto = new Deg();
282
                $konto->addDataElement($account->getAccountNumber());
283
                $konto->addDataElement($account->getSubAccount());
284
                $konto->addDataElement(static::DEFAULT_COUNTRY_CODE);
285
                $konto->addDataElement($account->getBlz());
286
                break;
287 View Code Duplication
            case 6:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
288
                $konto = new Ktv(
289
                    $account->getAccountNumber(),
290
                    $account->getSubAccount(),
291
                    new Kik(280, $account->getBlz())
292
                );
293
                break;
294 View Code Duplication
            case 7:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
                $konto = new Kti(
296
                    $account->getIban(),
297
                    $account->getBic(),
298
                    $account->getAccountNumber(),
299
                    $account->getSubAccount(),
300
                    new Kik(280, $account->getBlz())
301
                );
302
                break;
303
            default:
304
                throw new \Exception('Unsupported HKKAZ version: ' . $dialog->getHkkazMaxVersion());
305
        }
306
307
        $message = $this->getNewMessage(
308
            $dialog,
309
            array(
310
                new HKKAZ(
311
                    $dialog->getHkkazMaxVersion(),
312
                    3,
313
                    $konto,
314
                    HKKAZ::ALL_ACCOUNTS_N,
315
                    $from,
316
                    $to,
317
                    $touchdown
318
                )
319
            ),
320
            array(AbstractMessage::OPT_PINTAN_MECH => $dialog->getSupportedPinTanMechanisms())
321
        );
322
323
        return $message;
324
    }
325
326
    /**
327
     * Gets the saldo of given SEPAAccount.
328
     *
329
     * @param SEPAAccount $account
330
     * @return Model\Saldo|null
331
     * @throws Adapter\Exception\AdapterException
332
     * @throws Adapter\Exception\CurlException
333
     * @throws \Exception
334
     */
335
    public function getSaldo(SEPAAccount $account)
336
    {
337
        $dialog = $this->getDialog();
338
        $dialog->syncDialog($this->dialogProductName, $this->dialogProductVersion);
339
        $dialog->initDialog($this->dialogProductName, $this->dialogProductVersion);
340
341
        switch ((int) $dialog->getHksalMaxVersion()) {
342
            case 4:
343
            case 5:
344
                $hksalAccount = new Deg(
345
                    $account->getAccountNumber(),
0 ignored issues
show
Unused Code introduced by
The call to Deg::__construct() has too many arguments starting with $account->getAccountNumber().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
346
                    $account->getSubAccount(),
347
                    static::DEFAULT_COUNTRY_CODE, $account->getBlz()
348
                );
349
                $hksalAccount->addDataElement($account->getAccountNumber());
350
                $hksalAccount->addDataElement($account->getSubAccount());
351
                $hksalAccount->addDataElement(static::DEFAULT_COUNTRY_CODE);
352
                $hksalAccount->addDataElement($account->getBlz());
353
                break;
354 View Code Duplication
            case 6:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
355
                $hksalAccount = new Ktv(
356
                    $account->getAccountNumber(),
357
                    $account->getSubAccount(),
358
                    new Kik(280, $account->getBlz())
359
                );
360
                break;
361 View Code Duplication
            case 7:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
362
                $hksalAccount = new Kti(
363
                    $account->getIban(),
364
                    $account->getBic(),
365
                    $account->getAccountNumber(),
366
                    $account->getSubAccount(),
367
                    new Kik(280, $account->getBlz())
368
                );
369
                break;
370
            default:
371
                throw new \Exception('Unsupported HKSAL version: ' . $dialog->getHksalMaxVersion());
372
        }
373
374
        $message = new Message(
375
            $this->bankCode,
376
            $this->username,
377
            $this->pin,
378
            $dialog->getSystemId(),
379
            $dialog->getDialogId(),
380
            $dialog->getMessageNumber(),
381
            array(
382
                new HKSAL($dialog->getHksalMaxVersion(), 3, $hksalAccount, HKSAL::ALL_ACCOUNTS_N)
383
            ),
384
            array(
385
                AbstractMessage::OPT_PINTAN_MECH => $dialog->getSupportedPinTanMechanisms()
386
            )
387
        );
388
389
        $response = $dialog->sendMessage($message);
390
        $response = new GetSaldo($response->rawResponse);
391
392
        return $response->getSaldoModel();
393
    }
394
395
    /**
396
     * Helper method to retrieve a pre configured message object.
397
     * Factory for poor people :)
398
     *
399
     * @param Dialog $dialog
400
     * @param array $segments
401
     * @param array $options
402
     * @return Message
403
     */
404
    protected function getNewMessage(Dialog $dialog, array $segments, array $options)
405
    {
406
        return new Message(
407
            $this->bankCode,
408
            $this->username,
409
            $this->pin,
410
            $dialog->getSystemId(),
411
            $dialog->getDialogId(),
412
            $dialog->getMessageNumber(),
413
            $segments,
414
            $options
415
        );
416
    }
417
418
    /**
419
     * Helper method to retrieve a pre configured dialog object.
420
     * Factory for poor people :)
421
     *
422
     * @return Dialog
423
     */
424
    protected function getDialog()
425
    {
426
        return new Dialog(
427
            $this->connection,
428
            $this->bankCode,
429
            $this->username,
430
            $this->pin,
431
            $this->systemId,
432
            $this->logger
433
        );
434
    }
435
436
    /**
437
     * Needed for escaping userdata.
438
     * HBCI escape char is "?"
439
     *
440
     * @param string $string
441
     * @return string
442
     */
443 10
    protected function escapeString($string)
444
    {
445 10
        return str_replace(
446 10
            array('?', '@', ':', '+', '\''),
447 10
            array('??', '?@', '?:', '?+', '?\''),
448
            $string
449 10
        );
450
    }
451
}
452