Test Setup Failed
Push — master ( 947c79...20ba58 )
by
unknown
34s queued 10s
created

Tools::checkContingencyForWebServices()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 0
cts 13
cp 0
rs 9.6666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 12
1
<?php
2
3
namespace NFePHP\CTe\Common;
4
5
/**
6
 * Class base responsible for communication with SEFAZ
7
 *
8
 * @category  NFePHP
9
 * @package   NFePHP\CTe\Common\Tools
10
 * @copyright NFePHP Copyright (c) 2008-2017
11
 * @license   http://www.gnu.org/licenses/lgpl.txt LGPLv3+
12
 * @license   https://opensource.org/licenses/MIT MIT
13
 * @license   http://www.gnu.org/licenses/gpl.txt GPLv3+
14
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
15
 * @link      http://github.com/nfephp-org/sped-nfe for the canonical source repository
16
 */
17
18
use DOMDocument;
19
use InvalidArgumentException;
20
use NFePHP\Common\Certificate;
21
use NFePHP\Common\Signer;
22
use NFePHP\Common\Soap\SoapCurl;
23
use NFePHP\Common\Soap\SoapInterface;
24
use NFePHP\Common\Strings;
25
use NFePHP\Common\TimeZoneByUF;
26
use NFePHP\Common\UFList;
27
use NFePHP\Common\Validator;
28
use NFePHP\CTe\Factories\Contingency;
29
use NFePHP\CTe\Factories\ContingencyCTe;
30
use NFePHP\CTe\Factories\Header;
31
use NFePHP\CTe\Factories\QRCode;
32
use RuntimeException;
33
34
class Tools
35
{
36
    /**
37
     * config class
38
     * @var \stdClass
39
     */
40
    public $config;
41
    /**
42
     * Path to storage folder
43
     * @var string
44
     */
45
    public $pathwsfiles = '';
46
    /**
47
     * Path to schemes folder
48
     * @var string
49
     */
50
    public $pathschemes = '';
51
    /**
52
     * ambiente
53
     * @var string
54
     */
55
    public $ambiente = 'homologacao';
56
    /**
57
     * Environment
58
     * @var int
59
     */
60
    public $tpAmb = 2;
61
    /**
62
     * contingency class
63
     * @var Contingency
64
     */
65
    public $contingency;
66
    /**
67
     * soap class
68
     * @var SoapInterface
69
     */
70
    public $soap;
71
    /**
72
     * Application version
73
     * @var string
74
     */
75
    public $verAplic = '';
76
    /**
77
     * last soap request
78
     * @var string
79
     */
80
    public $lastRequest = '';
81
    /**
82
     * last soap response
83
     * @var string
84
     */
85
    public $lastResponse = '';
86
    /**
87
     * certificate class
88
     * @var Certificate
89
     */
90
    protected $certificate;
91
    /**
92
     * Sign algorithm from OPENSSL
93
     * @var int
94
     */
95
    protected $algorithm = OPENSSL_ALGO_SHA1;
96
    /**
97
     * Canonical conversion options
98
     * @var array
99
     */
100
    protected $canonical = [true, false, null, null];
101
    /**
102
     * Model of CTe 57 or 67
103
     * @var int
104
     */
105
    protected $modelo = 57;
106
    /**
107
     * Version of layout
108
     * @var string
109
     */
110
    protected $versao = '3.00';
111
    /**
112
     * urlPortal
113
     * Instância do WebService
114
     *
115
     * @var string
116
     */
117
    protected $urlPortal = 'http://www.portalfiscal.inf.br/cte';
118
    /**
119
     * urlcUF
120
     * @var string
121
     */
122
    protected $urlcUF = '';
123
    /**
124
     * urlVersion
125
     * @var string
126
     */
127
    protected $urlVersion = '';
128
    /**
129
     * urlService
130
     * @var string
131
     */
132
    protected $urlService = '';
133
    /**
134
     * @var string
135
     */
136
    protected $urlMethod = '';
137
    /**
138
     * @var string
139
     */
140
    protected $urlOperation = '';
141
    /**
142
     * @var string
143
     */
144
    protected $urlNamespace = '';
145
    /**
146
     * @var string
147
     */
148
    protected $urlAction = '';
149
    /**
150
     * @var \SOAPHeader
151
     */
152
    protected $objHeader;
153
    /**
154
     * @var string
155
     */
156
    protected $urlHeader = '';
157
    /**
158
     * @var array
159
     */
160
    protected $soapnamespaces = [
161
        'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
162
        'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema",
163
        'xmlns:soap' => "http://www.w3.org/2003/05/soap-envelope"
164
    ];
165
    /**
166
     * @var array
167
     */
168
    protected $availableVersions = [
169
        '3.00' => 'PL_CTe_300a'
170
    ];
171
172
    /**
173
     * Constructor
174
     * load configurations,
175
     * load Digital Certificate,
176
     * map all paths,
177
     * set timezone and
178
     * and instanciate Contingency::class
179
     * @param string $configJson content of config in json format
180
     * @param Certificate $certificate
181
     */
182
    public function __construct($configJson, Certificate $certificate)
183
    {
184
        $this->config = json_decode($configJson);
185
        $this->pathwsfiles = realpath(
186
                __DIR__ . '/../../storage'
187
            ) . '/';
188
        $this->version($this->config->versao);
189
        $this->setEnvironmentTimeZone($this->config->siglaUF);
190
        $this->certificate = $certificate;
191
        $this->setEnvironment($this->config->tpAmb);
192
        $this->contingency = new Contingency();
193
    }
194
195
    /**
196
     * Sets environment time zone
197
     * @param string $acronym (ou seja a sigla do estado)
198
     * @return void
199
     */
200
    public function setEnvironmentTimeZone($acronym)
201
    {
202
        date_default_timezone_set(TimeZoneByUF::get($acronym));
203
    }
204
205
    /**
206
     * Set application version
207
     * @param string $ver
208
     */
209
    public function setVerAplic($ver)
210
    {
211
        $this->verAplic = $ver;
212
    }
213
214
    /**
215
     * Load Soap Class
216
     * Soap Class may be \NFePHP\Common\Soap\SoapNative
217
     * or \NFePHP\Common\Soap\SoapCurl
218
     * @param SoapInterface $soap
219
     * @return void
220
     */
221
    public function loadSoapClass(SoapInterface $soap)
222
    {
223
        $this->soap = $soap;
224
        $this->soap->loadCertificate($this->certificate);
225
    }
226
227
    /**
228
     * Set OPENSSL Algorithm using OPENSSL constants
229
     * @param int $algorithm
230
     * @return void
231
     */
232
    public function setSignAlgorithm($algorithm = OPENSSL_ALGO_SHA1)
233
    {
234
        $this->algorithm = $algorithm;
235
    }
236
237
    /**
238
     * Set or get model of document CTe = 57 or CTeOS = 67
239
     * @param int $model
240
     * @return int modelo class parameter
241
     */
242
    public function model($model = null)
243
    {
244
        if ($model == 57 || $model == 67) {
245
            $this->modelo = $model;
246
        }
247
        return $this->modelo;
248
    }
249
250
    /**
251
     * Set or get parameter layout version
252
     * @param string $version
253
     * @return string
254
     * @throws InvalidArgumentException
255
     */
256
    public function version($version = '')
257
    {
258
        if (!empty($version)) {
259
            if (!array_key_exists($version, $this->availableVersions)) {
260
                throw new \InvalidArgumentException('Essa versão de layout não está disponível');
261
            }
262
            $this->versao = $version;
263
            $this->config->schemes = $this->availableVersions[$version];
264
            $this->pathschemes = realpath(
265
                    __DIR__ . '/../../schemes/' . $this->config->schemes
266
                ) . '/';
267
        }
268
        return $this->versao;
269
    }
270
271
    /**
272
     * Recover cUF number from state acronym
273
     * @param string $acronym Sigla do estado
274
     * @return int number cUF
275
     */
276
    public function getcUF($acronym)
277
    {
278
        return UFlist::getCodeByUF($acronym);
279
    }
280
281
    /**
282
     * Recover state acronym from cUF number
283
     * @param int $cUF
284
     * @return string acronym sigla
285
     */
286
    public function getAcronym($cUF)
287
    {
288
        return UFlist::getUFByCode($cUF);
289
    }
290
291
    /**
292
     * Validate cUF from the key content and returns the state acronym
293
     * @param string $chave
294
     * @return string
295
     * @throws InvalidArgumentException
296
     */
297
    public function validKeyByUF($chave)
298
    {
299
        $uf = $this->config->siglaUF;
300
        if ($uf != UFList::getUFByCode(substr($chave, 0, 2))) {
301
            throw new \InvalidArgumentException(
302
                "A chave do CTe indicado [$chave] não pertence a [$uf]."
303
            );
304
        }
305
        return $uf;
306
    }
307
308
    /**
309
     * Sign CTe
310
     * @param  string $xml CTe xml content
311
     * @return string singed CTe xml
312
     * @throws RuntimeException
313
     */
314
    public function signCTe($xml)
315
    {
316
        //remove all invalid strings
317
        $xml = Strings::clearXmlString($xml);
318
        $signed = Signer::sign(
319
            $this->certificate,
320
            $xml,
321
            'infCte',
322
            'Id',
323
            $this->algorithm,
324
            $this->canonical
325
        );
326
        $dom = new DOMDocument('1.0', 'UTF-8');
327
        $dom->preserveWhiteSpace = false;
328
        $dom->formatOutput = false;
329
        $dom->loadXML($signed);
330
        //exception will be throw if CTe is not valid
331
        $modelo = $dom->getElementsByTagName('mod')->item(0)->nodeValue;
332
        $method = 'cte';
333
        if ($modelo == 67) {
334
            $method = 'cteOS';
335
        }
336
        $isInfCTeSupl = !empty($dom->getElementsByTagName('infCTeSupl')->item(0));
337
        if (!$isInfCTeSupl) {
338
            $signed = $this->addQRCode($dom);
339
        }
340
        $this->isValid($this->versao, $signed, $method);
341
        return $signed;
342
    }
343
344
    /**
345
     * @todo
346
     * Corret NFe fields when in contingency mode is set
347
     * @param string $xml CTe xml content
348
     * @return string
349
     */
350
    protected function correctCTeForContingencyMode($xml)
351
    {
352
        if ($this->contingency->type == '') {
353
            return $xml;
354
        }
355
        $xml = ContingencyCTe::adjust($xml, $this->contingency);
356
        return $this->signCTe($xml);
357
    }
358
359
    /**
360
     * Performs xml validation with its respective
361
     * XSD structure definition document
362
     * NOTE: if dont exists the XSD file will return true
363
     * @param string $version layout version
364
     * @param string $body
365
     * @param string $method
366
     * @return boolean
367
     */
368
    protected function isValid($version, $body, $method)
369
    {
370
        $schema = $this->pathschemes . $method . "_v$version.xsd";
371
        if (!is_file($schema)) {
372
            return true;
373
        }
374
        return Validator::isValid(
375
            $body,
376
            $schema
377
        );
378
    }
379
380
    /**
381
     * Verifies the existence of the service
382
     * @param string $service
383
     * @throws RuntimeException
384
     */
385
    protected function checkContingencyForWebServices($service)
0 ignored issues
show
Unused Code introduced by
The parameter $service is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
386
    {
387
        $permit = [
388
            57 => ['SVSP', 'SVRS'],
389
            67 => ['SVSP', 'SVRS']
390
        ];
391
392
        $type = $this->contingency->type;
393
        $mod = $this->modelo;
394
        if (!empty($type)) {
395
            if (array_search($type, $permit[$mod]) === false) {
396
                throw new RuntimeException(
397
                    "Esse modo de contingência [$type] não é aceito "
398
                    . "para o modelo [$mod]"
399
                );
400
            }
401
        }
402
    }
403
404
    /**
405
     * Alter environment from "homologacao" to "producao" and vice-versa
406
     * @param int $tpAmb
407
     * @return void
408
     */
409
    public function setEnvironment($tpAmb = 2)
410
    {
411
        if (!empty($tpAmb) && ($tpAmb == 1 || $tpAmb == 2)) {
412
            $this->tpAmb = $tpAmb;
413
            $this->ambiente = ($tpAmb == 1) ? 'producao' : 'homologacao';
414
        }
415
    }
416
417
    /**
418
     * Set option for canonical transformation see C14n
419
     * @param array $opt
420
     * @return array
421
     */
422
    public function canonicalOptions($opt = [true, false, null, null])
423
    {
424
        if (!empty($opt) && is_array($opt)) {
425
            $this->canonical = $opt;
426
        }
427
        return $this->canonical;
428
    }
429
430
    /**
431
     * Assembles all the necessary parameters for soap communication
432
     * @param string $service
433
     * @param string $uf
434
     * @param string $tpAmb
435
     * @param bool $ignoreContingency
436
     * @return void
437
     */
438
    protected function servico(
439
        $service,
440
        $uf,
441
        $tpAmb,
442
        $ignoreContingency = false
443
    )
444
    {
445
        $ambiente = $tpAmb == 1 ? "producao" : "homologacao";
446
        $webs = new Webservices($this->getXmlUrlPath());
447
        $sigla = $uf;
448
        if (!$ignoreContingency) {
449
            $contType = $this->contingency->type;
450
            if (!empty($contType)
451
                && ($contType == 'SVRS' || $contType == 'SVSP')
452
            ) {
453
                $sigla = $contType;
454
            }
455
        }
456
        $stdServ = $webs->get($sigla, $ambiente, $this->modelo);
457
        if ($stdServ === false) {
458
            throw new \RuntimeException(
459
                "Nenhum serviço foi localizado para esta unidade "
460
                . "da federação [$sigla], com o modelo [$this->modelo]."
461
            );
462
        }
463
        if (empty($stdServ->$service->url)) {
464
            throw new \RuntimeException(
465
                "Este serviço [$service] não está disponivel para esta "
466
                . "unidade da federação [$uf] ou para este modelo de Nota ["
467
                . $this->modelo
468
                . "]."
469
            );
470
        }
471
        //recuperação do cUF
472
        $this->urlcUF = $this->getcUF($uf);
0 ignored issues
show
Documentation Bug introduced by
The property $urlcUF was declared of type string, but $this->getcUF($uf) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
473
        if ($this->urlcUF > 91) {
474
            //foi solicitado dado de SVRS ou SVSP
475
            $this->urlcUF = $this->getcUF($this->config->siglaUF);
0 ignored issues
show
Documentation Bug introduced by
The property $urlcUF was declared of type string, but $this->getcUF($this->config->siglaUF) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
476
        }
477
        //recuperação da versão
478
        $this->urlVersion = $stdServ->$service->version;
479
        //recuperação da url do serviço
480
        $this->urlService = $stdServ->$service->url;
481
        //recuperação do método
482
        $this->urlMethod = $stdServ->$service->method;
483
        //recuperação da operação
484
        $this->urlOperation = $stdServ->$service->operation;
485
        //montagem do namespace do serviço
486
        $this->urlNamespace = sprintf(
487
            "%s/wsdl/%s",
488
            $this->urlPortal,
489
            $this->urlOperation
490
        );
491
        //montagem do cabeçalho da comunicação SOAP
492
        $this->urlHeader = Header::get(
493
            $this->urlNamespace,
494
            $this->urlcUF,
495
            $this->urlVersion
496
        );
497
        $this->urlAction = "\""
498
            . $this->urlNamespace
499
            . "/"
500
            . $this->urlMethod
501
            . "\"";
502
        //montagem do SOAP Header
503
        $this->objHeader = new \SOAPHeader(
504
            $this->urlNamespace,
505
            'cteCabecMsg',
506
            ['cUF' => $this->urlcUF, 'versaoDados' => $this->urlVersion]
507
        );
508
    }
509
510
    /**
511
     * Send request message to webservice
512
     * @param array $parameters
513
     * @param string $request
514
     * @return string
515
     */
516
    protected function sendRequest($request, array $parameters = [])
517
    {
518
        $this->checkSoap();
519
        return (string)$this->soap->send(
520
            $this->urlService,
521
            $this->urlMethod,
522
            $this->urlAction,
523
            SOAP_1_2,
524
            $parameters,
525
            $this->soapnamespaces,
526
            $request,
527
            $this->objHeader
528
        );
529
    }
530
531
    /**
532
     * Recover path to xml data base with list of soap services
533
     * @return string
534
     */
535
    protected function getXmlUrlPath()
536
    {
537
        $file = $this->pathwsfiles
538
            . DIRECTORY_SEPARATOR
539
            . "wscte_" . $this->versao . "_mod57.xml";
540
        if (!file_exists($file)) {
541
            return '';
542
        }
543
        return file_get_contents($file);
544
    }
545
546
    /**
547
     * Add QRCode Tag to signed XML from a NFCe
548
     * @param DOMDocument $dom
549
     * @return string
550
     */
551
    protected function addQRCode(DOMDocument $dom)
552
    {
553
        $signed = QRCode::putQRTag(
554
            $dom
555
        );
556
        return Strings::clearXmlString($signed);
557
    }
558
559
    /**
560
     * Verify if SOAP class is loaded, if not, force load SoapCurl
561
     */
562
    protected function checkSoap()
563
    {
564
        if (empty($this->soap)) {
565
            $this->soap = new SoapCurl($this->certificate);
566
        }
567
    }
568
}
569