@@ -383,23 +383,46 @@ public function consume(
383383 $ options [\GuzzleHttp \RequestOptions::JSON ] = $ data ;
384384 }
385385
386+ // realizar consulta HTTP con reintento por si falla la sesión del SII.
387+ foreach ([true , false ] as $ auth_cache ) {
388+
389+ // Forzar el valor de auth_cache en la llamada a la API.
390+ $ this ->last_url = $ this ->forceUrlParams ($ this ->last_url , [
391+ 'auth_cache ' => (int )$ auth_cache ,
392+ ]);
393+
386394 // Ejecutar consulta al SII.
387395 try {
388396 $ this ->last_response = $ client ->request (
389397 method: $ method ,
390398 uri: $ this ->last_url ,
391399 options: $ options
392400 );
393- } catch (\GuzzleHttp \Exception \RequestException $ e ) {
394- if ( $ e -> hasResponse ()) {
401+ } catch (\GuzzleHttp \Exception \BadResponseException $ e ) {
402+ // Obtener la respuesta de la llamada.
395403 $ this ->last_response = $ e ->getResponse ();
404+
405+ // Si es un error HTTP 401 con problema de sesión pasamos a la otra iteración
406+ // del ciclo foreach para reintentar sin caché de sesión del SII.
407+ if ($ this ->getLastResponse ()->getStatusCode () == 401 ) {
408+ if ($ this ->getLastResponse ()->getHeaderLine ('X-Stats-NavegadorSessionProblem ' )) {
409+ continue ;
410+ }
411+ }
412+
413+ // Si no es un error 401 con problema de sesión se lanza la excepción.
414+ $ this ->throwException ();
415+ } catch (\GuzzleHttp \Exception \GuzzleException $ e ) {
416+ throw new ApiException ('Error de conexión con el SII: ' . $ e ->getMessage (), 500 );
417+ }
418+
419+ // Break obligatorio, ya que si la llamada es exitosa no se debe reintentar.
420+ if ($ this ->getLastResponse ()->getStatusCode () == 200 ) {
421+ break ;
396422 }
423+
424+ // Si no se reintentó se lanza excepción por no ser código 200 (break anterior).
397425 $ this ->throwException ();
398- } catch (\GuzzleHttp \Exception \ConnectException $ e ) {
399- throw new ApiException (
400- message: 'Error de conexión con el SII: ' . $ e ->getMessage (),
401- code: 500
402- );
403426 }
404427
405428 // Entregar respuesta (contenida en el mismo objeto del cliente).
@@ -468,4 +491,37 @@ private function env(string $name)
468491 {
469492 return function_exists ('env ' ) ? env ($ name ) : getenv ($ name );
470493 }
494+
495+ /**
496+ * Fuerza parámetros específicos en la URL dada.
497+ *
498+ * @param string $url La URL original a modificar.
499+ * @param array $params Arreglo asociativo de parámetros para añadir a la URL.
500+ * @return string La URL modificada con los nuevos parámetros.
501+ */
502+ private function forceUrlParams (string $ url , array $ params ): string
503+ {
504+ // Parsear la URL para extraer componentes.
505+ $ parsedUrl = parse_url ($ url );
506+
507+ // Parsear la cadena de consulta existente y obtener los parámetros actuales.
508+ parse_str ($ parsedUrl ['query ' ] ?? '' , $ queryParams );
509+
510+ // Fusionar los parámetros existentes con los nuevos parámetros forzados.
511+ $ queryParams = array_merge ($ queryParams , $ params );
512+
513+ // Reconstruir la cadena de consulta con los nuevos parámetros.
514+ $ parsedUrl ['query ' ] = http_build_query ($ queryParams );
515+
516+ // Reconstruir y devolver la URL completa.
517+ return (isset ($ parsedUrl ['scheme ' ]) ? "{$ parsedUrl ['scheme ' ]}:// " : '' ) .
518+ (isset ($ parsedUrl ['user ' ]) ? "{$ parsedUrl ['user ' ]}" . (isset ($ parsedUrl ['pass ' ]) ? ": {$ parsedUrl ['pass ' ]}" : '' ) .'@ ' : '' ) .
519+ (isset ($ parsedUrl ['host ' ]) ? "{$ parsedUrl ['host ' ]}" : '' ) .
520+ (isset ($ parsedUrl ['port ' ]) ? ": {$ parsedUrl ['port ' ]}" : '' ) .
521+ (isset ($ parsedUrl ['path ' ]) ? "{$ parsedUrl ['path ' ]}" : '' ) .
522+ (isset ($ parsedUrl ['query ' ]) ? "? {$ parsedUrl ['query ' ]}" : '' ) .
523+ (isset ($ parsedUrl ['fragment ' ]) ? "# {$ parsedUrl ['fragment ' ]}" : '' )
524+ ;
525+ }
526+
471527}
0 commit comments