Passed
Push — main ( 5943f3...623d6a )
by Daniel
02:55
created

ClassElectronicInvoiceUserInterface   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 7
Bugs 0 Features 2
Metric Value
eloc 185
c 7
b 0
f 2
dl 0
loc 265
ccs 0
cts 204
cp 0
rs 9.92
wmc 31

12 Methods

Rating   Name   Duplication   Size   Complexity  
A setActionToDo() 0 16 3
A setArchiveFromAnaf() 0 39 5
A actionAnalyzeZIPfromANAFfromLocalFolder() 0 12 4
A getButtonToActionSomething() 0 15 2
A __construct() 0 6 1
A setDataSupplierOrCustomer() 0 12 3
A setHtmlFooter() 0 11 1
A setUserInterface() 0 8 1
B setStandardizedFeedbackArray() 0 63 3
A setArrayToHtmlTable() 0 16 4
A setArrayToHtmlTableHeader() 0 24 3
A setHtmlHeader() 0 10 1
1
<?php
2
3
/*
4
 * Copyright (c) 2024, Daniel Popiniuc and its licensors.
5
 *
6
 * All rights reserved. This program and the accompanying materials
7
 * are made available under the terms of the Eclipse Public License v1.0
8
 * which accompanies this distribution, and is available at
9
 * http://www.eclipse.org/legal/epl-v10.html
10
 *
11
 * Contributors:
12
 *    Daniel Popiniuc
13
 */
