Passed
Push — master ( a707ad...480443 )
by Jan
05:15
created

PaymentOrderSEPAExporter   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 67
c 1
b 0
f 0
dl 0
loc 164
rs 10
wmc 16

4 Methods

Rating   Name   Duplication   Size   Complexity  
A exportAuto() 0 37 4
B exportUsingGivenIBAN() 0 69 6
A exportAutoSingle() 0 22 5
A __construct() 0 4 1
1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published
7
 * by the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Services\SEPAExport;
20
21
use App\Entity\BankAccount;
22
use App\Entity\PaymentOrder;
23
use App\Entity\SEPAExport;
24
use App\Exception\SEPAExportAutoModeNotPossible;
25
use App\Helpers\SEPAXML\SEPAXMLExportResult;
26
use Digitick\Sepa\DomBuilder\BaseDomBuilder;
27
use Digitick\Sepa\DomBuilder\DomBuilderFactory;
28
use Digitick\Sepa\PaymentInformation;
29
use Digitick\Sepa\TransferFile\CustomerCreditTransferFile;
30
use Digitick\Sepa\TransferInformation\CustomerCreditTransferInformation;
31
use Webmozart\Assert\Assert;
32
33
final class PaymentOrderSEPAExporter
34
{
35
    /** @var GroupHeaderHelper */
36
    private $group_header_helper;
37
38
    /** @var SEPAExportGroupAndSplitHelper */
39
    private $splitHelper;
40
41
    public function __construct(GroupHeaderHelper $group_header_helper, SEPAExportGroupAndSplitHelper $splitHelper)
42
    {
43
        $this->group_header_helper = $group_header_helper;
44
        $this->splitHelper = $splitHelper;
45
    }
46
47
    /**
48
     * Exports the given payment orders and automatically assign the used bank accounts.
49
     * For this the bankaccount of the associated departments are used, and the FSR-Kom bank account if a payment is an
50
     * FSR-Kom transaction.
51
     * @param  PaymentOrder[]  $payment_orders The payment orders which should be exported
52
     * @throws SEPAExportAutoModeNotPossible If an element has no assigned default bank account, then automatic mode is not possible
53
     * @return SEPAXMLExportResult
54
     */
55
    public function exportAuto(array $payment_orders): SEPAXMLExportResult
56
    {
57
        //First we have to group the payment orders according to their bank accounts
58
        $results = $this->splitHelper->groupAndSplitPaymentOrdersForAutoExport($payment_orders);
59
60
        $exports = [];
61
62
        //Export each group on its own
63
        foreach ($results as $bank_account)
64
        {
65
            /** @var BankAccount $bank_account */
66
            /** @var PaymentOrder[][] $file */
67
            $file = $results[$bank_account];
68
69
            $file_number = 1;
70
            $max_number = count($file);
71
72
            foreach ($file as $group) {
73
                $tmp = $this->exportUsingGivenIBAN(
74
                    $group,
75
                    $bank_account->getIbanWithoutSpaces(),
76
                    $bank_account->getBic(),
77
                    $bank_account->getExportAccountName()
78
                );
79
80
                $description = $bank_account->getExportAccountName();
81
                if ($max_number > 1)
82
                {
83
                    $description .= ' ' . $file_number . ' / ' . $max_number;
84
                }
85
                $tmp->setDescription($description);
86
87
                $exports[] = $tmp;
88
            }
89
        }
90
91
        return new SEPAXMLExportResult($exports);
92
    }
93
94
    /**
95
     * Exports the given payment orders and automatically assign the used bank accounts.
96
     * Each payment order is put into its own file.
97
     * For this the bankaccount of the associated departments are used, and the FSR-Kom bank account if a payment is an
98
     * FSR-Kom transaction.
99
     * @param  PaymentOrder[]  $payment_orders The payment orders which should be exported
100
     * @throws SEPAExportAutoModeNotPossible If an element has no assigned default bank account, then automatic mode is not possible
101
     * @return SEPAXMLExportResult
102
     */
103
    public function exportAutoSingle(array $payment_orders): SEPAXMLExportResult
104
    {
105
        $exports = [];
106
107
        //Export each group on its own
108
        foreach ($payment_orders as $paymentOrder)
109
        {
110
            if ($paymentOrder->isFsrKomResolution()) {
111
                $bank_account = $this->splitHelper->getFSRKomBankAccount();
112
            } elseif ($paymentOrder->getDepartment() !== null && $paymentOrder->getDepartment()->getBankAccount() !== null) {
113
                $bank_account = $paymentOrder->getDepartment()->getBankAccount();
114
            } else {
115
                throw new SEPAExportAutoModeNotPossible($paymentOrder->getDepartment());
116
            }
117
118
            $tmp = $this->exportUsingGivenIBAN([$paymentOrder], $bank_account->getIbanWithoutSpaces(), $bank_account->getBic(), $bank_account->getExportAccountName());
119
            $tmp->setDescription($paymentOrder->getIDString());
120
121
            $exports[] = $tmp;
122
        }
123
124
        return new SEPAXMLExportResult($exports);
125
    }
126
127
128
    public function exportUsingGivenIBAN(array $payment_orders, string $debtor_iban, string $debtor_bic, string $debtor_account_name): SEPAExport
129
    {
130
        //We need IBAN without spaces
131
        $debtor_iban = str_replace(" ", "", $debtor_iban);
132
133
        $groupHeader = $this->group_header_helper->getGroupHeader($debtor_bic);
134
        $sepaFile = new CustomerCreditTransferFile($groupHeader);
135
136
        $payment = new PaymentInformation(
137
            md5(random_bytes(50)), //Use a random payment identifier ID
138
            $debtor_iban,
139
            $debtor_bic,
140
            $debtor_account_name
141
        );
142
143
        //Disable batch booking, as the commerzbank does not show details for "Sammelüberweisungen"
144
        $payment->setBatchBooking(false);
145
146
        //Add each payment order as transaction
147
        foreach ($payment_orders as $payment_order) {
148
            //Ensure that type is correct
149
            if (!$payment_order instanceof PaymentOrder) {
150
                throw new \InvalidArgumentException('$payment_orders must be an array of PaymentOrder elements!');
151
            }
152
153
            //Ensure that the ID is available
154
            if (!$payment_order->getId() === null) {
155
                throw new \InvalidArgumentException('A payment order that should be exported misses an ID. All payment orders must have been persisted!');
156
            }
157
158
            $transfer = new CustomerCreditTransferInformation(
159
                $payment_order->getAmount(),
160
                $payment_order->getBankInfo()->getIbanWithoutSpaces(),
161
                $payment_order->getBankInfo()->getAccountOwner()
162
            );
163
164
            //BIC is optional, only set it if it was set.
165
            if (!empty($payment_order->getBankInfo()->getBic())) {
166
                $transfer->setBic($payment_order->getBankInfo()->getBic());
167
            }
168
169
            //We use the ID String of the payment order as end to end reference
170
            $transfer->setEndToEndIdentification($payment_order->getIDString());
171
            //Set the reference ID of the payment order as
172
            $transfer->setRemittanceInformation($payment_order->getBankInfo()->getReference());
173
174
            $payment->addTransfer($transfer);
175
        }
176
177
        //Add payment infos to SEPA file
178
        $sepaFile->addPaymentInformation($payment);
179
180
        // We have to use the format 'pain.001.001.03'
181
        $domBuilder = DomBuilderFactory::createDomBuilder($sepaFile, 'pain.001.001.03');
182
183
        if (!$domBuilder instanceof BaseDomBuilder) {
0 ignored issues
show
introduced by
$domBuilder is always a sub-type of Digitick\Sepa\DomBuilder\BaseDomBuilder.
Loading history...
184
            throw new \RuntimeException('$domBuilder must be an BaseDomBuilder instance!');
185
        }
186
187
        //Create a temporary file with the XML content
188
        $xml_string = $domBuilder->asXml();
189
190
        //We use the format YYYYMMDDHHmmss_MsgID.xml
191
        $original_filename = sprintf("%s_%s.xml",
192
            (new \DateTime())->format('YmdHis'),
193
            $groupHeader->getMessageIdentification(),
194
        );
195
196
        return SEPAExport::createFromXMLString($xml_string, $original_filename);
197
    }
198
199
200
201
202
}