TraitUserInterfaceLogic::handleArchiveContent()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 33
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 4
eloc 27
c 4
b 0
f 0
nc 4
nop 2
dl 0
loc 33
rs 9.488
1
<?php
2
3
/*
4
 * Copyright (c) 2024 - 2025 Daniel Popiniuc.
5
 * All rights reserved. This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 *
10
 * Contributors:
11
 *    Daniel Popiniuc
12
 */
13
14
namespace danielgp\efactura;
15
16
trait TraitUserInterfaceLogic
17
{
18
    use \danielgp\io_operations\InputOutputFiles;
19
20
    protected array $arrayConfiguration;
21
    protected $translation;
22
23
    public function actionAnalyzeZIPfromANAFfromLocalFolder(string $strFilePath): array
24
    {
25
        $arrayFiles    = new \RecursiveDirectoryIterator($strFilePath, \FilesystemIterator::SKIP_DOTS);
26
        $arrayInvoices = [];
27
        $intFileNo     = 0;
28
        foreach ($arrayFiles as $strFile) {
29
            if ($strFile->isFile()) {
30
                $arrayFileDetails = $this->handleResponseFile($strFile);
31
                if ($arrayFileDetails !== []) {
32
                    $arrayInvoices[$intFileNo] = $arrayFileDetails;
33
                    $intFileNo++;
34
                }
35
            }
36
        }
37
        return $arrayInvoices;
38
    }
39
40
    protected function getConfiguration()
41
    {
42
        $this->arrayConfiguration = $this->getArrayFromJsonFile(__DIR__
43
            . DIRECTORY_SEPARATOR . 'config', 'BasicConfiguration.json');
44
    }
45
46
    /**
47
     * Archived document is read as content in memory since 2024-02-16
48
     * (prior to this date a temporary local file was saved, processed and finally removed when done with it)
49
     *
50
     * @param array $arrayData
51
     * @return array
52
     */
53
    private function getDocumentDetails(array $arrayData): array
54
    {
55
        $appR               = new \danielgp\efactura\ClassElectronicInvoiceRead();
56
        $arrayElectronicInv = $appR->readElectronicInvoice($arrayData['strInvoiceContent']);
57
        $arrayBasic         = $arrayElectronicInv['Header']['CommonBasicComponents-2'];
58
        $arrayAggregate     = $arrayElectronicInv['Header']['CommonAggregateComponents-2'];
59
        $arrayStandardized  = [
60
            'DocumentTypeCode'     => $this->handleDocumentTypeCode($arrayBasic),
61
            'Customer'             => $arrayAggregate['AccountingCustomerParty']['Party'],
62
            'ID'                   => $arrayBasic['ID'],
63
            'IssueDate'            => $arrayBasic['IssueDate'],
64
            'DocumentCurrencyCode' => $arrayBasic['DocumentCurrencyCode'],
65
            'No_of_Lines'          => count($arrayElectronicInv['Lines']),
66
            'Supplier'             => $arrayAggregate['AccountingSupplierParty']['Party'],
67
            'TOTAL'                => (float) $arrayAggregate['LegalMonetaryTotal']['TaxInclusiveAmount']['value'],
68
            'wo_VAT'               => (float) $arrayAggregate['LegalMonetaryTotal']['TaxExclusiveAmount']['value'],
69
        ];
70
        if (array_key_exists('InvoicePeriod', $arrayAggregate)) {
71
            if (array_key_exists('StartDate', $arrayAggregate['InvoicePeriod'])) {
72
                $arrayStandardized['InvoicePeriod_StartDate'] = $arrayAggregate['InvoicePeriod']['StartDate'];
73
            }
74
            if (array_key_exists('EndDate', $arrayAggregate['InvoicePeriod'])) {
75
                $arrayStandardized['InvoicePeriod_EndDate'] = $arrayAggregate['InvoicePeriod']['EndDate'];
76
            }
77
        }
78
        if (array_key_exists('ContractDocumentReference', $arrayAggregate)) {
79
            $arrayStandardized['ContractDocumentReference_ID'] = $arrayAggregate['ContractDocumentReference']['ID'];
80
        }
81
        return $arrayStandardized;
82
    }
83
84
    private function handleArchiveContent(\ZipArchive $classZip, array $arrayArchiveParam): array
85
    {
86
        $arrayToReturn = [];
87
        for ($intArchivedFile = 0; $intArchivedFile < $arrayArchiveParam['No_of_Files']; $intArchivedFile++) {
88
            $strArchivedFile = $classZip->getNameIndex($intArchivedFile);
89
            $matches         = [];
90
            preg_match('/^[0-9]{5,20}\.xml$/', $strArchivedFile, $matches, PREG_OFFSET_CAPTURE);
91
            $matches2        = [];
92
            preg_match('/^semnatura_[0-9]{5,20}\.xml$/', $strArchivedFile, $matches2, PREG_OFFSET_CAPTURE);
93
            if ($matches !== []) {
94
                $resInvoice        = $classZip->getStream($strArchivedFile);
95
                $strInvoiceContent = filter_var(stream_get_contents($resInvoice), FILTER_FLAG_ENCODE_LOW | FILTER_FLAG_ENCODE_HIGH);
96
                fclose($resInvoice);
97
                $strFileStats      = $classZip->statIndex($intArchivedFile);
98
                $arrayToReturn     = $this->setStandardizedFeedbackArray([
99
                    'Response_Index'      => pathinfo($arrayArchiveParam['FileName'])['filename'],
100
                    'Size'                => $strFileStats['size'],
101
                    'FileDateTime'        => date('Y-m-d H:i:s', $strFileStats['mtime']),
102
                    'Matches'             => $matches,
103
                    'strArchivedFileName' => $strArchivedFile,
104
                    'strInvoiceContent'   => $strInvoiceContent,
105
                    'Response_Size'       => $arrayArchiveParam['Response_Size'],
106
                ]);
107
            } elseif ($matches2 === []) {
108
                echo vsprintf('<div>'
109
                    . filter_var($this->arrayConfiguration['Feedback']['DifferentFile'], FILTER_FLAG_ENCODE_LOW | FILTER_FLAG_ENCODE_HIGH)
110
                    . '</div>', [
111
                    $strArchivedFile,
112
                    $arrayArchiveParam['Filename'],
113
                ]);
114
            }
115
        }
116
        return $arrayToReturn;
117
    }
118
119
    private function handleDocumentTypeCode(array $arrayBasic): string
120
    {
121
        $strValueToReturn = '';
122
        if (array_key_exists('InvoiceTypeCode', $arrayBasic)) {
123
            $strValueToReturn = $arrayBasic['InvoiceTypeCode'];
124
        } elseif (array_key_exists('CreditNoteTypeCode', $arrayBasic)) {
125
            $strValueToReturn = $arrayBasic['CreditNoteTypeCode'];
126
        }
127
        return $strValueToReturn;
128
    }
129
130
    private function handleResponseFile(\SplFileInfo | string $strFile): array
131
    {
132
        $arrayToReturn = [];
133
        $strFileMime   = mime_content_type($strFile->getRealPath());
134
        switch($strFileMime) {
135
            case 'application/json':
136
                $arrayError    = $this->getArrayFromJsonFile($strFile->getPath(), $strFile->getFilename());
137
                $arrayToReturn = $this->setStandardizedFeedbackArray([
138
                    'Error'          => $arrayError['eroare'] . ' ===> ' . $arrayError['titlu'],
139
                    'Response_Index' => $strFile->getFilename(),
140
                    'Response_Size'  => $strFile->getSize(),
141
                ]);
142
                break;
143
            case 'application/zip':
144
                $arrayToReturn = $this->setArchiveFromAnaf($strFile->getRealPath(), $strFile->getSize());
145
                break;
146
        }
147
        return $arrayToReturn;
148
    }
149
150
    private function setArchiveFromAnaf(string $strFile, int $intFileSize)
151
    {
152
        $arrayToReturn = [];
153
        $classZip      = new \ZipArchive();
154
        $res           = $classZip->open($strFile, \ZipArchive::RDONLY);
155
        if ($res) {
156
            $intFilesArchived = $classZip->numFiles;
157
            $arrayToReturn    = $this->handleArchiveContent($classZip, [
158
                'No_of_Files'   => $intFilesArchived,
159
                'FileName'      => $strFile,
160
                'Response_Size' => $intFileSize,
161
            ]);
162
        } else {
163
            // @codeCoverageIgnoreStart
164
            $arrayToReturn = $this->setStandardizedFeedbackArray([
165
                'Response_Index' => pathinfo($strFile)['filename'],
166
                'Error'          => $this->translation->find(null, 'i18n_Msg_InvalidZip')->getTranslation(),
167
                'Response_Size'  => 0,
168
            ]);
169
            // @codeCoverageIgnoreEnd
170
        }
171
        return $arrayToReturn;
172
    }
173
174
    private function setDataSupplierOrCustomer(array $arrayData)
175
    {
176
        $strCustomerCui = '';
177
        if (isset($arrayData['PartyTaxScheme']['01']['CompanyID'])) {
178
            $strCustomerCui = $arrayData['PartyTaxScheme']['01']['CompanyID'];
179
        } else {
180
            $strCustomerCui = $arrayData['PartyLegalEntity']['CompanyID'];
181
        }
182
        if (is_numeric($strCustomerCui)) {
183
            $strCustomerCui = 'RO' . $strCustomerCui;
184
        }
185
        return $strCustomerCui;
186
    }
187
188
    private function setDaysElapsed(string $strFirstDate, string $strLaterDate): string
189
    {
190
        $origin   = new \DateTimeImmutable($strFirstDate);
191
        $target   = new \DateTimeImmutable($strLaterDate);
192
        $interval = $origin->diff($target);
193
        return $interval->format('%R%a');
194
    }
195
196
    private function setDefaultsToInvoiceDetailsArray(array $arrayData): array
197
    {
198
        return [
199
            'Response_DateTime'      => '',
200
            'Response_Index'         => $arrayData['Response_Index'],
201
            'Response_Size'          => $arrayData['Response_Size'],
202
            'Loading_Index'          => '',
203
            'Size'                   => '',
204
            'Document_Type_Code'     => '',
205
            'Document_No'            => '',
206
            'Issue_Date'             => '',
207
            'Issue_YearMonth'        => '',
208
            'Document_Currency_Code' => '',
209
            'Amount_wo_VAT'          => '',
210
            'Amount_TOTAL'           => '',
211
            'Amount_VAT'             => '',
212
            'Supplier_CUI'           => '',
213
            'Supplier_Name'          => '',
214
            'Customer_CUI'           => '',
215
            'Customer_Name'          => '',
216
            'No_of_Lines'            => '',
217
            'Error'                  => '',
218
            'Message'                => '',
219
            'Days_Between'           => '',
220
        ];
221
    }
222
223
    private function setErrorsFromExtendedMarkupLaguage(array $arrayData, string $strErrorTag): array
224
    {
225
        $arrayErrors = [];
226
        $parser      = xml_parser_create();
227
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
228
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
229
        xml_parse_into_struct($parser, filter_var($arrayData['strInvoiceContent'], FILTER_FLAG_ENCODE_LOW | FILTER_FLAG_ENCODE_HIGH), $arrayErrors);
230
        xml_parser_free($parser);
231
        return [
232
            'Loading_Index'     => $arrayErrors[0]['attributes']['Index_incarcare'],
233
            'Size'              => $arrayData['Size'],
234
            'Response_DateTime' => $arrayData['FileDateTime'],
235
            'Supplier_CUI'      => 'RO' . $arrayErrors[0]['attributes']['Cif_emitent'],
236
            'Supplier_Name'     => '??????????',
237
            'Error'             => sprintf($strErrorTag, $arrayErrors[1]['attributes']['errorMessage']),
238
        ];
239
    }
240
241
    private function setLocalization(): void
242
    {
243
        if (!array_key_exists('language_COUNTRY', $_GET)) {
244
            $_GET['language_COUNTRY'] = 'ro_RO';
245
        }
246
        $loader            = new \Gettext\Loader\PoLoader();
247
        $this->translation = $loader->loadFile(__DIR__ . '/locale/'
248
            . filter_input(INPUT_GET, 'language_COUNTRY', FILTER_VALIDATE_REGEXP, [
249
                'options' => [
250
                    'regexp' => '/^(en_US|it_IT|ro_RO)$/'
251
                ]
252
            ]) . '/LC_MESSAGES/eFactura.po');
253
    }
254
255
    private function setStandardizedFeedbackArray(array $arrayData): array
256
    {
257
        $arrayToReturn = $this->setDefaultsToInvoiceDetailsArray($arrayData);
258
        $strErrorTag   = '<div style="max-width:200px;font-size:0.8rem;">%s</div>';
259
        $strTimeZone   = $this->translation->find(null, 'i18n_TimeZone')->getTranslation();
260
        $strFormatter  = new \IntlDateFormatter(
261
            filter_input(INPUT_GET, 'language_COUNTRY', FILTER_VALIDATE_REGEXP, [
262
                'options' => [
263
                    'regexp' => '/^(en_US|it_IT|ro_RO)$/'
264
                ]
265
            ]),
266
            \IntlDateFormatter::FULL,
267
            \IntlDateFormatter::FULL,
268
            $strTimeZone,
269
            \IntlDateFormatter::GREGORIAN,
270
            'r-MM__MMMM'
271
        );
272
        if (array_key_exists('Error', $arrayData)) {
273
            $arrayToReturn['Error'] = sprintf($strErrorTag, $arrayData['Error']);
274
            $arrayToReturn['Size']  = 0;
275
        } else {
276
            $appR              = new \danielgp\efactura\ClassElectronicInvoiceRead();
277
            $objFile           = $appR->readElectronicXmlHeader(filter_var($arrayData['strInvoiceContent'], FILTER_FLAG_ENCODE_LOW | FILTER_FLAG_ENCODE_HIGH));
278
            $documentHeaderTag = $appR->getDocumentRoot($objFile);
279
            switch($documentHeaderTag['DocumentTagName']) {
280
                case 'header':
281
                    switch($documentHeaderTag['DocumentNameSpaces']['']) {
282
                        case 'mfp:anaf:dgti:efactura:mesajEroriFactuta:v1':
283
                            $arrayTemp     = $this->setErrorsFromExtendedMarkupLaguage($arrayData, $strErrorTag);
284
                            $arrayToReturn = array_merge($arrayToReturn, $arrayTemp);
285
                            break;
286
                        case 'mfp:anaf:dgti:spv:reqMesaj:v1':
287
                            $arrayTemp     = [
288
                                'Loading_Index'     => $documentHeaderTag['header']['index_incarcare'],
289
                                'Message'           => $documentHeaderTag['header']['message'],
290
                                'Size'              => $arrayData['Size'],
291
                                'Response_DateTime' => $arrayData['FileDateTime'],
292
                            ];
293
                            $arrayToReturn = array_merge($arrayToReturn, $arrayTemp);
294
                            break;
295
                    }
296
                    break;
297
                case 'CreditNote':
298
                case 'Invoice':
299
                    $arrayAttr         = $this->getDocumentDetails($arrayData);
300
                    $arrayTemp         = [
301
                        'Loading_Index'          => substr($arrayData['Matches'][0][0], 0, -4),
302
                        'Size'                   => $arrayData['Size'],
303
                        'Document_Type_Code'     => $arrayAttr['DocumentTypeCode'],
304
                        'Document_No'            => $arrayAttr['ID'],
305
                        'Issue_Date'             => $arrayAttr['IssueDate'],
306
                        'Issue_YearMonth'        => $strFormatter->format(new \DateTime($arrayAttr['IssueDate'])),
307
                        'Response_DateTime'      => $arrayData['FileDateTime'],
308
                        'Document_Currency_Code' => $arrayAttr['DocumentCurrencyCode'],
309
                        'Amount_wo_VAT'          => $arrayAttr['wo_VAT'],
310
                        'Amount_TOTAL'           => $arrayAttr['TOTAL'],
311
                        'Amount_VAT'             => round(($arrayAttr['TOTAL'] - $arrayAttr['wo_VAT']), 2),
312
                        'Supplier_CUI'           => $this->setDataSupplierOrCustomer($arrayAttr['Supplier']),
313
                        'Supplier_Name'          => $arrayAttr['Supplier']['PartyLegalEntity']['RegistrationName'],
314
                        'Customer_CUI'           => $this->setDataSupplierOrCustomer($arrayAttr['Customer']),
315
                        'Customer_Name'          => $arrayAttr['Customer']['PartyLegalEntity']['RegistrationName'],
316
                        'No_of_Lines'            => $arrayAttr['No_of_Lines'],
317
                        'Days_Between'           => $this->setDaysElapsed($arrayAttr['IssueDate'], $arrayData['FileDateTime']),
318
                    ];
319
                    $arrayOptionalTags = [
320
                        'InvoicePeriod_StartDate',
321
                        'InvoicePeriod_EndDate',
322
                        'ContractDocumentReference_ID',
323
                    ];
324
                    foreach ($arrayOptionalTags as $strKey) {
325
                        if (array_key_exists($strKey, $arrayAttr)) {
326
                            $arrayTemp[$strKey] = $arrayAttr[$strKey];
327
                        }
328
                    }
329
                    $arrayToReturn = array_merge($arrayToReturn, $arrayTemp);
330
                    break;
331
            }
332
        }
333
        return $arrayToReturn;
334
    }
335
}
336