14
15
namespace danielgp\efactura;
16
17
class ClassElectronicInvoiceUserInterface
18
{
19
20
    use \danielgp\io_operations\InputOutputFiles;
21
22
    private array $arrayConfiguration;
23
    private \SebastianBergmann\Timer\Timer $classTimer;
24
25
    public function __construct()
26
    {
27
        $this->classTimer         = new \SebastianBergmann\Timer\Timer();
28
        $this->classTimer->start();
29
        $this->arrayConfiguration = $this->getArrayFromJsonFile(__DIR__
30
            . DIRECTORY_SEPARATOR . 'config', 'BasicConfiguration.json');
31
    }
32
33
    public function actionAnalyzeZIPfromANAFfromLocalFolder(string $strFilePath): array
34
    {
35
        $arrayFiles    = new \RecursiveDirectoryIterator($strFilePath, \FilesystemIterator::SKIP_DOTS);
36
        $arrayInvoices = [];
37
        $intFileNo     = 0;
38
        foreach ($arrayFiles as $strFile) {
39
            if ($strFile->isFile() && ($strFile->getExtension() === 'zip')) {
40
                $arrayInvoices[$intFileNo] = $this->setArchiveFromAnaf($strFile->getRealPath());
41
                $intFileNo++;
42
            }
43
        }
44
        return $arrayInvoices;
45
    }
46
47
    private function getButtonToActionSomething(array $arrayButtonFeatures): string
48
    {
49
        $arrayButtonStyle = [
50
            'font: bold 14pt Arial',
51
            'margin: 2px',
52
            'padding: 4px 10px',
53
        ];
54
        $arrayStylePieces = $arrayButtonStyle;
55
        if (array_key_exists('AdditionalStyle', $arrayButtonFeatures)) {
56
            $arrayStylePieces = array_merge($arrayButtonStyle, $arrayButtonFeatures['AdditionalStyle']);
57
        }
58
        return vsprintf('<a href="%s" class="btn btn-outline-primary" style="%s">%s</a>', [
59
            $arrayButtonFeatures['URL'],
60
            implode(';', $arrayStylePieces),
61
            $arrayButtonFeatures['Text'],
62
        ]);
63
    }
64
65
    private function setArchiveFromAnaf(string $strFile)
66
    {
67
        $classZip      = new \ZipArchive();
68
        $arrayToReturn = [];
69
        $res           = $classZip->open($strFile, \ZipArchive::RDONLY);
70
        if ($res === true) {
71
            $intFilesArchived = $classZip->numFiles;
72
            for ($intArchivedFile = 0; $intArchivedFile < $intFilesArchived; $intArchivedFile++) {
73
                $strArchivedFile = $classZip->getNameIndex($intArchivedFile);
74
                $strFileStats    = $classZip->statIndex($intArchivedFile);
75
                $matches         = [];
76
                preg_match('/^[0-9]{5,20}\.xml$/', $strArchivedFile, $matches, PREG_OFFSET_CAPTURE);
77
                $matches2        = [];
78
                preg_match('/^semnatura_[0-9]{5,20}\.xml$/', $strArchivedFile, $matches2, PREG_OFFSET_CAPTURE);
79
                if ($matches !== []) {
80
                    $resInvoice        = $classZip->getStream($strArchivedFile);
81
                    $strInvoiceContent = stream_get_contents($resInvoice);
82
                    fclose($resInvoice);
83
                    $arrayToReturn     = $this->setStandardizedFeedbackArray([
84
                        'Response_Index'      => pathinfo($strFile)['filename'],
85
                        'Size'                => $strFileStats['size'],
86
                        'FileDate'            => date('Y-m-d H:i:s', $strFileStats['mtime']),
87
                        'Matches'             => $matches,
88
                        'strArchivedFileName' => $strArchivedFile,
89
                        'strInvoiceContent'   => $strInvoiceContent,
90
                    ]);
91
                } elseif ($matches2 === []) {
92
                    echo vsprintf('<div>' . $this->arrayConfiguration['Feedback']['DifferentFile'] . '</div>', [
93
                        $strArchivedFile,
94
                        $strFile->getBasename(),
95
                    ]);
96
                }
97
            }
98
        } else {
99
            // @codeCoverageIgnoreStart
100
            throw new \RuntimeException(sprintf('Archive %s could not be opened!', $strFile));
101
            // @codeCoverageIgnoreEnd
102
        }
103
        return $arrayToReturn;
104
    }
105
106
    public function setActionToDo(): void
107
    {
108
        echo '<main>';
109
        $arrayOptions = [
110
            'action' => FILTER_SANITIZE_SPECIAL_CHARS,
111
        ];
112
        $arrayInputs  = filter_input_array(INPUT_GET, $arrayOptions);
113
        if (array_key_exists('action', $arrayInputs)) {
114
            switch ($arrayInputs['action']) {
115
                case 'AnalyzeZIPfromANAFfromLocalFolder':
116
                    $arrayInvoices = $this->actionAnalyzeZIPfromANAFfromLocalFolder('P:/e-Factura/Downloaded/');
117
                    $this->setArrayToHtmlTable($arrayInvoices);
118
                    break;
119
            }
120
        }
121
        echo '</main>';
122
    }
123
124
    private function setArrayToHtmlTableHeader(array $arrayData): string
125
    {
126
        $arrayMap    = [
127
            'Amount_TOTAL'   => 'TOTAL',
128
            'Amount_VAT'     => 'TVA',
129
            'Amount_wo_VAT'  => 'Valoare',
130
            'Customer_CUI'   => 'CUI client',
131
            'Customer_Name'  => 'Nume client',
132
            'Days_Between'   => 'Zile emitere-depunere',
133
            'Document_No'    => 'Identificator',
134
            'Error'          => 'Eroare',
135
            'Issue_Date'     => 'Data emiterii',
136
            'Loading_Index'  => 'Index încărcare',
137
            'No_Lines'       => 'Nr. linii',
138
            'Response_Date'  => 'Data răspuns',
139
            'Response_Index' => 'Index răspuns',
140
            'Supplier_CUI'   => 'CUI emitent',
141
            'Supplier_Name'  => 'Nume emitent',
142
        ];
143
        $strToReturn = '<th>#</th>';
144
        foreach ($arrayData as $key) {
145
            $strToReturn .= sprintf('<th>%s</th>', (array_key_exists($key, $arrayMap) ? $arrayMap[$key] : $key));
146
        }
147
        return '<thead><tr>' . $strToReturn . '</tr></thead>';
148
    }
149
150
    public function setArrayToHtmlTable(array $arrayData)
151
    {
152
        foreach ($arrayData as $intLineNo => $arrayContent) {
153
            ksort($arrayContent);
154
            if ($intLineNo === 0) {
155
                echo '<table style="margin-left:auto;margin-right:auto;">'
156
                . $this->setArrayToHtmlTableHeader(array_keys($arrayContent))
157
                . '<tbody>';
158
            }
159
            echo '<tr' . ($arrayContent['Error'] === '' ? '' : ' style="color:red;"') . '>'
160
            . '<td>' . ($intLineNo + 1) . '</td>'
161
            . '<td>' . implode('</td><td>', array_values($arrayContent)) . '</td>'
162
            . '</tr>';
163
        }
164
        echo '</tbody>'
165
        . '</table>';
166
    }
167
168
    private function setDataSupplierOrCustomer(array $arrayData)
169
    {
170
        $strCustomerCui = '';
171
        if (isset($arrayData['PartyTaxScheme']['01']['CompanyID'])) {
172
            $strCustomerCui = $arrayData['PartyTaxScheme']['01']['CompanyID'];
173
        } else {
174
            $strCustomerCui = $arrayData['PartyLegalEntity']['CompanyID'];
175
        }
176
        if (is_numeric($strCustomerCui)) {
177
            $strCustomerCui = 'RO' . $strCustomerCui;
178
        }
179
        return $strCustomerCui;
180
    }
181
182
    public function setHtmlFooter(): void
183
    {
184
        $strHtmlContent = implode('', $this->getFileEntireContent(implode(DIRECTORY_SEPARATOR, [
185
                __DIR__,
186
                'HTML',
187
                'footer.html',
188
        ])));
189
        echo vsprintf($strHtmlContent, [
190
            (new \SebastianBergmann\Timer\ResourceUsageFormatter())->resourceUsage($this->classTimer->stop()),
191
            date('Y'),
192
            $this->arrayConfiguration['Application']['Developer'],
193
        ]);
194
    }
195
196
    public function setHtmlHeader(): void
197
    {
198
        $strHtmlContent = implode('', $this->getFileEntireContent(implode(DIRECTORY_SEPARATOR, [
199
                __DIR__,
200
                'HTML',
201
                'header.html',
202
        ])));
203
        echo vsprintf($strHtmlContent, [
204
            $this->arrayConfiguration['Application']['Name'],
205
            $this->arrayConfiguration['Application']['Developer'],
206
        ]);
207
    }
208
209
    private function setStandardizedFeedbackArray(array $arrayData): array
210
    {
211
        $arrayToReturn = [
212
            'Response_Date'  => '',
213
            'Response_Index' => $arrayData['Response_Index'],
214
            'Loading_Index'  => '',
215
            'Size'           => '',
216
            'Document_No'    => '',
217
            'Issue_Date'     => '',
218
            'Amount_wo_VAT'  => '',
219
            'Amount_TOTAL'   => '',
220
            'Amount_VAT'     => '',
221
            'Supplier_CUI'   => '',
222
            'Supplier_Name'  => '',
223
            'Customer_CUI'   => '',
224
            'Customer_Name'  => '',
225
            'No_Lines'       => '',
226
            'Error'          => '',
227
            'Days_Between'   => '',
228
        ];
229
        if ($arrayData['Size'] > 1000) {
230
            file_put_contents($arrayData['strArchivedFileName'], $arrayData['strInvoiceContent']);
231
            $appR                           = new \danielgp\efactura\ClassElectronicInvoiceRead();
232
            $arrayElectronicInv             = $appR->readElectronicInvoice($arrayData['strArchivedFileName']);
233
            $arrayBasic                     = $arrayElectronicInv['Header']['CommonBasicComponents-2'];
234
            $arrayAggregate                 = $arrayElectronicInv['Header']['CommonAggregateComponents-2'];
235
            $floatAmounts                   = [
236
                'wo_VAT' => (float) $arrayAggregate['LegalMonetaryTotal']['TaxExclusiveAmount']['value'],
237
                'TOTAL'  => (float) $arrayAggregate['LegalMonetaryTotal']['TaxInclusiveAmount']['value'],
238
            ];
239
            $arrayParties                   = [
240
                'Customer' => $arrayAggregate['AccountingCustomerParty']['Party'],
241
                'Supplier' => $arrayAggregate['AccountingSupplierParty']['Party'],
242
            ];
243
            $arrayToReturn['Loading_Index'] = substr($arrayData['Matches'][0][0], 0, -4);
244
            $arrayToReturn['Size']          = $arrayData['Size'];
245
            $arrayToReturn['Document_No']   = $arrayBasic['ID'];
246
            $arrayToReturn['Issue_Date']    = $arrayBasic['IssueDate'];
247
            $arrayToReturn['Response_Date'] = $arrayData['FileDate'];
248
            $arrayToReturn['Amount_wo_VAT'] = $floatAmounts['wo_VAT'];
249
            $arrayToReturn['Amount_TOTAL']  = $floatAmounts['TOTAL'];
250
            $arrayToReturn['Amount_VAT']    = round(($floatAmounts['TOTAL'] - $floatAmounts['wo_VAT']), 2);
251
            $arrayToReturn['Supplier_CUI']  = $this->setDataSupplierOrCustomer($arrayParties['Supplier']);
252
            $arrayToReturn['Supplier_Name'] = $arrayParties['Supplier']['PartyLegalEntity']['RegistrationName'];
253
            $arrayToReturn['Customer_CUI']  = $this->setDataSupplierOrCustomer($arrayParties['Customer']);
254
            $arrayToReturn['Customer_Name'] = $arrayParties['Customer']['PartyLegalEntity']['RegistrationName'];
255
            $arrayToReturn['No_Lines']      = count($arrayElectronicInv['Lines']);
256
            $origin                         = new \DateTimeImmutable($arrayBasic['IssueDate']);
257
            $target                         = new \DateTimeImmutable($arrayData['FileDate']);
258
            $interval                       = $origin->diff($target);
259
            $arrayToReturn['Days_Between']  = $interval->format('%R%a');
260
            unlink($arrayData['strArchivedFileName']);
261
        } elseif ($arrayData['Size'] > 0) {
262
            $objErrors                      = new \SimpleXMLElement($arrayData['strInvoiceContent']);
263
            $arrayToReturn['Loading_Index'] = $objErrors->attributes()->Index_incarcare->__toString();
264
            $arrayToReturn['Size']          = $arrayData['Size'];
265
            $arrayToReturn['Response_Date'] = $arrayData['FileDate'];
266
            $arrayToReturn['Supplier_CUI']  = 'RO' . $objErrors->attributes()->Cif_emitent->__toString();
267
            $arrayToReturn['Supplier_Name'] = '??????????';
268
            $arrayToReturn['Error']         = '<div style="max-width:200px;font-size:0.8rem;">'
269
                . $objErrors->Error->attributes()->errorMessage->__toString() . '</div>';
270
        }
271
        return $arrayToReturn;
272
    }
273
274
    public function setUserInterface(): void
275
    {
276
        echo '<header class="border-bottom">'
277
        . $this->getButtonToActionSomething([
278
            'Text' => 'Analyze ZIP archives from ANAF from a local folder',
279
            'URL'  => '?action=AnalyzeZIPfromANAFfromLocalFolder',
280
        ])
281
        . '</header>';
282
    }
283
}
284