Passed
Pull Request — master (#58)
by
unknown
01:14
created

Hsbc::parseVirtualAccount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Kingsquare\Parser\Banking\Mt940\Engine;
4
5
use Kingsquare\Banking\Statement;
6
use Kingsquare\Banking\Hsbc\HsbcTransaction;
7
use Kingsquare\Banking\Transaction;
8
use Kingsquare\Parser\Banking\Mt940\Engine;
9
10
/**
11
 * @author  jun ([email protected])
12
 * @license http://opensource.org/licenses/MIT MIT
13
 */
14
class Hsbc extends Engine
15
{
16
    const PATTERN_TAG_61 = '/^:61:(\d{6})(\d{4}?)(C|D|EC|ED|RC|RD)[A-Z](\d+,\d+)(F|N|S)([A-Z]{3})(.{16})/m';
17
18
    /**
19
     * returns the name of the bank.
20
     *
21
     * @return string
22
     */
23
    protected function parseStatementBank()
24
    {
25
        return 'HSBC';
26
    }
27
28
    /**
29
     * Overloaded
30
     *
31
     * @return array
32
     */
33
    protected function parseStatementData()
34
    {
35
        $results = preg_split(
36
            '/(^:20:|^-X{,3}$|\Z)/m',
37
            $this->getRawData(),
38
            -1,
39
            PREG_SPLIT_NO_EMPTY
40
        );
41
        return $results;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $results could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
42
    }
43
44
    /**
45
     * actual parsing of the data.
46
     *
47
     * @return Statement[]
48
     */
49
    public function parse()
50
    {
51
        $results = [];
52
        foreach ($this->parseStatementData() as $this->currentStatementData) {
53
            $statement = new Statement();
54
            if ($this->debug) {
55
                $statement->rawData = $this->currentStatementData;
56
            }
57
            $statement->setBank($this->parseStatementBank());
58
            $statement->setAccount($this->parseStatementAccount());
59
            $statement->setStartPrice($this->parseStatementStartPrice());
60
            $statement->setEndPrice($this->parseStatementEndPrice());
61
            $statement->setStartTimestamp($this->parseStatementStartTimestamp());
62
            $statement->setEndTimestamp($this->parseStatementEndTimestamp());
63
            $statement->setNumber($this->parseStatementNumber());
64
            $statement->setCurrency($this->parseStatementCurrency());
65
66
            foreach ($this->parseTransactionData() as $this->currentTransactionData) {
0 ignored issues
show
Comprehensibility Bug introduced by
$this is overwriting a variable from outer foreach loop.
Loading history...
67
                $transaction = new HsbcTransaction();
68
                if ($this->debug) {
69
                    $transaction->rawData = $this->currentTransactionData;
70
                }
71
                $transaction->setAccount($this->parseTransactionAccount());
72
                $transaction->setAccountName($this->parseTransactionAccountName());
73
                $transaction->setPrice($this->parseTransactionPrice());
74
                $transaction->setDebitCredit($this->parseTransactionDebitCredit());
75
                $transaction->setCancellation($this->parseTransactionCancellation());
76
                $transaction->setDescription($this->parseTransactionDescription());
77
                $transaction->setValueTimestamp($this->parseTransactionValueTimestamp());
78
                $transaction->setEntryTimestamp($this->parseTransactionEntryTimestamp());
79
                $transaction->setTransactionCode($this->parseTransactionCode());
80
                $transaction->setVirtualAccount($this->parseVirtualAccount());
81
                $statement->addTransaction($transaction);
82
            }
83
            $results[] = $statement;
84
        }
85
86
        return $results;
87
    }
88
89
    /**
90
     * Overloaded: 16x, like 808XXXXXX292 .
91
     *
92
     * @return string accountnumber
93
     */
94
    protected function parseStatementAccount()
95
    {
96
        $results = [];
97
        if (preg_match('/:25:([0-9X]+)*/', $this->getCurrentStatementData(), $results)
98
            && ! empty($results[1])
99
        ) {
100
            return $this->sanitizeAccount($results[1]);
101
        }
102
103
        return '';
104
    }
105
106
    /**
107
     * Overloaded: HSBC has different way of storing account info.
108
     *
109
     * {@inheritdoc}
110
     */
111
    protected function parseTransactionAccount()
112
    {
113
        $results = [];
114
        // YYMMDD[MMDD]2a[1!a]15d1!a3!c16x[//16x][34x]
115
        // eg.: :61:1203290329DD20000,00NTRF1004688128      //6128522200250001
116
        // Reference for the Account Owner (16x): 1004688128
117
        // Reference of the Account Servicing Institution [//16x]: 6128522200250001
118
        // Supplementary Details [34x]: null
119
        if (preg_match(self::PATTERN_TAG_61, $this->getCurrentTransactionData(), $results)) {
120
            return $this->sanitizeAccount($results[7]);
121
        }
122
123
        return '';
124
    }
125
126
    /**
127
     * Overloaded: debit or credit of the transaction.
128
     *
129
     * @return string
130
     */
131
    protected function parseTransactionDebitCredit()
132
    {
133
        $results = [];
134
        if (preg_match(self::PATTERN_TAG_61, $this->getCurrentTransactionData(), $results)) {
135
            return $this->sanitizeDebitCredit($results[3]);
136
        }
137
138
        return '';
139
    }
140
141
    /**
142
     * Overloaded: HSBC has different way of storing account name.
143
     *
144
     * {@inheritdoc}
145
     */
146
    protected function parseTransactionAccountName()
147
    {
148
        $results = [];
149
        // SEPA MT940 Structured
150
        if (preg_match('#/NAME/(.+?)\n?/(REMI|ADDR|ISDT|CSID)/#ms', $this->getCurrentTransactionData(), $results)) {
151
            $accountName = trim($results[1]);
152
            if ( ! empty($accountName)) {
153
                return $this->sanitizeAccountName($accountName);
154
            }
155
        }
156
157
        if (preg_match('/^:61:.*? (.+)/m', $this->getCurrentTransactionData(), $results)) {
158
            $accountName = trim($results[1]);
159
            if ( ! empty($accountName)) {
160
                return $this->sanitizeAccountName($accountName);
161
            }
162
        }
163
164
        if (preg_match('/(.*) Betaalautomaat/', $this->parseTransactionDescription(), $results)) {
165
            $accountName = trim($results[1]);
166
            if ( ! empty($accountName)) {
167
                return $this->sanitizeAccountName($accountName);
168
            }
169
        }
170
        return '';
171
    }
172
173
    /**
174
     * Overloaded: HSBC has different way of storing transaction value timestamps (ymd).
175
     *
176
     * {@inheritdoc}
177
     */
178
    protected function parseTransactionEntryTimestamp()
179
    {
180
        $results = [];
181
        if (preg_match('/^:60F:[C|D]([\d]{6})/m', $this->getCurrentStatementData(), $results)) {
182
            return $this->sanitizeTimestamp($results[1], 'ymd');
183
        }
184
185
        return 0;
186
    }
187
188
    /**
189
     * Overloaded: HSBC has different way of storing transaction value timestamps (ymd).
190
     *
191
     * {@inheritdoc}
192
     */
193
    protected function parseTransactionValueTimestamp()
194
    {
195
        $results = [];
196
        if (preg_match(self::PATTERN_TAG_61, $this->getCurrentTransactionData(), $results)) {
197
            return $this->sanitizeTimestamp($results[1], 'ymd');
198
        }
199
200
        return 0;
201
    }
202
203
    /**
204
     * retrieve the virtual account from full description of the transaction.
205
     *
206
     * @return string
207
     */
208
    protected function parseVirtualAccount()
209
    {
210
        $results = [];
211
        if (preg_match('/[\n].*?(?:\/VA\/(.+)$)/m', $this->getCurrentTransactionData(), $results)) {
212
            return $this->sanitizeVirtualAccount($results[1]);
213
        }
214
215
        return '';
216
    }
217
218
    /**
219
     * Overloaded: HSBC encapsulates the description with /REMI/ for SEPA.
220
     *
221
     * {@inheritdoc}
222
     */
223
    protected function sanitizeDescription($string)
224
    {
225
        $description = parent::sanitizeDescription($string);
226
        if (strpos($description, '/REMI/') !== false
227
            && preg_match('#/REMI/(.*?)(/((PURP|ISDT|CSID|RTRN)/)|$)#s', $description, $results) && ! empty($results[1])
228
        ) {
229
            return $results[1];
230
        }
231
        if (strpos($description, '/EREF/') !== false
232
            && preg_match('#/EREF/(.*?)/(ORDP)/#s', $description, $results) && ! empty($results[1])
233
        ) {
234
            return $results[1];
235
        }
236
237
        return $description;
238
    }
239
240
    /**
241
     * Overloaded: HSBC has some specific debit/credit marks.
242
     *
243
     * @param string $string
244
     *
245
     * @return string
246
     */
247
    protected function sanitizeDebitCredit($string)
248
    {
249
        $debitOrCredit = strtoupper(substr((string) $string, -1, 1));
250
        if ($debitOrCredit !== Transaction::DEBIT && $debitOrCredit !== Transaction::CREDIT) {
251
            trigger_error('wrong value for debit/credit ('.$string.')', E_USER_ERROR);
252
            $debitOrCredit = '';
253
        }
254
255
        return $debitOrCredit;
256
    }
257
258
    /**
259
     * @param string $string
260
     *
261
     * @return string
262
     */
263
    protected function sanitizeVirtualAccount($string)
264
    {
265
        return trim($string);
266
    }
267
268
    /**
269
     * Overloaded: Is applicable if first line starts with :20:AI.
270
     *
271
     * {@inheritdoc}
272
     */
273
    public static function isApplicable($string)
274
    {
275
        $firstline = strtok($string, "\r\n\t");
276
277
        return strpos($firstline, ':20:AI') !== false && strlen($firstline) === 20;
278
    }
279
}
280