Lines 100.00% 66 / 66
Functions and Methods 100.00% 3 / 3
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
VubMailParser 100.00% 66 / 66 100.00% 3 / 3 22 100.00% 1 / 1
 bankDomains 100.00% 1 / 1 100.00% 1 / 1 1
 supports 100.00% 10 / 10 100.00% 1 / 1 6
 parse 100.00% 55 / 55 100.00% 1 / 1 15
1<?php
2
3declare(strict_types=1);
4
5namespace Tomaj\BankMailsParser\Parser\Vub;
6
7use Tomaj\BankMailsParser\Exception\InvalidEmailFormatException;
8use Tomaj\BankMailsParser\MailContent;
9use Tomaj\BankMailsParser\Parser\BankDate;
10use Tomaj\BankMailsParser\Parser\ParserInterface;
11use Tomaj\BankMailsParser\Parser\ParsesBankMail;
12
13final readonly class VubMailParser implements ParserInterface
14{
15    use ParsesBankMail;
16
17    /**
18     * @return list<string>
19     */
20    #[\Override]
21    public function bankDomains(): array
22    {
23        return ['vub.sk'];
24    }
25
26    #[\Override]
27    public function supports(string $content, ?string $sender = null, ?string $subject = null): bool
28    {
29        return $this->supportsQuietly(function () use ($content): bool {
30            $content = $this->withoutByteOrderMark($content);
31            $hasDate = $this->matched($this->field('D(?:á|a)?tum', ':'), $content);
32            $hasSource = $this->matched($this->field('Z[ \t\x{00A0}\x{2009}\x{202F}]*(?:(?:ú|u)?čtu|tu)', ':'), $content);
33            $hasDestination = $this->matched($this->field('Na[ \t\x{00A0}\x{2009}\x{202F}]+(?:účet|et)', ':'), $content);
34            $hasStatus = $this->matched($this->field('(?:Stav|SIGN)', ':'), $content);
35            $hasAmount = $this->matched($this->field('Suma', ':'), $content);
36            $hasVs = $this->matched($this->field('VS', ':'), $content);
37
38            return $hasDate && $hasSource && $hasDestination && $hasStatus && $hasAmount && $hasVs;
39        });
40    }
41
42    public function parse(string $content): MailContent
43    {
44        $content = $this->requireUniformLineBreaks($content);
45        $signals = 0;
46
47        $transactionDate = null;
48        if ($this->matched($this->field('D(?:á|a)?tum:', '(.*)$'), $content, $result)) {
49            ++$signals;
50            $transactionDate = BankDate::parseFirst(mb_trim($this->group($result, 1), " \t\n\r\0\x0B\u{00A0}\u{2009}\u{202F}"), ['!j.n.Y', '!Y-m-d', '!j.n.Y G:i'], BankDate::bratislava());
51        }
52
53        $ownAccountNumber = null;
54        if ($this->matched($this->field('Na[ \t\x{00A0}\x{2009}\x{202F}]+(?:účet|et):', '([A-Z0-9 \x{00A0}\x{2009}\x{202F}\t]*)'), $content, $result)) {
55            $account = $this->normalizeAccount($this->group($result, 1));
56            if ($account !== '') {
57                ++$signals;
58                $ownAccountNumber = $account;
59            }
60        }
61
62        $accountNumber = null;
63        if ($this->matched($this->field('Z[ \t\x{00A0}\x{2009}\x{202F}]*(?:(?:ú|u)?čtu|tu):', '([A-Z0-9 \x{00A0}\x{2009}\x{202F}\t]*)'), $content, $result)) {
64            $account = $this->normalizeAccount($this->group($result, 1));
65            if ($account !== '') {
66                ++$signals;
67                $accountNumber = $account;
68            }
69        }
70
71        $money = null;
72        if ($this->matched($this->field('Suma:', '(.*)$'), $content, $result)) {
73            ++$signals;
74            $raw = trim(str_replace(["\u{00A0}", "\u{2009}", "\u{202F}", "\t"], ' ', $this->group($result, 1)));
75            if ($raw !== '' && preg_match('/^(-?\d(?:[\d \x{00A0}\x{2009}\x{202F}\t.,]*\d)?)(?:[ \t]*([A-Z]{3}))?$/u', $raw, $amount) === 1) {
76                $currency = $amount[2] ?? 'EUR';
77                $money = $this->moneyOrNull($amount[1], $currency, ',');
78            }
79        }
80
81        $vs = null;
82        if ($this->matched($this->field('VS:', '([0-9]+)'), $content, $result)) {
83            ++$signals;
84            $vs = $this->paymentSymbol($this->group($result, 1));
85        }
86
87        $ks = null;
88        if ($this->matched($this->field('KS:', '([0-9]+)'), $content, $result)) {
89            ++$signals;
90            $ks = $this->paymentSymbol($this->group($result, 1));
91        }
92
93        $ss = null;
94        if ($this->matched($this->field('(?:ŠS|SS|S):', '([0-9]+)'), $content, $result)) {
95            ++$signals;
96            $ss = $this->paymentSymbol($this->group($result, 1));
97        }
98
99        $sign = null;
100        if ($this->matched($this->field('SIGN:', '(.*)$'), $content, $result)) {
101            ++$signals;
102            $value = mb_trim($this->group($result, 1), " \t\n\r\0\x0B\u{00A0}\u{2009}\u{202F}");
103            if ($value !== '') {
104                $sign = $value;
105            }
106        }
107
108        if ($signals < 2) {
109            throw InvalidEmailFormatException::malformedContent(self::class, 'No VÚB fields found');
110        }
111
112        return new MailContent(
113            money: $money,
114            transactionDate: $transactionDate,
115            accountNumber: $accountNumber,
116            ownAccountNumber: $ownAccountNumber,
117            vs: $vs,
118            ss: $ss,
119            ks: $ks,
120            sign: $sign,
121        );
122    }
123}