These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace NFePHP\CTe; |
||
4 | |||
5 | /** |
||
6 | * Class responsible for communication with SEFAZ extends |
||
7 | * NFePHP\CTe\Common\Tools |
||
8 | * |
||
9 | * @category NFePHP |
||
10 | * @package NFePHP\CTe\Tools |
||
11 | * @copyright NFePHP Copyright (c) 2008-2017 |
||
12 | * @license http://www.gnu.org/licenses/lgpl.txt LGPLv3+ |
||
13 | * @license https://opensource.org/licenses/MIT MIT |
||
14 | * @license http://www.gnu.org/licenses/gpl.txt GPLv3+ |
||
15 | * @author Roberto L. Machado <linux.rlm at gmail dot com> |
||
16 | * @link http://github.com/nfephp-org/sped-cte for the canonical source repository |
||
17 | */ |
||
18 | |||
19 | use NFePHP\Common\Strings; |
||
20 | use NFePHP\Common\Signer; |
||
21 | use NFePHP\Common\UFList; |
||
22 | use NFePHP\CTe\Factories\Events; |
||
23 | use NFePHP\CTe\Common\Tools as ToolsCommon; |
||
24 | use RuntimeException; |
||
25 | use InvalidArgumentException; |
||
26 | |||
27 | class Tools extends ToolsCommon |
||
28 | { |
||
29 | const EVT_CONFIRMACAO = 210200; |
||
30 | const EVT_CIENCIA = 210210; |
||
31 | const EVT_DESCONHECIMENTO = 210220; |
||
32 | const EVT_NAO_REALIZADA = 210240; |
||
33 | |||
34 | /** |
||
35 | * Request authorization to issue CTe in batch with one or more documents |
||
36 | * @param array $aXml array of cte's xml |
||
37 | * @param string $idLote lote number |
||
38 | * @param bool $compactar flag to compress data with gzip |
||
39 | * @return string soap response xml |
||
40 | */ |
||
41 | public function sefazEnviaLote( |
||
42 | $aXml, |
||
43 | $idLote = '', |
||
44 | $compactar = false, |
||
45 | &$xmls = [] |
||
46 | ) { |
||
47 | if (!is_array($aXml)) { |
||
48 | throw new \InvalidArgumentException('Os XML das CTe devem ser passados em um array.'); |
||
49 | } |
||
50 | $servico = 'CteRecepcao'; |
||
51 | $this->checkContingencyForWebServices($servico); |
||
52 | if ($this->contingency->type != '') { |
||
53 | //em modo de contingencia |
||
54 | //esses xml deverão ser modificados e re-assinados e retornados |
||
55 | //no parametro $xmls para serem armazenados pelo aplicativo |
||
56 | //pois serão alterados |
||
57 | foreach ($aXml as $doc) { |
||
58 | //corrigir o xml para o tipo de contigência setado |
||
59 | $xmls[] = $this->correctNFeForContingencyMode($doc); |
||
60 | } |
||
61 | $aXml = $xmls; |
||
62 | } |
||
63 | |||
64 | $sxml = implode("", $aXml); |
||
65 | $sxml = preg_replace("/<\?xml.*?\?>/", "", $sxml); |
||
66 | $this->servico( |
||
67 | $servico, |
||
68 | $this->config->siglaUF, |
||
69 | $this->tpAmb |
||
70 | ); |
||
71 | $request = "<enviCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
72 | . "<idLote>$idLote</idLote>" |
||
73 | . "$sxml" |
||
74 | . "</enviCTe>"; |
||
75 | $this->isValid($this->urlVersion, $request, 'enviCTe'); |
||
76 | $this->lastRequest = $request; |
||
77 | //montagem dos dados da mensagem SOAP |
||
78 | $parameters = ['cteDadosMsg' => $request]; |
||
79 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
80 | $method = $this->urlMethod; |
||
81 | if ($compactar) { |
||
82 | $gzdata = base64_encode(gzencode($cons, 9, FORCE_GZIP)); |
||
83 | $body = "<cteDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</cteDadosMsgZip>"; |
||
84 | $method = $this->urlMethod."Zip"; |
||
85 | $parameters = ['cteDadosMsgZip' => $gzdata]; |
||
86 | $body = "<cteDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</cteDadosMsgZip>"; |
||
87 | } |
||
88 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
89 | return $this->lastResponse; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Request authorization to issue CTe OS with one document only |
||
94 | * @param type $xml |
||
95 | * @return type |
||
96 | */ |
||
97 | public function sefazEnviaCTeOS($xml) |
||
98 | { |
||
99 | //carrega serviço |
||
100 | $servico = 'CteRecepcaoOS'; |
||
101 | $this->checkContingencyForWebServices($servico); |
||
102 | $this->servico( |
||
103 | $servico, |
||
104 | $this->config->siglaUF, |
||
105 | $this->tpAmb |
||
106 | ); |
||
107 | $request = preg_replace("/<\?xml.*\?>/", "", $xml); |
||
108 | $this->isValid($this->urlVersion, $request, 'cteOS'); |
||
109 | $this->lastRequest = $request; |
||
110 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
111 | $this->lastResponse = $this->sendRequest($body); |
||
112 | return $this->lastResponse; |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Check status of Batch of CTe sent by receipt of this shipment |
||
117 | * @param string $recibo |
||
118 | * @param int $tpAmb |
||
119 | * @return string |
||
120 | */ |
||
121 | public function sefazConsultaRecibo($recibo, $tpAmb = null) |
||
122 | { |
||
123 | if (empty($tpAmb)) { |
||
124 | $tpAmb = $this->tpAmb; |
||
125 | } |
||
126 | //carrega serviço |
||
127 | $servico = 'CteRetRecepcao'; |
||
128 | $this->checkContingencyForWebServices($servico); |
||
129 | $this->servico( |
||
130 | $servico, |
||
131 | $this->config->siglaUF, |
||
132 | $tpAmb |
||
133 | ); |
||
134 | if ($this->urlService == '') { |
||
135 | $msg = "A consulta de CTe não está disponível na SEFAZ {$this->config->siglaUF}!!!"; |
||
136 | throw new RuntimeException($msg); |
||
137 | } |
||
138 | $request = "<consReciCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
139 | . "<tpAmb>$tpAmb</tpAmb>" |
||
140 | . "<nRec>$recibo</nRec>" |
||
141 | . "</consReciCTe>"; |
||
142 | $this->isValid($this->urlVersion, $request, 'consReciCTe'); |
||
143 | $this->lastRequest = $request; |
||
144 | $parameters = ['cteDadosMsg' => $request]; |
||
145 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
146 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
147 | return $this->lastResponse; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Check the CTe status for the 44-digit key and retrieve the protocol |
||
152 | * @param string $chave |
||
153 | * @param int $tpAmb |
||
154 | * @return string |
||
155 | */ |
||
156 | public function sefazConsultaChave($chave, $tpAmb = null) |
||
157 | { |
||
158 | $uf = UFList::getUFByCode(substr($chave, 0, 2)); |
||
159 | if (empty($tpAmb)) { |
||
160 | $tpAmb = $this->tpAmb; |
||
161 | } |
||
162 | //carrega serviço |
||
163 | $servico = 'CteConsultaProtocolo'; |
||
164 | $this->checkContingencyForWebServices($servico); |
||
165 | $this->servico( |
||
166 | $servico, |
||
167 | $uf, |
||
168 | $tpAmb |
||
169 | ); |
||
170 | $request = "<consSitCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
171 | . "<tpAmb>$tpAmb</tpAmb>" |
||
172 | . "<xServ>CONSULTAR</xServ>" |
||
173 | . "<chCTe>$chave</chCTe>" |
||
174 | . "</consSitCTe>"; |
||
175 | $this->isValid($this->urlVersion, $request, 'consSitCTe'); |
||
176 | $this->lastRequest = $request; |
||
177 | $parameters = ['cteDadosMsg' => $request]; |
||
178 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
179 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
180 | return $this->lastResponse; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Request to disable one or an NFe sequence of a given series |
||
185 | * @param int $nSerie |
||
186 | * @param int $nIni |
||
187 | * @param int $nFin |
||
188 | * @param string $xJust |
||
189 | * @param int $tpAmb |
||
190 | * @return string |
||
191 | */ |
||
192 | public function sefazInutiliza( |
||
193 | $nSerie, |
||
194 | $nIni, |
||
195 | $nFin, |
||
196 | $xJust, |
||
197 | $tpAmb = null |
||
198 | ) { |
||
199 | if (empty($tpAmb)) { |
||
200 | $tpAmb = $this->tpAmb; |
||
201 | } |
||
202 | $xJust = Strings::replaceSpecialsChars($xJust); |
||
203 | $nSerie = (integer) $nSerie; |
||
204 | $nIni = (integer) $nIni; |
||
205 | $nFin = (integer) $nFin; |
||
206 | $servico = 'CteInutilizacao'; |
||
207 | $this->checkContingencyForWebServices($servico); |
||
208 | //carrega serviço |
||
209 | $this->servico( |
||
210 | $servico, |
||
211 | $this->config->siglaUF, |
||
212 | $tpAmb |
||
213 | ); |
||
214 | $cnpj = $this->config->cnpj; |
||
215 | $strAno = (string) date('y'); |
||
216 | $strSerie = str_pad($nSerie, 3, '0', STR_PAD_LEFT); |
||
217 | $strInicio = str_pad($nIni, 9, '0', STR_PAD_LEFT); |
||
218 | $strFinal = str_pad($nFin, 9, '0', STR_PAD_LEFT); |
||
219 | $idInut = "ID" |
||
220 | . $this->urlcUF |
||
221 | . $cnpj |
||
222 | . $this->modelo |
||
223 | . $strSerie |
||
224 | . $strInicio |
||
225 | . $strFinal; |
||
226 | //limpa os caracteres indesejados da justificativa |
||
227 | $xJust = Strings::replaceSpecialsChars($xJust); |
||
228 | //montagem do corpo da mensagem |
||
229 | $msg = "<inutCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" . |
||
230 | "<infInut Id=\"$idInut\">" . |
||
231 | "<tpAmb>$tpAmb</tpAmb>" . |
||
232 | "<xServ>INUTILIZAR</xServ>" . |
||
233 | "<cUF>$this->urlcUF</cUF>" . |
||
234 | "<ano>$strAno</ano>" . |
||
235 | "<CNPJ>$cnpj</CNPJ>" . |
||
236 | "<mod>$this->modelo</mod>" . |
||
237 | "<serie>$nSerie</serie>" . |
||
238 | "<nCTIni>$nIni</nCTIni>" . |
||
239 | "<nCTFin>$nFin</nCTFin>" . |
||
240 | "<xJust>$xJust</xJust>" . |
||
241 | "</infInut></inutCTe>"; |
||
242 | //assina a solicitação |
||
243 | $request = Signer::sign( |
||
244 | $this->certificate, |
||
245 | $msg, |
||
246 | 'infInut', |
||
247 | 'Id', |
||
248 | $this->algorithm, |
||
249 | $this->canonical |
||
250 | ); |
||
251 | $request = Strings::clearXmlString($request, true); |
||
252 | $this->isValid($this->urlVersion, $request, 'inutCTe'); |
||
253 | $this->lastRequest = $request; |
||
254 | $parameters = ['cteDadosMsg' => $request]; |
||
255 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
256 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
257 | return $this->lastResponse; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Search for the registration data of an NFe issuer, |
||
262 | * if in contingency mode this service will cause a |
||
263 | * Exception and remember not all Sefaz have this service available, |
||
264 | * so it will not work in some cases. |
||
265 | * @param string $uf federation unit |
||
266 | * @param string $cnpj CNPJ number (optional) |
||
267 | * @param string $iest IE number (optional) |
||
268 | * @param string $cpf CPF number (optional) |
||
269 | * @return string xml soap response |
||
270 | */ |
||
271 | public function sefazCadastro( |
||
272 | $uf, |
||
273 | $cnpj = '', |
||
274 | $iest = '', |
||
275 | $cpf = '' |
||
276 | ) { |
||
277 | if ($cnpj != '') { |
||
278 | $filter = "<CNPJ>$cnpj</CNPJ>"; |
||
279 | $txtFile = "CNPJ_$cnpj"; |
||
280 | } elseif ($iest != '') { |
||
281 | $filter = "<IE>$iest</IE>"; |
||
282 | $txtFile = "IE_$iest"; |
||
283 | } else { |
||
284 | $filter = "<CPF>$cpf</CPF>"; |
||
285 | $txtFile = "CPF_$cpf"; |
||
286 | } |
||
287 | //carrega serviço |
||
288 | $servico = 'CteConsultaCadastro'; |
||
289 | $this->checkContingencyForWebServices($servico); |
||
290 | $this->servico( |
||
291 | $servico, |
||
292 | $uf, |
||
293 | $this->tpAmb, |
||
294 | true |
||
295 | ); |
||
296 | $request = "<ConsCad xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
297 | . "<infCons>" |
||
298 | . "<xServ>CONS-CAD</xServ>" |
||
299 | . "<UF>$uf</UF>" |
||
300 | . "$filter</infCons></ConsCad>"; |
||
301 | $this->isValid($this->urlVersion, $request, 'consCad'); |
||
302 | $this->lastRequest = $request; |
||
303 | $parameters = ['cteDadosMsg' => $request]; |
||
304 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
305 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
306 | return $this->lastResponse; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Check services status SEFAZ/SVC |
||
311 | * If $uf is empty use normal check with contingency |
||
312 | * If $uf is NOT empty ignore contingency mode |
||
313 | * @param string $uf initials of federation unit |
||
314 | * @param int $tpAmb |
||
315 | * @return string xml soap response |
||
316 | */ |
||
317 | public function sefazStatus($uf = '', $tpAmb = null) |
||
318 | { |
||
319 | if (empty($tpAmb)) { |
||
320 | $tpAmb = $this->tpAmb; |
||
321 | } |
||
322 | $ignoreContingency = true; |
||
323 | if (empty($uf)) { |
||
324 | $uf = $this->config->siglaUF; |
||
325 | $ignoreContingency = false; |
||
326 | } |
||
327 | $servico = 'CteStatusServico'; |
||
328 | $this->checkContingencyForWebServices($servico); |
||
329 | $this->servico( |
||
330 | $servico, |
||
331 | $uf, |
||
332 | $tpAmb, |
||
333 | $ignoreContingency |
||
334 | ); |
||
335 | $request = "<consStatServCte xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
336 | . "<tpAmb>$tpAmb</tpAmb>" |
||
337 | . "<xServ>STATUS</xServ></consStatServCte>"; |
||
338 | $this->isValid($this->urlVersion, $request, 'consStatServCte'); |
||
339 | $this->lastRequest = $request; |
||
340 | $parameters = ['cteDadosMsg' => $request]; |
||
341 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
342 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
343 | return $this->lastResponse; |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * Service for the distribution of summary information and |
||
348 | * electronic tax documents of interest to an actor. |
||
349 | * @param integer $ultNSU last NSU number recived |
||
350 | * @param integer $numNSU NSU number you wish to consult |
||
351 | * @param string $fonte data source 'AN' and for some cases it may be 'RS' |
||
352 | * @return string |
||
353 | */ |
||
354 | public function sefazDistDFe( |
||
355 | $ultNSU = 0, |
||
356 | $numNSU = 0, |
||
357 | $fonte = 'AN' |
||
358 | ) { |
||
359 | //carrega serviço |
||
360 | $servico = 'CTeDistribuicaoDFe'; |
||
361 | $this->checkContingencyForWebServices($servico); |
||
362 | $this->servico( |
||
363 | $servico, |
||
364 | $fonte, |
||
365 | $this->tpAmb, |
||
366 | true |
||
367 | ); |
||
368 | $cUF = UFList::getCodeByUF($this->config->siglaUF); |
||
369 | $ultNSU = str_pad($ultNSU, 15, '0', STR_PAD_LEFT); |
||
370 | $tagNSU = "<distNSU><ultNSU>$ultNSU</ultNSU></distNSU>"; |
||
371 | if ($numNSU != 0) { |
||
372 | $numNSU = str_pad($numNSU, 15, '0', STR_PAD_LEFT); |
||
373 | $tagNSU = "<consNSU><NSU>$numNSU</NSU></consNSU>"; |
||
374 | } |
||
375 | //monta a consulta |
||
376 | $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
377 | . "<tpAmb>".$this->tpAmb."</tpAmb>" |
||
378 | . "<cUFAutor>$cUF</cUFAutor>" |
||
379 | . "<CNPJ>".$this->config->cnpj."</CNPJ>$tagNSU</distDFeInt>"; |
||
380 | //valida o xml da requisição |
||
381 | $this->isValid($this->urlVersion, $consulta, 'distDFeInt'); |
||
382 | $this->lastRequest = $consulta; |
||
383 | //montagem dos dados da mensagem SOAP |
||
384 | $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>"; |
||
385 | $parameters = ['cteDistDFeInteresse' => $request]; |
||
386 | $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">" |
||
387 | . $request |
||
388 | . "</cteDistDFeInteresse>"; |
||
389 | //este webservice não requer cabeçalho |
||
390 | $this->objHeader = null; |
||
391 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
392 | return $this->lastResponse; |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * Request authorization for Letter of Correction |
||
397 | * @param string $chave |
||
398 | * @param array $infCorrecao |
||
399 | * @param int $nSeqEvento |
||
400 | * @return string |
||
401 | */ |
||
402 | public function sefazCCe($chave, $infCorrecao = [], $nSeqEvento = 1) |
||
403 | { |
||
404 | $uf = $this->validKeyByUF($chave); |
||
405 | $tpEvento = 110110; |
||
406 | $tagAdic = self::serializerCCe($infCorrecao); |
||
407 | return $this->sefazEvento( |
||
408 | $uf, |
||
409 | $chave, |
||
410 | $tpEvento, |
||
411 | $nSeqEvento, |
||
412 | $tagAdic |
||
413 | ); |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Request extension of the term of return of products of an NF-e of |
||
418 | * consignment for industrialization to order with suspension of ICMS |
||
419 | * in interstate operations |
||
420 | * @param string $chNFe |
||
421 | * @param string $nProt |
||
422 | * @param integer $tipo 1-primerio prazo, 2-segundo prazo |
||
423 | * @param array $itens |
||
424 | * @param integer $nSeqEvento |
||
425 | * @return string |
||
426 | */ |
||
427 | public function sefazEPP( |
||
428 | $chNFe, |
||
429 | $nProt, |
||
430 | $itens = array(), |
||
431 | $tipo = 1, |
||
432 | $nSeqEvento = 1 |
||
433 | ) { |
||
434 | $uf = UFList::getUFByCode(substr($chNFe, 0, 2)); |
||
435 | $tpEvento = 111500; |
||
436 | if ($tipo == 2) { |
||
437 | $tpEvento = 111501; |
||
438 | } |
||
439 | $tagAdic = "<nProt>$nProt</nProt>"; |
||
440 | foreach ($itens as $item) { |
||
441 | $tagAdic .= "<itemPedido numItem=\"" |
||
442 | . $item[0] |
||
443 | . "\"><qtdeItem>" |
||
444 | . $item[1] |
||
445 | ."</qtdeItem></itemPedido>"; |
||
446 | } |
||
447 | return $this->sefazEvento( |
||
448 | $uf, |
||
449 | $chNFe, |
||
450 | $tpEvento, |
||
451 | $nSeqEvento, |
||
452 | $tagAdic |
||
453 | ); |
||
454 | } |
||
455 | |||
456 | /** |
||
457 | * Request the cancellation of the request for an extension of the term |
||
458 | * of return of products of an NF-e of consignment for industrialization |
||
459 | * by order with suspension of ICMS in interstate operations |
||
460 | * @param string $chNFe |
||
461 | * @param string $nProt |
||
462 | * @param integer $nSeqEvento |
||
463 | * @return string |
||
464 | */ |
||
465 | public function sefazECPP( |
||
466 | $chNFe, |
||
467 | $nProt, |
||
468 | $nSeqEvento = 1 |
||
469 | ) { |
||
470 | $uf = UFList::getUFByCode(substr($chNFe, 0, 2)); |
||
471 | $tpEvento = 111502; |
||
472 | $origEvent = 111500; |
||
473 | if ($nSeqEvento == 2) { |
||
474 | $tpEvento = 111503; |
||
475 | $origEvent = 111501; |
||
476 | } |
||
477 | $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT); |
||
478 | $idPedidoCancelado = "ID$origEvent$chNFe$sSeqEvento"; |
||
479 | $tagAdic = "<idPedidoCancelado>" |
||
480 | . "$idPedidoCancelado" |
||
481 | . "</idPedidoCancelado>" |
||
482 | . "<nProt>$nProt</nProt>"; |
||
483 | return $this->sefazEvento( |
||
484 | $uf, |
||
485 | $chNFe, |
||
486 | $tpEvento, |
||
487 | $nSeqEvento, |
||
488 | $tagAdic |
||
489 | ); |
||
490 | } |
||
491 | |||
492 | /** |
||
493 | * Requires cte cancellation |
||
494 | * @param string $chave key of CTe |
||
495 | * @param string $xJust justificative 255 characters max |
||
496 | * @param string $nProt protocol number |
||
497 | * @return string |
||
498 | */ |
||
499 | public function sefazCancela($chave, $xJust, $nProt) |
||
500 | { |
||
501 | $uf = $this->validKeyByUF($chave); |
||
502 | $xJust = Strings::replaceSpecialsChars( |
||
503 | substr(trim($xJust), 0, 255) |
||
504 | ); |
||
505 | $tpEvento = 110111; |
||
506 | $nSeqEvento = 1; |
||
507 | $tagAdic = "<evCancCTe>" |
||
508 | . "<descEvento>Cancelamento</descEvento>" |
||
509 | . "<nProt>$nProt</nProt>" |
||
510 | . "<xJust>$xJust</xJust>" |
||
511 | . "</evCancCTe>"; |
||
512 | return $this->sefazEvento( |
||
513 | $uf, |
||
514 | $chave, |
||
515 | $tpEvento, |
||
516 | $nSeqEvento, |
||
517 | $tagAdic |
||
518 | ); |
||
519 | } |
||
520 | |||
521 | /** |
||
522 | * Request the registration of the manifestation of recipient |
||
523 | * @param string $chNFe |
||
524 | * @param int $tpEvento |
||
525 | * @param string $xJust Justification for not carrying out the operation |
||
526 | * @param int $nSeqEvento |
||
527 | * @return string |
||
528 | */ |
||
529 | public function sefazManifesta( |
||
530 | $chNFe, |
||
531 | $tpEvento, |
||
532 | $xJust = '', |
||
533 | $nSeqEvento = 1, |
||
534 | $ufEvento = 'RS' |
||
535 | ) { |
||
536 | $tagAdic = ''; |
||
537 | if ($tpEvento == 210240) { |
||
538 | $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255)); |
||
539 | $tagAdic = "<xJust>$xJust</xJust>"; |
||
540 | } |
||
541 | if ($tpEvento == 610110) { |
||
542 | $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255)); |
||
543 | $tagAdic = "<evPrestDesacordo>" |
||
544 | . "<descEvento>Prestação do Serviço em Desacordo</descEvento>" |
||
545 | . "<indDesacordoOper>1</indDesacordoOper>" |
||
546 | . "<xObs>$xJust</xObs>" |
||
547 | . "</evPrestDesacordo>"; |
||
548 | } |
||
549 | return $this->sefazEvento( |
||
550 | $ufEvento, |
||
551 | $chNFe, |
||
552 | $tpEvento, |
||
553 | $nSeqEvento, |
||
554 | $tagAdic |
||
555 | ); |
||
556 | } |
||
557 | |||
558 | /** |
||
559 | * Request authorization for issuance in contingency EPEC |
||
560 | * @param string $xml |
||
561 | * @return string |
||
562 | */ |
||
563 | public function sefazEPEC(&$xml) |
||
564 | { |
||
565 | $tagAdic = ''; |
||
566 | $tpEvento = 110140; |
||
567 | $nSeqEvento = 1; |
||
568 | if ($this->contingency->type !== 'EPEC') { |
||
569 | throw new \RuntimeException('A contingência EPEC deve estar ativada.'); |
||
570 | } |
||
571 | $xml = $this->correctNFeForContingencyMode($xml); |
||
572 | $dom = new \DOMDocument('1.0', 'UTF-8'); |
||
573 | $dom->preserveWhiteSpace = false; |
||
574 | $dom->formatOutput = false; |
||
575 | $dom->loadXML($xml); |
||
576 | $infNFe = $dom->getElementsByTagName('infNFe')->item(0); |
||
577 | $emit = $dom->getElementsByTagName('emit')->item(0); |
||
578 | $dest = $dom->getElementsByTagName('dest')->item(0); |
||
579 | $cOrgaoAutor = UFList::getCodeByUF($this->config->siglaUF); |
||
580 | $chNFe = substr($infNFe->getAttribute('Id'), 3, 44); |
||
581 | // EPEC |
||
582 | $dhEmi = $dom->getElementsByTagName('dhEmi')->item(0)->nodeValue; |
||
583 | $tpNF = $dom->getElementsByTagName('tpNF')->item(0)->nodeValue; |
||
584 | $emitIE = $emit->getElementsByTagName('IE')->item(0)->nodeValue; |
||
585 | $destUF = $dest->getElementsByTagName('UF')->item(0)->nodeValue; |
||
586 | $total = $dom->getElementsByTagName('total')->item(0); |
||
587 | $vNF = $total->getElementsByTagName('vNF')->item(0)->nodeValue; |
||
588 | $vICMS = $total->getElementsByTagName('vICMS')->item(0)->nodeValue; |
||
589 | $vST = $total->getElementsByTagName('vST')->item(0)->nodeValue; |
||
590 | $dID = $dest->getElementsByTagName('CNPJ')->item(0)->nodeValue; |
||
591 | if (!empty($dID)) { |
||
592 | $destID = "<CNPJ>$dID</CNPJ>"; |
||
593 | } else { |
||
594 | $dID = $dest->getElementsByTagName('CPF')->item(0)->nodeValue; |
||
595 | if (!empty($dID)) { |
||
596 | $destID = "<CPF>$dID</CPF>"; |
||
597 | } else { |
||
598 | $dID = $dest->getElementsByTagName('idEstrangeiro') |
||
599 | ->item(0) |
||
600 | ->nodeValue; |
||
601 | $destID = "<idEstrangeiro>$dID</idEstrangeiro>"; |
||
602 | } |
||
603 | } |
||
604 | $dIE = !empty($dest->getElementsByTagName('IE')->item(0)->nodeValue) ? |
||
605 | $dest->getElementsByTagName('IE')->item(0)->nodeValue : ''; |
||
606 | $destIE = ''; |
||
607 | if (!empty($dIE)) { |
||
608 | $destIE = "<IE>$dIE</IE>"; |
||
609 | } |
||
610 | $tagAdic = "<cOrgaoAutor>$cOrgaoAutor</cOrgaoAutor>" |
||
611 | . "<tpAutor>1</tpAutor>" |
||
612 | . "<verAplic>$this->verAplic</verAplic>" |
||
613 | . "<dhEmi>$dhEmi</dhEmi>" |
||
614 | . "<tpNF>$tpNF</tpNF>" |
||
615 | . "<IE>$emitIE</IE>" |
||
616 | . "<dest>" |
||
617 | . "<UF>$destUF</UF>" |
||
618 | . $destID |
||
619 | . $destIE |
||
620 | . "<vNF>$vNF</vNF>" |
||
621 | . "<vICMS>$vICMS</vICMS>" |
||
622 | . "<vST>$vST</vST>" |
||
623 | . "</dest>"; |
||
624 | |||
625 | return $this->sefazEvento( |
||
626 | 'AN', |
||
627 | $chNFe, |
||
628 | $tpEvento, |
||
629 | $nSeqEvento, |
||
630 | $tagAdic |
||
631 | ); |
||
632 | } |
||
633 | |||
634 | /** |
||
635 | * Send event to SEFAZ |
||
636 | * @param string $uf |
||
637 | * @param string $chave |
||
638 | * @param int $tpEvento |
||
639 | * @param int $nSeqEvento |
||
640 | * @param string $tagAdic |
||
641 | * @return string |
||
642 | */ |
||
643 | public function sefazEvento( |
||
644 | $uf, |
||
645 | $chave, |
||
646 | $tpEvento, |
||
647 | $nSeqEvento = 1, |
||
648 | $tagAdic = '' |
||
649 | ) { |
||
650 | $ignore = false; |
||
651 | if ($tpEvento == 110140) { |
||
652 | $ignore = true; |
||
653 | } |
||
654 | $servico = 'CteRecepcaoEvento'; |
||
655 | $this->checkContingencyForWebServices($servico); |
||
656 | $this->servico( |
||
657 | $servico, |
||
658 | $uf, |
||
659 | $this->tpAmb, |
||
660 | $ignore |
||
661 | ); |
||
662 | $ev = $this->tpEv($tpEvento); |
||
663 | $aliasEvento = $ev->alias; |
||
664 | $descEvento = $ev->desc; |
||
665 | $cnpj = $this->config->cnpj; |
||
666 | $dt = new \DateTime(); |
||
667 | $dhEvento = $dt->format('Y-m-d\TH:i:sP'); |
||
668 | $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT); |
||
669 | $eventId = "ID".$tpEvento.$chave.$sSeqEvento; |
||
670 | $cOrgao = UFList::getCodeByUF($uf); |
||
671 | |||
672 | $request = "<eventoCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
673 | . "<infEvento Id=\"$eventId\">" |
||
674 | . "<cOrgao>$cOrgao</cOrgao>" |
||
675 | . "<tpAmb>$this->tpAmb</tpAmb>" |
||
676 | . "<CNPJ>$cnpj</CNPJ>" |
||
677 | . "<chCTe>$chave</chCTe>" |
||
678 | . "<dhEvento>$dhEvento</dhEvento>" |
||
679 | . "<tpEvento>$tpEvento</tpEvento>" |
||
680 | . "<nSeqEvento>$nSeqEvento</nSeqEvento>" |
||
681 | . "<detEvento versaoEvento=\"$this->urlVersion\">" |
||
682 | . "$tagAdic" |
||
683 | . "</detEvento>" |
||
684 | . "</infEvento>" |
||
685 | . "</eventoCTe>"; |
||
686 | |||
687 | //assinatura dos dados |
||
688 | $request = Signer::sign( |
||
689 | $this->certificate, |
||
690 | $request, |
||
691 | 'infEvento', |
||
692 | 'Id', |
||
693 | $this->algorithm, |
||
694 | $this->canonical |
||
695 | ); |
||
696 | |||
697 | $request = Strings::clearXmlString($request, true); |
||
698 | // if ($tpEvento != 610110) { |
||
0 ignored issues
–
show
|
|||
699 | // $lote = $dt->format('YmdHis').rand(0, 9); |
||
700 | // $request = "<envEventoCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
701 | // . "<idLote>$lote</idLote>" |
||
702 | // . $request |
||
703 | // . "</envEventoCTe>"; |
||
704 | // } |
||
705 | $this->isValid($this->urlVersion, $request, 'eventoCTe'); |
||
706 | $this->lastRequest = $request; |
||
707 | $parameters = ['cteDadosMsg' => $request]; |
||
708 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
709 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
710 | return $this->lastResponse; |
||
711 | } |
||
712 | |||
713 | /** |
||
714 | * Request the NFe download already manifested by its recipient, by the key |
||
715 | * using new service in CTeDistribuicaoDFe |
||
716 | * @param string $chave |
||
717 | * @return string |
||
718 | */ |
||
719 | public function sefazDownload($chave) |
||
720 | { |
||
721 | //carrega serviço |
||
722 | $servico = 'CteDistribuicaoDFe'; |
||
723 | $this->checkContingencyForWebServices($servico); |
||
724 | $this->servico( |
||
725 | $servico, |
||
726 | 'AN', |
||
727 | $this->tpAmb, |
||
728 | true |
||
729 | ); |
||
730 | $cUF = UFList::getCodeByUF($this->config->siglaUF); |
||
731 | $tagChave = "<consChNFe><chNFe>$chave</chNFe></consChNFe>"; |
||
732 | //monta a consulta |
||
733 | $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" |
||
734 | . "<tpAmb>".$this->tpAmb."</tpAmb>" |
||
735 | . "<cUFAutor>$cUF</cUFAutor>" |
||
736 | . "<CNPJ>".$this->config->cnpj."</CNPJ>$tagChave</distDFeInt>"; |
||
737 | //valida o xml da requisição |
||
738 | $this->isValid($this->urlVersion, $consulta, 'distDFeInt'); |
||
739 | $this->lastRequest = $consulta; |
||
740 | //montagem dos dados da mensagem SOAP |
||
741 | $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>"; |
||
742 | $parameters = ['cteDistDFeInteresse' => $request]; |
||
743 | $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">" |
||
744 | . $request |
||
745 | . "</cteDistDFeInteresse>"; |
||
746 | //este webservice não requer cabeçalho |
||
747 | $this->objHeader = null; |
||
748 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
749 | return $this->lastResponse; |
||
750 | } |
||
751 | |||
752 | /** |
||
753 | * Maintenance of the Taxpayer Security Code - CSC (Old Token) |
||
754 | * @param int $indOp Identificador do tipo de operação: |
||
755 | * 1 - Consulta CSC Ativos; |
||
756 | * 2 - Solicita novo CSC; |
||
757 | * 3 - Revoga CSC Ativo |
||
758 | * @return string |
||
759 | */ |
||
760 | public function sefazCsc($indOp) |
||
761 | { |
||
762 | if ($this->modelo != 65) { |
||
763 | throw new RuntimeException( |
||
764 | "Esta operação é exclusiva de NFCe modelo [65], " |
||
765 | . "você está usando modelo [55]." |
||
766 | ); |
||
767 | } |
||
768 | $raizCNPJ = substr($this->config->cnpj, 0, -6); |
||
769 | //carrega serviço |
||
770 | $servico = 'CscNFCe'; |
||
771 | $this->checkContingencyForWebServices($servico); |
||
772 | $this->servico( |
||
773 | $servico, |
||
774 | $this->config->siglaUF, |
||
775 | $this->tpAmb |
||
776 | ); |
||
777 | $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">" |
||
778 | . "<tpAmb>$this->tpAmb</tpAmb>" |
||
779 | . "<indOp>$indOp</indOp>" |
||
780 | . "<raizCNPJ>$raizCNPJ</raizCNPJ>" |
||
781 | . "</admCscNFCe>"; |
||
782 | if ($indOp == 3) { |
||
783 | $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">" |
||
784 | . "<tpAmb>$this->tpAmb</tpAmb>" |
||
785 | . "<indOp>$indOp</indOp>" |
||
786 | . "<raizCNPJ>$raizCNPJ</raizCNPJ>" |
||
787 | . "<dadosCsc>" |
||
788 | . "<idCsc>".$this->config->CSCid."</idCsc>" |
||
789 | . "<codigoCsc>".$this->config->CSC."</codigoCsc>" |
||
790 | . "</dadosCsc>" |
||
791 | . "</admCscNFCe>"; |
||
792 | } |
||
793 | //o xsd não está disponivel |
||
794 | //$this->isValid($this->urlVersion, $request, 'cscNFCe'); |
||
795 | $this->lastRequest = $request; |
||
796 | $parameters = ['cteDadosMsg' => $request]; |
||
797 | $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>"; |
||
798 | $this->lastResponse = $this->sendRequest($body, $parameters); |
||
799 | return $this->lastResponse; |
||
800 | } |
||
801 | |||
802 | /** |
||
803 | * Checks the validity of an NFe, normally used for received NFe |
||
804 | * @param string $cte |
||
805 | * @return boolean |
||
806 | */ |
||
807 | public function sefazValidate($cte) |
||
808 | { |
||
809 | //verifica a assinatura da NFe, exception caso de falha |
||
810 | Signer::isSigned($cte); |
||
811 | $dom = new \DOMDocument('1.0', 'utf-8'); |
||
812 | $dom->formatOutput = false; |
||
813 | $dom->preserveWhiteSpace = false; |
||
814 | $dom->loadXML($cte); |
||
815 | //verifica a validade no webservice da SEFAZ |
||
816 | $tpAmb = $dom->getElementsByTagName('tpAmb')->item(0)->nodeValue; |
||
817 | $infNFe = $dom->getElementsByTagName('infNFe')->item(0); |
||
818 | $chNFe = preg_replace('/[^0-9]/', '', $infNFe->getAttribute("Id")); |
||
819 | $protocol = $dom->getElementsByTagName('nProt')->item(0)->nodeValue; |
||
820 | $digval = $dom->getElementsByTagName('DigestValue')->item(0)->nodeValue; |
||
821 | //consulta a NFe |
||
822 | $response = $this->sefazConsultaChave($chNFe, $tpAmb); |
||
823 | $ret = new \DOMDocument('1.0', 'UTF-8'); |
||
824 | $ret->preserveWhiteSpace = false; |
||
825 | $ret->formatOutput = false; |
||
826 | $ret->loadXML($response); |
||
827 | $retProt = $ret->getElementsByTagName('protNFe')->item(0); |
||
828 | if (!isset($retProt)) { |
||
829 | throw new InvalidArgumentException( |
||
830 | 'O documento de resposta não contêm o NODE "protNFe".' |
||
831 | ); |
||
832 | } |
||
833 | $infProt = $ret->getElementsByTagName('infProt')->item(0); |
||
834 | $cStat = $infProt->getElementsByTagName('cStat')->item(0)->nodeValue; |
||
835 | $xMotivo = $infProt->getElementsByTagName('xMotivo')->item(0)->nodeValue; |
||
836 | $dig = $infProt->getElementsByTagName("digVal")->item(0); |
||
837 | $digProt = '000'; |
||
838 | if (isset($dig)) { |
||
839 | $digProt = $dig->nodeValue; |
||
840 | } |
||
841 | $chProt = $infProt->getElementsByTagName("chNFe")->item(0)->nodeValue; |
||
842 | $nProt = $infProt->getElementsByTagName("nProt")->item(0)->nodeValue; |
||
843 | if ($protocol == $nProt |
||
844 | && $digval == $digProt |
||
845 | && $chNFe == $chProt |
||
846 | ) { |
||
847 | return true; |
||
848 | } |
||
849 | return false; |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * |
||
854 | * @param int $tpEvento |
||
855 | * @return \stdClass |
||
856 | * @throws Exception |
||
857 | */ |
||
858 | private function tpEv($tpEvento) |
||
859 | { |
||
860 | $std = new \stdClass(); |
||
861 | $std->alias = ''; |
||
862 | $std->desc = ''; |
||
863 | switch ($tpEvento) { |
||
864 | case 110110: |
||
865 | //CCe |
||
866 | $std->alias = 'CCe'; |
||
867 | $std->desc = 'Carta de Correcao'; |
||
868 | break; |
||
869 | case 110111: |
||
870 | //cancelamento |
||
871 | $std->alias = 'CancCTe'; |
||
872 | $std->desc = 'Cancelamento'; |
||
873 | break; |
||
874 | case 110140: |
||
875 | //EPEC |
||
876 | //emissão em contingência EPEC |
||
877 | $std->alias = 'EPEC'; |
||
878 | $std->desc = 'EPEC'; |
||
879 | break; |
||
880 | case 111500: |
||
881 | case 111501: |
||
882 | //EPP |
||
883 | //Pedido de prorrogação |
||
884 | $std->alias = 'EPP'; |
||
885 | $std->desc = 'Pedido de Prorrogacao'; |
||
886 | break; |
||
887 | case 111502: |
||
888 | case 111503: |
||
889 | //ECPP |
||
890 | //Cancelamento do Pedido de prorrogação |
||
891 | $std->alias = 'ECPP'; |
||
892 | $std->desc = 'Cancelamento de Pedido de Prorrogacao'; |
||
893 | break; |
||
894 | case 210200: |
||
895 | //Confirmacao da Operacao |
||
896 | $std->alias = 'EvConfirma'; |
||
897 | $std->desc = 'Confirmacao da Operacao'; |
||
898 | break; |
||
899 | case 210210: |
||
900 | //Ciencia da Operacao |
||
901 | $std->alias = 'EvCiencia'; |
||
902 | $std->desc = 'Ciencia da Operacao'; |
||
903 | $std->tpAutor = 2; |
||
904 | break; |
||
905 | case 210220: |
||
906 | //Desconhecimento da Operacao |
||
907 | $std->alias = 'EvDesconh'; |
||
908 | $std->desc = 'Desconhecimento da Operacao'; |
||
909 | break; |
||
910 | case 210240: |
||
911 | //Operacao não Realizada |
||
912 | $std->alias = 'EvNaoRealizada'; |
||
913 | $std->desc = 'Operacao nao Realizada'; |
||
914 | break; |
||
915 | case 610110: |
||
916 | //Serviço em desacordo |
||
917 | $std->alias = 'EvPrestDesacordo'; |
||
918 | $std->desc = 'Servico em desacordo'; |
||
919 | break; |
||
920 | default: |
||
921 | $msg = "O código do tipo de evento informado não corresponde a " |
||
922 | . "nenhum evento estabelecido."; |
||
923 | throw new RuntimeException($msg); |
||
924 | } |
||
925 | return $std; |
||
926 | } |
||
927 | |||
928 | private static function serializerCCe(array $infCorrecoes) |
||
929 | { |
||
930 | // Grupo de Informações de Correção |
||
931 | $correcoes = ''; |
||
932 | foreach ($infCorrecoes as $info) { |
||
933 | $nroItemAlteradoOptionalElement = ''; |
||
934 | if (key_exists('nroItemAlterado', $info)) { |
||
935 | $nroItemAlteradoOptionalElement = "<nroItemAlterado>{$info['nroItemAlterado']}</nroItemAlterado>"; |
||
936 | } |
||
937 | $correcoes .= "<infCorrecao>" . |
||
938 | "<grupoAlterado>{$info['grupoAlterado']}</grupoAlterado>" . |
||
939 | "<campoAlterado>{$info['campoAlterado']}</campoAlterado>" . |
||
940 | "<valorAlterado>{$info['valorAlterado']}</valorAlterado>" . |
||
941 | "{$nroItemAlteradoOptionalElement}" . |
||
942 | "</infCorrecao>"; |
||
943 | } |
||
944 | //monta mensagem |
||
945 | return "<evCCeCTe>" . |
||
946 | "<descEvento>Carta de Correcao</descEvento>" . |
||
947 | "{$correcoes}" . |
||
948 | "<xCondUso>" . |
||
949 | "A Carta de Correcao e disciplinada pelo Art. 58-B do " . |
||
950 | "CONVENIO/SINIEF 06/89: Fica permitida a utilizacao de carta de " . |
||
951 | "correcao, para regularizacao de erro ocorrido na emissao de " . |
||
952 | "documentos fiscais relativos a prestacao de servico de transporte, " . |
||
953 | "desde que o erro nao esteja relacionado com: I - as variaveis que " . |
||
954 | "determinam o valor do imposto tais como: base de calculo, " . |
||
955 | "aliquota, diferenca de preco, quantidade, valor da prestacao;II - " . |
||
956 | "a correcao de dados cadastrais que implique mudanca do emitente, " . |
||
957 | "tomador, remetente ou do destinatario;III - a data de emissao ou " . |
||
958 | "de saida." . |
||
959 | "</xCondUso>" . |
||
960 | "</evCCeCTe>"; |
||
961 | } |
||
962 | } |
||
963 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.