Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Internet
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 02-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
Cita:
Empezado por Galaxian Ver Mensaje
¿Alguien sabe si el encadenamiento con la factura anterior es relativo o absoluto? es decir, si se encadena con la última factura de su serie o con la última generada sea de la serie que sea?

Se encadena con la última generada sea de la serie que sea
Responder Con Cita
  #2  
Antiguo 02-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
PHP Generación del xml

Generación previa a su firma
En mi caso sólo vendo bienes, no servicios

La intención es ver la estructura del xml

Código PHP:
 $xml  = "<?xml version='1.0' encoding='UTF-8'?>";     
    $xml .= "<T:TicketBai xmlns:T='urn:ticketbai:emision' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
    xsi:schemaLocation='http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd'>";
    $xml .= "<Cabecera>";
    $xml .= "<IDVersionTBAI>".$versionTB."</IDVersionTBAI>";
     
    $xml .= "</Cabecera>";  
    $xml .= "<Sujetos>";
    $xml .= "<Emisor>";
    $xml .= "<NIF>".$cif_emisor."</NIF>";    
    $xml .= "<ApellidosNombreRazonSocial>".$nomb_emisor."</ApellidosNombreRazonSocial>";
    $xml .= "</Emisor>";   

    if ($ano_cli == 'S') $cif_cli = $nif_simplificado;  
    // $ano_cli si es fra simplificada  $nif_simplificado = 00000000T
    $xml .= "<Destinatarios>";
    $xml .= "<IDDestinatario>";    // $pai_cli = país del cliente
    if($pai_cli != 'ES' && $es_exportacion == 'SI')    
    {
    $xml .= "<IDOtro>";
    $xml .= "<CodigoPais>".$pai_cli."</CodigoPais>";
    $xml .= "<IDType>06</IDType>";    
    $xml .= "<ID>".$cif_cli."</ID>";
    $xml .= "</IDOtro>";    
    } elseif($es_intracomunitaria == 'SI')    
    {
    $xml .= "<IDOtro>";
    $xml .= "<IDType>02</IDType>";    
    $xml .= "<ID>".$cif_cli."</ID>";
    $xml .= "</IDOtro>";        
    }
    else    
    $xml .= "<NIF>".$cif_cli."</NIF>";
    $xml .= "<ApellidosNombreRazonSocial>".$nomb_cli."</ApellidosNombreRazonSocial>";
    $xml .= "<CodigoPostal>".$cpo_cli."</CodigoPostal>";  
    $ClientAdresse = elimina_acentos($ClientAdresse);      
    $xml .= "<Direccion>".$ClientAdresse."</Direccion>";     
    $xml .= "</IDDestinatario>";
    $xml .= "</Destinatarios>";
    $xml .= "<EmitidaPorTercerosODestinatario>N</EmitidaPorTercerosODestinatario>";  
    $xml .= "</Sujetos>";
$hora = time();
$hora = (date("H:i:s"));
  
    $xml .= "<Factura>";
    $xml .= "<CabeceraFactura>";  
    $xml .= "<SerieFactura>".$seriefactura."</SerieFactura>";  
    $xml .= "<NumFactura>".$numero_factura."</NumFactura>";
    $xml .= "<FechaExpedicionFactura>".$fecha_factura_TBAI."</FechaExpedicionFactura>";
    $xml .= "<HoraExpedicionFactura>".$hora."</HoraExpedicionFactura>";
    if($ano_cli == 'S')
    $xml .= "<FacturaSimplificada>".$ano_cli."</FacturaSimplificada>"; 
    $xml .= "<FacturaEmitidaSustitucionSimplificada>N</FacturaEmitidaSustitucionSimplificada>";
    if($FacturaRectificativa == 'S')
    {
    $base_ivaR = number_format($bimp_alb*(-1),2,".","");      
    $imp_ivaR  = number_format($iiva_alb*(-1),2,".","");    
    $imp_reqR  = number_format($ire_alb*(-1), 2,".",""); 
    
    $xml .= "<FacturaRectificativa>";  
    if($ano_cli == 'S')
    $xml .= "<Codigo>R5</Codigo>"; 
    else
    $xml .= "<Codigo>R1</Codigo>";   
    $xml .= "<Tipo>I</Tipo>";   
    
    if ($hacienda_foral == 'GIP')    
    {    
    $xml .= "<ImporteRectificacionSustitutiva>";      
    $xml .= "<BaseRectificada>".$base_ivaR."</BaseRectificada>";    
    $xml .= "<CuotaRectificada>".$imp_ivaR."</CuotaRectificada>";    
    $xml .= "<CuotaRecargoRectificada>".$imp_reqR."</CuotaRecargoRectificada>";    
    $xml .= "</ImporteRectificacionSustitutiva>";  
    }
    
    $xml .= "</FacturaRectificativa>";  


    $xml .= "<FacturasRectificadasSustituidas>";  
    $xml .= "<IDFacturaRectificadaSustituida>";    
    $xml .= "<NumFactura>".$rectifica1."</NumFactura>";
    $xml .= "<FechaExpedicionFactura>".$rectifica2."</FechaExpedicionFactura>";    
    $xml .= "</IDFacturaRectificadaSustituida>";      
    $xml .= "</FacturasRectificadasSustituidas>"; 

    }
    $xml .= "</CabeceraFactura>";     

    $xml .= "<DatosFactura>";   
    
    if($FacturaRectificativa == 'S') 
    {        
    $xml .= "<FechaOperacion>".$rectifica2."</FechaOperacion>"; 
    $xml .= "<DescripcionFactura>FACTURA RECTIFICATIVA</DescripcionFactura>";       
    }    
     else
    {
     $xml .= "<FechaOperacion>".$fecha_factura_TBAI."</FechaOperacion>";  
    $xml .= "<DescripcionFactura>FACTURA DE VENTA</DescripcionFactura>";     
    }

/////////// detalle factura ////////////////////////

    if($enviar_detalle_lineas == 'SI')
    {
    $xml .= "<DetallesFactura>";
    
    if($lineas_factura)
    foreach ($lineas_factura as $clave => $valor)
    {
    $valor_valor = explode("|",$valor);
    $des_art   = $valor_valor[1];
    $neto_lin  = number_format($valor_valor[2],2,".","");  
    $prec_lin  = number_format($valor_valor[3],8,".",""); 
    $impo_lin  = $valor_valor[4];
    $impo_lin  = $impo_lin + $impo_lin*($tipo_iva/100) + $impo_lin*($tipo_req/100); 
    $impo_lin  = number_format($impo_lin,2,".",""); 

    $xml .= "<IDDetalleFactura>";
    $des_art = elimina_acentos($des_art);    
    $des_art = preg_replace("([^ A-Za-z0-9])", "", $des_art);     
    $xml .= "<DescripcionDetalle>".$des_art."</DescripcionDetalle>"; 
    $xml .= "<Cantidad>".$neto_lin."</Cantidad>"; 
    $xml .= "<ImporteUnitario>".$prec_lin."</ImporteUnitario>"; 
    $xml .= "<ImporteTotal>".$impo_lin."</ImporteTotal>";     
    $xml .= "</IDDetalleFactura>";
    }       // fin for
    unset($lineas_factura);
    
    $xml .= "</DetallesFactura>";  
    }
    
#########################   totales    

    $xml .= "<ImporteTotalFactura>".$total_factura."</ImporteTotalFactura>"; 

    if($retencion)
    $xml .= "<RetencionSoportada>".$retencion."</RetencionSoportada>"; 
    
    $xml .= "<Claves>";   
    $xml .= "<IDClave>"; 
    $xml .= "<ClaveRegimenIvaOpTrascendencia>".$ClaveRegimenEspecialOTrascendencia."</ClaveRegimenIvaOpTrascendencia>"; 
    $xml .= "</IDClave>";     
    $xml .= "</Claves>";    
  
    $xml .= "</DatosFactura>";    

    $tipo_iva_m = number_format($tipo_iva,2,".","");
    if($tipo_req!=0 && $ire_alb!=0)
    $tipo_req_m = number_format($tipo_req,2,".","");
 
 
    if($es_exportacion == 'SI')    
    {        
    $xml .= "<TipoDesglose>";
    $xml .= "<DesgloseTipoOperacion>";
    $xml .= "<Entrega>";    
    $xml .= "<Sujeta>";
    $xml .= "<Exenta>";
    $xml .= "<DetalleExenta>";        
    $xml .= "<CausaExencion>E2</CausaExencion>";
    $xml .= "<BaseImponible>".$base_iva."</BaseImponible>";
    $xml .= "</DetalleExenta>";        
    $xml .= "</Exenta>";
    $xml .= "</Sujeta>";
    $xml .= "</Entrega>";    
    $xml .= "</DesgloseTipoOperacion>";
    $xml .= "</TipoDesglose>";
    }
    elseif($es_intracomunitaria == 'SI')     
    {
    $xml .= "<TipoDesglose>";
    $xml .= "<DesgloseTipoOperacion>";
    $xml .= "<Entrega>";    
    $xml .= "<Sujeta>";
    $xml .= "<Exenta>";
    $xml .= "<DetalleExenta>";    
    $xml .= "<CausaExencion>E5</CausaExencion>";
    $xml .= "<BaseImponible>".$base_iva."</BaseImponible>";
    $xml .= "</DetalleExenta>";        
    $xml .= "</Exenta>";
    $xml .= "</Sujeta>";
    $xml .= "</Entrega>";    
    $xml .= "</DesgloseTipoOperacion>";
    $xml .= "</TipoDesglose>";    
    } else {
    $xml .= "<TipoDesglose>";
    $xml .= "<DesgloseFactura>";
    $xml .= "<Sujeta>";
    $xml .= "<NoExenta>";
    $xml .= "<DetalleNoExenta>";    
    $xml .= "<TipoNoExenta>S1</TipoNoExenta>";
    $xml .= "<DesgloseIVA>";        
    $xml .= "<DetalleIVA>";
    $xml .= "<BaseImponible>".$base_iva."</BaseImponible>";
    $xml .= "<TipoImpositivo>".$tipo_iva_m."</TipoImpositivo>";
    $xml .= "<CuotaImpuesto>".$imp_iva."</CuotaImpuesto>";
    if($tipo_req!=0 && $ire_alb!=0)
    {
    $xml .= "<TipoRecargoEquivalencia>".$tipo_req_m."</TipoRecargoEquivalencia>";
    $xml .= "<CuotaRecargoEquivalencia>".$imp_req."</CuotaRecargoEquivalencia>";
    }
    $xml .= "</DetalleIVA>";
    $xml .= "</DesgloseIVA>";
    $xml .= "</DetalleNoExenta>";
    $xml .= "</NoExenta>";    
    $xml .= "</Sujeta>";
    $xml .= "</DesgloseFactura>";        
    $xml .= "</TipoDesglose>";
     } 
    $xml .= "</Factura>";
</div>Tened en cuenta u obviad las variables de PHP que vienen de una consulta sql previa


Seguimos con el encadenamiento dentro del mismo script
Busco la factura firmada anterior



Código PHP:
    $firmada_anterior $directorio_TBAI.$factura_anterior;
    
$file_anterior $firmada_anterior;
    if (
file_exists($file_anterior)) {
    
$xml_anterior simplexml_load_file($firmada_anterior);
    
$SerieFacturaAnterior $xml_anterior->Factura->CabeceraFactura->SerieFactura;    
    
$NumFacturaAnterior $xml_anterior->Factura->CabeceraFactura->NumFactura;    
    
$FechaExpedicionFacturaAnterior =    $xml_anterior->Factura->CabeceraFactura->FechaExpedicionFactura;        
    
$signatureNode $xml_anterior->children('ds'true)->Signature;    
    
$SignatureValueFirmaFacturaAnterior $signatureNode->SignatureValue;    
    } else {
    
$enviada_anterior $directorio_TBAI_envios.$factura_anterior;    
    
$file_enviado $enviada_anterior;    
    if (
file_exists($file_enviado)) {    
    
$xml_anterior simplexml_load_file($enviada_anterior);
    
$SerieFacturaAnterior $xml_anterior->Factura->CabeceraFactura->SerieFactura;        
    
$NumFacturaAnterior $xml_anterior->Factura->CabeceraFactura->NumFactura;    
    
$FechaExpedicionFacturaAnterior $xml_anterior->Factura->CabeceraFactura->FechaExpedicionFactura;        
    
$signatureNode $xml_anterior->children('ds'true)->Signature;    
    
$SignatureValueFirmaFacturaAnterior $signatureNode->SignatureValue;    
    } else {    
    
$NumFacturaAnterior 'Primera factura del ciclo de facturacion';    
    
$SignatureValueFirmaFacturaAnterior 'Primera factura del ciclo de facturacion';        
    }
    }    
    
$SignatureValueFirmaFacturaAnterior substr($SignatureValueFirmaFacturaAnterior,0,100);

    
$xml .= "<HuellaTBAI>";
    
$xml .= "<EncadenamientoFacturaAnterior>";
    
$xml .= "<SerieFacturaAnterior>".$SerieFacturaAnterior."</SerieFacturaAnterior>";
    
$xml .= "<NumFacturaAnterior>".$NumFacturaAnterior."</NumFacturaAnterior>";
    
$xml .= "<FechaExpedicionFacturaAnterior>".$FechaExpedicionFacturaAnterior."</FechaExpedicionFacturaAnterior>";    
    
$xml .= "<SignatureValueFirmaFacturaAnterior>".$SignatureValueFirmaFacturaAnterior."</SignatureValueFirmaFacturaAnterior>";
    
$xml .= "</EncadenamientoFacturaAnterior>";
    
$xml .= "<Software>";
    
$xml .= "<LicenciaTBAI>".$LicenciaTBAI."</LicenciaTBAI>";    
    
$xml .= "<EntidadDesarrolladora>";
    
$xml .= "<NIF>".$nif_fabricante."</NIF>";
    
$xml .= "</EntidadDesarrolladora>";    
    
$xml .= "<Nombre>".$SoftwareNombre."</Nombre>";
    
$xml .= "<Version>".$SoftwareVersion."</Version>";
    
$xml .= "</Software>";
    
$xml .= "<NumSerieDispositivo>".$NumSerieDispositivo_TBAI."</NumSerieDispositivo>";
  
$xml .= "</HuellaTBAI>";

   
$xml .= "</T:TicketBai>"
Fima del xml que detallaré más adelante en otro envío


Código PHP:
$guardar_como $tbai_alb.'.xsig';
    
    require_once(
$_SERVER['DOCUMENT_ROOT'].'/xxxxxx/ticketBAI/src/XmlTools.php' );
    require_once(
$_SERVER['DOCUMENT_ROOT'].'/xxxxxx/ticketBAI/src/firmador.php' );
    
$dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/infoxxxxrmix/_certificandos'.$alias_pdf.'/xxxxxxx.pfx' );    
    
$fac = new Firmador();
    
$xmlF $fac -> firmar($dir_cert,$cal_cert$xml$hacienda_foral);

    
$directorio_ventas $directorio_TBAI.$guardar_como;  
     
file_put_contents($directorio_ventas$xmlF); 
</div>

Queda enviar el desarrollo de la firma donde intervienen XmlTools.php, firmador.php y el certificado de firma y su clave.
Responder Con Cita
  #3  
Antiguo 02-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
PHP Firma del xml

Nos hemos quedado aquí:

Código PHP:
$guardar_como $tbai_alb.'.xsig';
    
    require_once(
$_SERVER['DOCUMENT_ROOT'].'/xxx/ticketBAI/src/XmlTools.php' );
    require_once(
$_SERVER['DOCUMENT_ROOT'].'/xxx/ticketBAI/src/firmador.php' );
    
$dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/xxx/_certificandos'.'/xxx.pfx' );    
    
$fac = new Firmador();
    
$xmlF $fac -> firmar($dir_cert,$cal_cert$xml$hacienda_foral);

    
$directorio_ventas $directorio_TBAI.$guardar_como;  
    
file_put_contents($directorio_ventas$xmlF); 
Lo que hago es indicar donde guardarlo, en mi caso con el mismo nombre número de orden de emisión de la factura.

XmlTools.php:
Código PHP:
class XmlTools {
    public function 
randomId() {
    if (
function_exists('random_int')) return random_int(0x100000000x7FFFFFFF);
    return 
rand(100000999999);
    }
    public function 
generateGUID($prefix='pfx')
    {
        
$uuid md5(uniqid(mt_rand(), true));
        
$guid $prefix.substr($uuid08)."-".
                
substr($uuid84)."-".
                
substr($uuid124)."-".
                
substr($uuid164)."-".
                
substr($uuid2012);
        return 
$guid;
    }
 } 
</div>

Este es el importante: firmador.php
Código PHP:
<?php
class Firmador{
    
    const 
POLITICA_FIRMA_BIZ = array(
    
"name" => "Politica de firma TicketBAI 1.0",
    
"url" => "https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf"
    
"digest" => "Quzn98x3PMbSHwbUzaj5f5KOpiH0u8bvmwbbbNkO9Es="
    
);

    const 
POLITICA_FIRMA_GIP = array(
    
"name" => "Politica de firma TicketBAI 1.0",
    
"url" => "https://www.gipuzkoa.eus/ticketbai/sinadura",  
    
"digest" => "dTtPpv4fWTcejeVx7+91ILruFX3HysbngBlllJm4i/E="
    
);
    
    private 
$signTime         NULL;
    private 
$signPolicy       NULL;
    private 
$publicKey        NULL;
    private 
$privateKey       NULL;
    private 
$cerROOT          NULL;
    private 
$cerINTERMEDIO    NULL;
    private 
$tipoDoc          '01';

    public function 
retC14DigestSha1($strcadena)
    {
    
$strcadena    str_replace("\r"""str_replace("\n"""$strcadena));
    
$d1p        = new DOMDocument('1.0''UTF-8');
    
$d1p->loadXML($strcadena);
    
$strdata    $d1p->C14N();
    return 
base64_encode(hash('sha256' $strdatatrue ));
    }

    public function 
firmar($certificadop12$clavecertificado$xmlsinfirma$hacienda_foral)
    {
    if (!
$pfx file_get_contents($certificadop12))
    {
    echo 
"Error: No se puede leer el fichero del certificado o no existe en la ruta especificada\n";
    exit;
    }
    if (
openssl_pkcs12_read($pfx$key$clavecertificado))
    {
    
$this->publicKey    $key["cert"];
    
$this->privateKey   $key["pkey"];
    
$complem              openssl_pkey_get_details(openssl_pkey_get_private($this->privateKey));
    
$this->Modulus        base64_encode($complem['rsa']['n']);
    
$this->Exponent       base64_encode($complem['rsa']['e']);
    }
    else
    {
    echo 
"Error: No se puede leer el almacén de certificados o la clave no es la correcta.\n";
    exit;
    }

    if (
$hacienda_foral == "BIZ")    
    
$this->signPolicy             self::POLITICA_FIRMA_BIZ;
    if (
$hacienda_foral == "GIP")    
    
$this->signPolicy             self::POLITICA_FIRMA_GIP;
    
$tools = new XmlTools();
    
$this->signatureID             $tools->generateGUID('xmldsig-');
    
$this->signatureValue         $this->signatureID.'-sigvalue';
    
$this->XadesObjectId          "XadesObjectId-".$this->signatureID;
    
$this->KeyInfoId              "KeyInfoId-".$this->signatureID;
    
$this->Reference0Id           $this->signatureID.'-ref0';
    
$this->Reference1Id           "ReferenceKeyInfo";
    
$this->SignedProperties       $this->signatureID.'-signedprops';
    
$this->qualifyingProperties "QualifyingProperties-".$this->signatureID;
    
    
$xml1                       $xmlsinfirma;
    
$xml1                       $this->insertaFirma($xml1);
    return 
$xml1;
    }

    public function 
insertaFirma($xml){
      

      
    if (
is_null($this->publicKey) || is_null($this->privateKey))
    return 
$xml;

    
$d = new DOMDocument('1.0''UTF-8');
    
$d->loadXML($xml);
    
$canonizadoreal $d->C14N();

    
$xmlns 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#" ' .
             
'xmlns:T="urn:ticketbai:emision" ' .
             
'xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"';
            
    
$xmnls_signeg        'xmlns:T="urn:ticketbai:emision" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
    
$xmlns_keyinfo       'xmlns:T="urn:ticketbai:emision" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
    
$xmnls_signedprops 'xmlns:T="urn:ticketbai:emision" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';

    
$signTime1 date('Y-m-d\TH:i:s+01:00');
    
$certData   openssl_x509_parse($this->publicKey);
    
$certDigest base64_encode(openssl_x509_fingerprint($this->publicKey"sha256"true));
    
$certIssuer = array();

    foreach (
$certData['issuer'] as $item=>$value)
    {
    
$certIssuer[] = $item '=' $value;
    }
    
$certIssuer implode(', 'array_reverse($certIssuer));

    
$prop '<xades:SignedProperties Id="'.$this->SignedProperties.'">' .
      
'<xades:SignedSignatureProperties>'.
          
'<xades:SigningTime>'.$signTime1.'</xades:SigningTime>' .
          
'<xades:SigningCertificate>'.
              
'<xades:Cert>'.
                  
'<xades:CertDigest>' .
                      
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>'.
                      
'<ds:DigestValue>'.$certDigest.'</ds:DigestValue>'.
                  
'</xades:CertDigest>'.
                  
'<xades:IssuerSerial>' .
                      
'<ds:X509IssuerName>'.$certIssuer.'</ds:X509IssuerName>'.
                      
'<ds:X509SerialNumber>'.$certData['serialNumber'].'</ds:X509SerialNumber>' .
                  
'</xades:IssuerSerial>'.
              
'</xades:Cert>'.
          
'</xades:SigningCertificate>' .
          
'<xades:SignaturePolicyIdentifier>'.
              
'<xades:SignaturePolicyId>' .
                  
'<xades:SigPolicyId>'.
                      
'<xades:Identifier>'.$this->signPolicy['url'].'</xades:Identifier>'.
                      
'<xades:Description>'.$this->signPolicy['name'].'</xades:Description>'.
                  
'</xades:SigPolicyId>'.
                  
'<xades:SigPolicyHash>' .
                      
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />'.
                      
'<ds:DigestValue>'.$this->signPolicy['digest'].'</ds:DigestValue>'.
                  
'</xades:SigPolicyHash>'.
                  
'<xades:SigPolicyQualifiers>'.
                    
'<xades:SigPolicyQualifier>'.
                      
'<xades:SPURI>'.$this->signPolicy['url'].'</xades:SPURI>'.
                    
'</xades:SigPolicyQualifier>'.
                  
'</xades:SigPolicyQualifiers>'.
              
'</xades:SignaturePolicyId>' .
          
'</xades:SignaturePolicyIdentifier>'.
      
'</xades:SignedSignatureProperties>'.
      
'<xades:SignedDataObjectProperties>'.
          
'<xades:DataObjectFormat ObjectReference="#'.$this->Reference0Id.'">'.
                  
'<xades:ObjectIdentifier>' .
                    
'<xades:Identifier Qualifier="OIDAsURN">urn:oid:1.2.840.10003.5.109.10</xades:Identifier>' .
                  
'</xades:ObjectIdentifier>' .          
              
'<xades:MimeType>text/xml</xades:MimeType>'.
              
'<xades:Encoding>UTF-8</xades:Encoding>'.
          
'</xades:DataObjectFormat>'.
      
'</xades:SignedDataObjectProperties>'.
      
'</xades:SignedProperties>';

    
// Prepare key info
    
$publicPEM "";
    
openssl_x509_export($this->publicKey$publicPEM);
    
$publicPEM str_replace("-----BEGIN CERTIFICATE-----"""$publicPEM);
    
$publicPEM str_replace("-----END CERTIFICATE-----"""$publicPEM);
    
$publicPEM str_replace("\r"""str_replace("\n"""$publicPEM));

    
$kInfo '<ds:KeyInfo Id="'.$this->KeyInfoId.'">' .
                
'<ds:X509Data>'  .
                    
'<ds:X509Certificate>'.$publicPEM.'</ds:X509Certificate>' .
                
'</ds:X509Data>' .
                
'<ds:KeyValue>'.
                
'<ds:RSAKeyValue>'.
                    
'<ds:Modulus>'.$this->Modulus.'</ds:Modulus>'.
                    
'<ds:Exponent>'.$this->Exponent.'</ds:Exponent>'.
                
'</ds:RSAKeyValue>'.
                
'</ds:KeyValue>'.                
             
'</ds:KeyInfo>';

    
$keyinfo_para_hash1 str_replace('<ds:KeyInfo''<ds:KeyInfo ' $xmlns_keyinfo$kInfo);
    
$kInfoDigest $this->retC14DigestSha1($keyinfo_para_hash1);
    
$aconop     str_replace('<xades:SignedProperties''<xades:SignedProperties ' $xmnls_signedprops$prop);
    
$propDigest $this->retC14DigestSha1($aconop);
    
$documentDigest base64_encode(hash('sha256'$canonizadorealtrue));
        
    
// Prepare signed info
    
$sInfo '<ds:SignedInfo>' .
        
'<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>' .
        
'<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>' .
 
        
'<ds:Reference URI="#'.$this->SignedProperties.'" Type="http://uri.etsi.org/01903#SignedProperties">' .
        
'<ds:Transforms>' .
        
'<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>' .
        
'</ds:Transforms>' .        
        
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>' .
        
'<ds:DigestValue>'.$propDigest.'</ds:DigestValue>' .
        
'</ds:Reference>' .

        
'<ds:Reference Id="'.$this->Reference1Id.'" URI="#'.$this->KeyInfoId.'">' .
        
'<ds:Transforms>' .
        
'<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>' .
        
'</ds:Transforms>' .        
        
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />' .
        
'<ds:DigestValue>'.$kInfoDigest.'</ds:DigestValue>' .
        
'</ds:Reference>' .
        
        
'<ds:Reference Id="'.$this->Reference0Id.'" URI=""
        Type="http://www.w3.org/2000/09/xmldsig#Object">' 
.
        
'<ds:Transforms>' .
        
'<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>' .        
        
'<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>' .
        
'</ds:Transforms>' .
        
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>' .
        
'<ds:DigestValue>'.$documentDigest.'</ds:DigestValue>' .
        
'</ds:Reference>' .

        
'</ds:SignedInfo>';


    
$signaturePayload str_replace('<ds:SignedInfo''<ds:SignedInfo ' $xmnls_signeg$sInfo);

    
$d1p = new DOMDocument('1.0''UTF-8');
    
$d1p->loadXML($signaturePayload);
    
$signaturePayload $d1p->C14N();
    
    
$signatureResult "";
    
$algo "SHA256";
    
    
openssl_sign($signaturePayload$signatureResult$this->privateKey$algo);
    
$signatureResult base64_encode($signatureResult);
    
$sig '<ds:Signature Id="'.$this->signatureID.'" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">'.
    
$sInfo.'<ds:SignatureValue Id="'.$this->signatureValue.'">'.$signatureResult'
    </ds:SignatureValue>'
.
    
$kInfo .
    
'<ds:Object Id="'.$this->XadesObjectId .'">'.
    
'<xades:QualifyingProperties Id="'.$this->qualifyingProperties.'" 
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Target="#'
.$this->signatureID.'" 
    xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">'

    
$prop .
    
'</xades:QualifyingProperties>
    </ds:Object>
    </ds:Signature>'
;

    
$xml str_replace('</T:TicketBai>'$sig '</T:TicketBai>'$xml);
    return 
$xml;
    }
}
?>
Mucha atención al contenido de firmador.php
Es posible que algo sobre pero no me atrevo a tocar nada ya que finciona bien.
Proximamente hablaremos del envío de los xml firmados a GIP y a BIZ, este último tiene su miga.
A vuestra disposición para comentar y aclarar lo que requiráis


Sería bueno poder firmar sólo con los .pem y sin clave de certificado pero quizás no se pueda.


Un saludo
Responder Con Cita
  #4  
Antiguo 02-05-2021
Sistel Sistel is offline
Miembro
 
Registrado: nov 2019
Ubicación: Bilbao
Posts: 373
Poder: 5
Sistel Va por buen camino
Cita:
Empezado por bilbur Ver Mensaje
Nos hemos quedado aquí:
...
¡¡¡¡ Genial, Bilbur !!!!

Estaba atrancado con el tema de la firma.
No conseguía firmar el XML sin errores.
Seguro que con tu clase Firmador, salgo, por fín, del atolladero.

¡¡¡ Muchísimas Gracias !!!
Apunta que te debo alguna, para cuando acabe la pandemia.

Un cordial saludo

Última edición por Sistel fecha: 02-05-2021 a las 19:15:30.
Responder Con Cita
  #5  
Antiguo 03-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
Cita:
Empezado por Sistel Ver Mensaje
¡¡¡¡ Genial, Bilbur !!!!

Estaba atrancado con el tema de la firma.
No conseguía firmar el XML sin errores.
Seguro que con tu clase Firmador, salgo, por fín, del atolladero.

Un cordial saludo

Si necesitas ayuda en la implementación, me dices. No sea que se me olvidara subir algo.
Para comprobar las firmas y antes de enviarlas yo utilizo estos dos enlaces

http://tools.chilkat.io/xmlDsigVerify.cshtml

https://web.uanataca.com/pe/servicio...ma-electronica

Si te da correcto en las dos validaciones pues ¡eureka!
Responder Con Cita
  #6  
Antiguo 03-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
PHP Envío a TBAI GIP

Os adjunto lo que tengo hecho para el envío a Gipuzkoa
Este envío es el más sencillo
Más o menos lo que hago es:
  1. Proceso previo o simultáneo a la emisión y firma de la factura
  2. En el directorio donde están las facturas firmadas, creo, si no están, los directorios de Envios y Respuestas.
  3. Si la factura firmada existe en el directorio de facturas firmadas, la envío a TBAI GIP
  4. Me guardo la respuesta y si es afirmativa muevo la factura firmada al directorio de Envios
<div>
Código PHP:
if($hacienda_foral == 'GIP' && $orden_tbai != '000000')     {    
    
$directorio_TBAI $originales."TBAI/".$cif_340."/";
    
$directorio_TBAI_envios $originales."TBAI/".$cif_340."/Envios/";        
    if (!
is_dir($directorio_TBAI_envios))  mkdir($directorio_TBAI_envios0777);
    
$directorio_respuestas $directorio_TBAI.'Respuestas/';   
    if (!
is_dir($directorio_respuestas))  mkdir($directorio_respuestas0777);    

    
$estado_tbai '';
    
$xml_enviado_tbai $orden_tbai.'.xsig';
    
$guardado_enviar_tbai $directorio_TBAI.$xml_enviado_tbai;    
    if (
file_exists($guardado_enviar_tbai)) 
    {    
    
$estado_tbai 'No enviado';
    
$descripcion_TBAI $estado_tbai;
    
$xml file_get_contents($guardado_enviar_tbai);

    
$header_soap = array(
    
"Content-Type: application/xml;charset=utf-8",
    
"Accept: application/xml",
    
"Content-length: ".strlen($xml)
    );

$soap_do curl_init();
curl_setopt($soap_doCURLOPT_URL$url_TBAI );
curl_setopt($soap_doCURLOPT_CONNECTTIMEOUT100);
curl_setopt($soap_doCURLOPT_TIMEOUT,        100);
curl_setopt($soap_doCURLOPT_RETURNTRANSFERtrue);
curl_setopt($soap_doCURLOPT_FOLLOWLOCATIONtrue);
curl_setopt($soap_doCURLOPT_SSL_VERIFYPEERfalse);
curl_setopt($soap_doCURLOPT_SSL_VERIFYHOSTfalse);
curl_setopt($soap_doCURLOPT_USERAGENT'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($soap_doCURLOPT_POST,           true );
curl_setopt($soap_doCURLOPT_SSLCERT,        getcwd().'/_certificandos'.$alias_pdf.'/'.$cif_340.'.pem' );
curl_setopt($soap_doCURLOPT_POSTFIELDS,     $xml);
curl_setopt($soap_doCURLOPT_HTTPHEADER,     $header_soap);

    
$response curl_exec($soap_do);     
    if(!
curl_exec($soap_do)) {
    
$err 'Error: ' curl_error($soap_do);
    
curl_close($soap_do);
    echo 
"<br>No se puede conectar con la TBAI GIP.<br><br>";    
    
print_r($err);
    echo 
"<br>";    
    echo 
"<br><b>Respuesta de la TBAI GIP: 312</b><br><br>";    
    
print_r($response);
    } else {
    
curl_close($soap_do);

    
$response preg_replace('/(<\s*)\w+:/','$1',$response);   // removes <xxx:
    
$response preg_replace('/(<\/\s*)\w+:/','$1',$response); // removes </xxx:
    
$response preg_replace('/\s+xmlns:[^>]+/','',$response); // removes xmlns:...    

    
$use_errors libxml_use_internal_errors(true);    
    
$parser simplexml_load_string($response);
    if (
$parser === false) {
    echo 
"<br>No se puede cargar el fichero xml devuelto por la TBA GIP.<br><br>";
    echo 
"<br>";    
    echo 
"<br><b>Respuesta de la TBAI GIP:</b><br><br>";    
    
print_r($response);
    }
    
libxml_clear_errors();
    
libxml_use_internal_errors($use_errors);    
    if (
$parser === false) exit();
    
$parser->asXML($directorio_respuestas.$orden_tbai.'.xml');
    }

    
$facturas_en_TBAI $parser;
    if (
$facturas_en_TBAI === false)    
    {
    echo 
"<br><b>Respuesta de TBAI parser:</b><br><br>";
    
print_r ($facturas_en_TBAI);
    }
    
$guardado_enviado_tbai $directorio_TBAI_envios.$xml_enviado_tbai;
    
    
$nodo $facturas_en_TBAI->Salida;
    
$Estado $nodo->Estado;    
    if(
$Estado == '00')    
    
rename($guardado_enviar_tbai,$guardado_enviado_tbai); /// atencion a esto
    
unset($facturas_en_TBAI);
    }    
     } 
// if($hacienda_foral == 'GIP') 
</div>Aparte tengo un script para visualizar la respuesta
En este lo más interesante puede ser la generación de la url del mensaje TBAI para verlo como si se tratara del código QR



Código PHP:
<?php

    $directorio_respuestas 
$directorio_TBAI.'Respuestas/';   
    if (!
is_dir($directorio_respuestas))  mkdir($directorio_respuestas0777);
    
$directorio_envios $directorio_TBAI.'Envios/';   
    if (!
is_dir($directorio_envios))  mkdir($directorio_envios0777);
    
    
$estado_tbai '';

    
$xml_enviado_tbai $orden_tbai.'.xsig';    
    
$guardado_enviado_tbai $directorio_envios.$xml_enviado_tbai;    
    if (
file_exists($guardado_enviado_tbai)) 
    
$estado_tbai 'Enviado'; else $estado_tbai 'No enviado';
    
$descripcion_TBAI $estado_tbai;

    if(
$estado_tbai == 'Enviado')
    {    
    
$msg_TBAI '';
    
$xml_actual_enviado simplexml_load_file($guardado_enviado_tbai);    
    
$signatureNodeActual $xml_actual_enviado->children('ds'true)->Signature;    
    
$SignatureValueFirmaFacturaActual $signatureNodeActual->SignatureValue;
    
$SignatureValueFirmaFacturaActual substr($SignatureValueFirmaFacturaActual,0,13);    
    
$factura_tbai_serie  $xml_actual_enviado->Factura->CabeceraFactura->SerieFactura;    
    
$factura_tbai_numero $xml_actual_enviado->Factura->CabeceraFactura->NumFactura;
    
$factura_tbai_fecha  $xml_actual_enviado->Factura->CabeceraFactura->FechaExpedicionFactura;    
    
$factura_tbai_fecha_dd substr($factura_tbai_fecha,0,2);
    
$factura_tbai_fecha_mm substr($factura_tbai_fecha,3,2);    
    
$factura_tbai_fecha_aa substr($factura_tbai_fecha,-2);        
    
$factura_tbai_importe  $xml_actual_enviado->Factura->DatosFactura->ImporteTotalFactura;        
    
$TBAIID  'TBAI'.$caracterSeparador.$cif_340.$caracterSeparador.$factura_tbai_fecha_dd;
    
$TBAIID .= $factura_tbai_fecha_mm.$factura_tbai_fecha_aa.$caracterSeparador;
    
$TBAIID .= $SignatureValueFirmaFacturaActual.$caracterSeparador;
    
$TBAIID utf8_encode($TBAIID);    
    
$cod_crc8 crc8($TBAIID);
    
$TBAIID  $TBAIID.$cod_crc8;
    unset(
$xml_actual_enviado);
    
$msg_TBAI =  $url_TBAI_QR.'?id='.$TBAIID.'&s='.$factura_tbai_serie.'&nf='.$factura_tbai_numero.'&i='.$factura_tbai_importe;
    
$msg_TBAI utf8_encode($msg_TBAI);    
    
$cod_crc8 crc8($msg_TBAI);
    
$msg_TBAI $msg_TBAI.'&cr='.$cod_crc8;    
    
$xml_respuesta $orden_tbai.'.xml';
    
$guardado_respuesta $directorio_respuestas.$xml_respuesta;
    if (
file_exists($guardado_respuesta)) 
    {
    
$respuesta_tbai simplexml_load_file($guardado_respuesta);
    if (
$respuesta_tbai === false) {
    
$estado_tbai 'No se puede leer la respuesta de TBAI';
    } else {
    
$estado_tbai 'Existe respuesta de TBAI';
    }
    } else {
    
$estado_tbai 'No se encuentra la respuesta de TBAI';
    
$sin_respuesta_tbai     '<?xml version="1.0" encoding="UTF-8"?>';
    
$sin_respuesta_tbai    .= '<Salida></Salida>';
    
$respuesta_tbai simplexml_load_string($sin_respuesta_tbai);    
    }
    
$descripcion_TBAI $estado_tbai;

    
$nodo $respuesta_tbai->Salida;
    
$Estado $nodo->Estado;
    
$FechaRecepcion $nodo->FechaRecepcion;

    if(
$Estado == '00')
    {    
    
$IdentificadorTBAI $nodo->IdentificadorTBAI;    
    
$Descripcion $nodo->Descripcion;
    
$Descripcion utf8_decode($Descripcion);
    
$CSV_tbai 'CSV: '.$nodo->CSV;
    
$ResultadosValidacion $nodo->ResultadosValidacion;
    
$CodigoRV $ResultadosValidacion->Codigo;
    if(
$CodigoRV)    
    
$DescripcionRV $errores_envio_TBAI["$CodigoRV"];    
    
$estado_tbai 'Correcto';    
    
$descripcion_TBAI $estado_tbai.': '.$IdentificadorTBAI.' '.$FechaRecepcion.' '.$Descripcion.' '.$CSV_tbai;
    if(
$CodigoRV)
    {    
    
$descripcion_TBAI .= ' '.$CodigoRV.' '.$DescripcionRV;
    
$estado_tbai 'Aviso';    
    }
    }    
    
    if(
$Estado == '01')    
    {
    
$ResultadosValidacion $nodo->ResultadosValidacion;
    
$CodigoRV $ResultadosValidacion->Codigo;
    
$DescripcionRV $errores_envio_TBAI["$CodigoRV"];    
    if(
substr($DescripcionRV,0,5) == 'Aviso' || $CodigoRV == '005' )
    
$estado_tbai 'Aviso';    
    else    
$estado_tbai 'Rechazado';
    
$descripcion_TBAI $estado_tbai.': '.$FechaRecepcion.' '.$CodigoRV.' '.$DescripcionRV;
    }
    unset(
$respuesta_tbai);
    } 
//  enviado
Tengo, si interesa, la generación del código QR para PDF con la libreria fpdf.


Comentamos ...
Responder Con Cita
  #7  
Antiguo 20-05-2021
canfora canfora is offline
Registrado
 
Registrado: may 2021
Posts: 3
Poder: 0
canfora Va por buen camino
PHP Envío a TBAI GIP

Buenos días,

Me acabo de poner con la programación en php para el envío de XML a TBAI a Gipuzkoa.
Estoy utilizando el código que sugerís a continuación y recibo en todo momento el siguiente error:
"
No se puede conectar con la TBAI GIP.

Error: unable to use client certificate (no key found or wrong pass phrase?)

Respuesta de la TBAI GIP: 312
"
Tengo un certificado pfx, el cual indico en la línea de declaración del CURLOPT_SSLCERT y añado la siguiente linea:
curl_setopt($soap_do, CURLOPT_SSLCERTPASSWD, $pass);

Si utilizo una conexión más sencilla, como la que indico a continuación, recibo el siguiente error:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $server);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestXML);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

ERROR:
"
01
Rechazado
Baztertua

001
Error: No se ha utilizado certificado de cliente.
Errorea: Ez da erabili bezeroaren ziurtagiririk.
"

Muchísimas gracias por vuestra ayuda.

Cita:
Empezado por bilbur Ver Mensaje
Os adjunto lo que tengo hecho para el envío a Gipuzkoa
Este envío es el más sencillo
Más o menos lo que hago es:
  1. Proceso previo o simultáneo a la emisión y firma de la factura
  2. En el directorio donde están las facturas firmadas, creo, si no están, los directorios de Envios y Respuestas.
  3. Si la factura firmada existe en el directorio de facturas firmadas, la envío a TBAI GIP
  4. Me guardo la respuesta y si es afirmativa muevo la factura firmada al directorio de Envios
<div>
Código PHP:
if($hacienda_foral == 'GIP' && $orden_tbai != '000000')     {    
    
$directorio_TBAI $originales."TBAI/".$cif_340."/";
    
$directorio_TBAI_envios $originales."TBAI/".$cif_340."/Envios/";        
    if (!
is_dir($directorio_TBAI_envios))  mkdir($directorio_TBAI_envios0777);
    
$directorio_respuestas $directorio_TBAI.'Respuestas/';   
    if (!
is_dir($directorio_respuestas))  mkdir($directorio_respuestas0777);    

    
$estado_tbai '';
    
$xml_enviado_tbai $orden_tbai.'.xsig';
    
$guardado_enviar_tbai $directorio_TBAI.$xml_enviado_tbai;    
    if (
file_exists($guardado_enviar_tbai)) 
    {    
    
$estado_tbai 'No enviado';
    
$descripcion_TBAI $estado_tbai;
    
$xml file_get_contents($guardado_enviar_tbai);

    
$header_soap = array(
    
"Content-Type: application/xml;charset=utf-8",
    
"Accept: application/xml",
    
"Content-length: ".strlen($xml)
    );

$soap_do curl_init();
curl_setopt($soap_doCURLOPT_URL$url_TBAI );
curl_setopt($soap_doCURLOPT_CONNECTTIMEOUT100);
curl_setopt($soap_doCURLOPT_TIMEOUT,        100);
curl_setopt($soap_doCURLOPT_RETURNTRANSFERtrue);
curl_setopt($soap_doCURLOPT_FOLLOWLOCATIONtrue);
curl_setopt($soap_doCURLOPT_SSL_VERIFYPEERfalse);
curl_setopt($soap_doCURLOPT_SSL_VERIFYHOSTfalse);
curl_setopt($soap_doCURLOPT_USERAGENT'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($soap_doCURLOPT_POST,           true );
curl_setopt($soap_doCURLOPT_SSLCERT,        getcwd().'/_certificandos'.$alias_pdf.'/'.$cif_340.'.pem' );
curl_setopt($soap_doCURLOPT_POSTFIELDS,     $xml);
curl_setopt($soap_doCURLOPT_HTTPHEADER,     $header_soap);

    
$response curl_exec($soap_do);     
    if(!
curl_exec($soap_do)) {
    
$err 'Error: ' curl_error($soap_do);
    
curl_close($soap_do);
    echo 
"<br>No se puede conectar con la TBAI GIP.<br><br>";    
    
print_r($err);
    echo 
"<br>";    
    echo 
"<br><b>Respuesta de la TBAI GIP: 312</b><br><br>";    
    
print_r($response);
    } else {
    
curl_close($soap_do);

    
$response preg_replace('/(<\s*)\w+:/','$1',$response);   // removes <xxx:
    
$response preg_replace('/(<\/\s*)\w+:/','$1',$response); // removes </xxx:
    
$response preg_replace('/\s+xmlns:[^>]+/','',$response); // removes xmlns:...    

    
$use_errors libxml_use_internal_errors(true);    
    
$parser simplexml_load_string($response);
    if (
$parser === false) {
    echo 
"<br>No se puede cargar el fichero xml devuelto por la TBA GIP.<br><br>";
    echo 
"<br>";    
    echo 
"<br><b>Respuesta de la TBAI GIP:</b><br><br>";    
    
print_r($response);
    }
    
libxml_clear_errors();
    
libxml_use_internal_errors($use_errors);    
    if (
$parser === false) exit();
    
$parser->asXML($directorio_respuestas.$orden_tbai.'.xml');
    }

    
$facturas_en_TBAI $parser;
    if (
$facturas_en_TBAI === false)    
    {
    echo 
"<br><b>Respuesta de TBAI parser:</b><br><br>";
    
print_r ($facturas_en_TBAI);
    }
    
$guardado_enviado_tbai $directorio_TBAI_envios.$xml_enviado_tbai;
    
    
$nodo $facturas_en_TBAI->Salida;
    
$Estado $nodo->Estado;    
    if(
$Estado == '00')    
    
rename($guardado_enviar_tbai,$guardado_enviado_tbai); /// atencion a esto
    
unset($facturas_en_TBAI);
    }    
     } 
// if($hacienda_foral == 'GIP') 
</div>Aparte tengo un script para visualizar la respuesta
En este lo más interesante puede ser la generación de la url del mensaje TBAI para verlo como si se tratara del código QR



Código PHP:
<?php

    $directorio_respuestas 
$directorio_TBAI.'Respuestas/';   
    if (!
is_dir($directorio_respuestas))  mkdir($directorio_respuestas0777);
    
$directorio_envios $directorio_TBAI.'Envios/';   
    if (!
is_dir($directorio_envios))  mkdir($directorio_envios0777);
    
    
$estado_tbai '';

    
$xml_enviado_tbai $orden_tbai.'.xsig';    
    
$guardado_enviado_tbai $directorio_envios.$xml_enviado_tbai;    
    if (
file_exists($guardado_enviado_tbai)) 
    
$estado_tbai 'Enviado'; else $estado_tbai 'No enviado';
    
$descripcion_TBAI $estado_tbai;

    if(
$estado_tbai == 'Enviado')
    {    
    
$msg_TBAI '';
    
$xml_actual_enviado simplexml_load_file($guardado_enviado_tbai);    
    
$signatureNodeActual $xml_actual_enviado->children('ds'true)->Signature;    
    
$SignatureValueFirmaFacturaActual $signatureNodeActual->SignatureValue;
    
$SignatureValueFirmaFacturaActual substr($SignatureValueFirmaFacturaActual,0,13);    
    
$factura_tbai_serie  $xml_actual_enviado->Factura->CabeceraFactura->SerieFactura;    
    
$factura_tbai_numero $xml_actual_enviado->Factura->CabeceraFactura->NumFactura;
    
$factura_tbai_fecha  $xml_actual_enviado->Factura->CabeceraFactura->FechaExpedicionFactura;    
    
$factura_tbai_fecha_dd substr($factura_tbai_fecha,0,2);
    
$factura_tbai_fecha_mm substr($factura_tbai_fecha,3,2);    
    
$factura_tbai_fecha_aa substr($factura_tbai_fecha,-2);        
    
$factura_tbai_importe  $xml_actual_enviado->Factura->DatosFactura->ImporteTotalFactura;        
    
$TBAIID  'TBAI'.$caracterSeparador.$cif_340.$caracterSeparador.$factura_tbai_fecha_dd;
    
$TBAIID .= $factura_tbai_fecha_mm.$factura_tbai_fecha_aa.$caracterSeparador;
    
$TBAIID .= $SignatureValueFirmaFacturaActual.$caracterSeparador;
    
$TBAIID utf8_encode($TBAIID);    
    
$cod_crc8 crc8($TBAIID);
    
$TBAIID  $TBAIID.$cod_crc8;
    unset(
$xml_actual_enviado);
    
$msg_TBAI =  $url_TBAI_QR.'?id='.$TBAIID.'&s='.$factura_tbai_serie.'&nf='.$factura_tbai_numero.'&i='.$factura_tbai_importe;
    
$msg_TBAI utf8_encode($msg_TBAI);    
    
$cod_crc8 crc8($msg_TBAI);
    
$msg_TBAI $msg_TBAI.'&cr='.$cod_crc8;    
    
$xml_respuesta $orden_tbai.'.xml';
    
$guardado_respuesta $directorio_respuestas.$xml_respuesta;
    if (
file_exists($guardado_respuesta)) 
    {
    
$respuesta_tbai simplexml_load_file($guardado_respuesta);
    if (
$respuesta_tbai === false) {
    
$estado_tbai 'No se puede leer la respuesta de TBAI';
    } else {
    
$estado_tbai 'Existe respuesta de TBAI';
    }
    } else {
    
$estado_tbai 'No se encuentra la respuesta de TBAI';
    
$sin_respuesta_tbai     '<?xml version="1.0" encoding="UTF-8"?>';
    
$sin_respuesta_tbai    .= '<Salida></Salida>';
    
$respuesta_tbai simplexml_load_string($sin_respuesta_tbai);    
    }
    
$descripcion_TBAI $estado_tbai;

    
$nodo $respuesta_tbai->Salida;
    
$Estado $nodo->Estado;
    
$FechaRecepcion $nodo->FechaRecepcion;

    if(
$Estado == '00')
    {    
    
$IdentificadorTBAI $nodo->IdentificadorTBAI;    
    
$Descripcion $nodo->Descripcion;
    
$Descripcion utf8_decode($Descripcion);
    
$CSV_tbai 'CSV: '.$nodo->CSV;
    
$ResultadosValidacion $nodo->ResultadosValidacion;
    
$CodigoRV $ResultadosValidacion->Codigo;
    if(
$CodigoRV)    
    
$DescripcionRV $errores_envio_TBAI["$CodigoRV"];    
    
$estado_tbai 'Correcto';    
    
$descripcion_TBAI $estado_tbai.': '.$IdentificadorTBAI.' '.$FechaRecepcion.' '.$Descripcion.' '.$CSV_tbai;
    if(
$CodigoRV)
    {    
    
$descripcion_TBAI .= ' '.$CodigoRV.' '.$DescripcionRV;
    
$estado_tbai 'Aviso';    
    }
    }    
    
    if(
$Estado == '01')    
    {
    
$ResultadosValidacion $nodo->ResultadosValidacion;
    
$CodigoRV $ResultadosValidacion->Codigo;
    
$DescripcionRV $errores_envio_TBAI["$CodigoRV"];    
    if(
substr($DescripcionRV,0,5) == 'Aviso' || $CodigoRV == '005' )
    
$estado_tbai 'Aviso';    
    else    
$estado_tbai 'Rechazado';
    
$descripcion_TBAI $estado_tbai.': '.$FechaRecepcion.' '.$CodigoRV.' '.$DescripcionRV;
    }
    unset(
$respuesta_tbai);
    } 
//  enviado
Tengo, si interesa, la generación del código QR para PDF con la libreria fpdf.


Comentamos ...
Responder Con Cita
  #8  
Antiguo 05-01-2022
GorkaB GorkaB is offline
Miembro
 
Registrado: dic 2021
Posts: 11
Poder: 0
GorkaB Va por buen camino
Cita:
Empezado por bilbur Ver Mensaje
Os adjunto lo que tengo hecho para el envío a Gipuzkoa...
...Tengo, si interesa, la generación del código QR para PDF con la libreria fpdf.

Comentamos ...

Me interesa la generación del QR. Bueno, primero de todo, muchísimas gracias por lo compartido, me está ayudando muchísimo. ¿Hay algún apartado en donde estén recopilados todos los archivos de php?


Muchísimas gracias de nuevo,
Un saludo
Responder Con Cita
  #9  
Antiguo 05-05-2021
Edgar7 Edgar7 is offline
Miembro
 
Registrado: nov 2020
Posts: 10
Poder: 0
Edgar7 Va por buen camino
Cita:
Empezado por bilbur Ver Mensaje
Si necesitas ayuda en la implementación, me dices. No sea que se me olvidara subir algo.
Para comprobar las firmas y antes de enviarlas yo utilizo estos dos enlaces

Si te da correcto en las dos validaciones pues ¡eureka!

Lo primero de todo, gracias por compartir el código de PHP, y a todos los miembros del hilo por que se aclaran muchas dudas que se va generando durante el desarrollo.

Llevo ya un tiempo con esto y la firma de momento es con diferencia lo que mas problema me esta dando, y tras probar tu codigo la cuestión es:

Y si no da correcto en ninguna validación?? Estoy usando un certificado de empresa con extensión p12 pero creo que ese no es el problema, y ya no se que mas hacer, he intentado comparar con un archivo TicketBAI que de ejemplo que me descargue de ello y ese si que pasa la validación pero por mas que los comparo no entiendo muy bien el problema.

Signature is Invalid
Number of Reference Digests = 3
Reference 1 digest is invalid because the computed digest differs from the digest in the XML.
Reference 2 digest is invalid because the computed digest differs from the digest in the XML.
Reference 3 digest is valid.

¿Podrías confirmarme si el código que tienes puesto te genera correctamente la firma o decirme si te ha pasado algo similar?

Muchas gracias.
Responder Con Cita
  #10  
Antiguo 05-05-2021
Elyas Elyas is offline
Registrado
 
Registrado: mar 2021
Posts: 6
Poder: 0
Elyas Va por buen camino
Cita:
Empezado por Edgar7 Ver Mensaje
Lo primero de todo, gracias por compartir el código de PHP, y a todos los miembros del hilo por que se aclaran muchas dudas que se va generando durante el desarrollo.

Llevo ya un tiempo con esto y la firma de momento es con diferencia lo que mas problema me esta dando, y tras probar tu codigo la cuestión es:

Y si no da correcto en ninguna validación?? Estoy usando un certificado de empresa con extensión p12 pero creo que ese no es el problema, y ya no se que mas hacer, he intentado comparar con un archivo TicketBAI que de ejemplo que me descargue de ello y ese si que pasa la validación pero por mas que los comparo no entiendo muy bien el problema.

Signature is Invalid
Number of Reference Digests = 3
Reference 1 digest is invalid because the computed digest differs from the digest in the XML.
Reference 2 digest is invalid because the computed digest differs from the digest in the XML.
Reference 3 digest is valid.

¿Podrías confirmarme si el código que tienes puesto te genera correctamente la firma o decirme si te ha pasado algo similar?

Muchas gracias.
Podrías hacerlo con chilkat, solo tienes que coger un xml ya firmado y válido, cualquiera, lo metes en el generador de la firma y se te genera automáticamente un código que te genera una firma igual. Ahora solo te falta alimentar el xml con datos dinámicos y lo tienes. Otra cosa es que es de pago, pero funciona. El otro código no lo he probado.
Responder Con Cita
  #11  
Antiguo 05-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
Cita:
Empezado por Edgar7 Ver Mensaje
Lo primero de todo, ...

Signature is Invalid
Number of Reference Digests = 3
Reference 1 digest is invalid because the computed digest differs from the digest in the XML.
Reference 2 digest is invalid because the computed digest differs from the digest in the XML.
Reference 3 digest is valid.

¿Podrías confirmarme si el código que tienes puesto te genera correctamente la firma o decirme si te ha pasado algo similar?

Muchas gracias.

El código me funciona

Versión PHP 5.6.40
Has de ser muy estricto en el xml con el orden de las "references" y con los "digest"


Reference 1:

Código PHP:
        '<ds:Reference URI="#'.$this->SignedProperties.'" Type="http://uri.etsi.org/01903#SignedProperties">' .
        
'<ds:Transforms>' .
        
'<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>' .
        
'</ds:Transforms>' .        
        
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>' .
        
'<ds:DigestValue>'.$propDigest.'</ds:DigestValue>' .
        
'</ds:Reference>' 
Verás en el firmador:

Código PHP:
 $aconop     str_replace('<xades:SignedProperties''<xades:SignedProperties ' $xmnls_signedprops$prop);
    
$propDigest $this->retC14DigestSha1($aconop); 
Que llama a, también dentro del firmador:


Código PHP:
   public function retC14DigestSha1($strcadena)
    {
    
$strcadena    str_replace("\r"""str_replace("\n"""$strcadena));
    
$d1p        = new DOMDocument('1.0''UTF-8');
    
$d1p->loadXML($strcadena);
    
$strdata    $d1p->C14N();
    return 
base64_encode(hash('sha256' $strdatatrue ));
    } 
Ve despacio, prueba con la reference 1 y me dices
Si no avanzas, puedes hacerme llegar, no sé como, un xml de prueba firmado



Un saludo
Responder Con Cita
  #12  
Antiguo 20-12-2021
musinho musinho is offline
Miembro
 
Registrado: dic 2021
Posts: 18
Poder: 0
musinho Va por buen camino
Aupa,

Alguien ha implementado la clase firmador que hizo bilbur? yo no consigo validar los documentos.
Al enviarlo a BATUZ me arroja el siguiente error:

Código:
La firma no cumple los requisitos de la política de firma TicketBAI.(El mensaje ha sido modificado en tránsito o la firma no está bien realizada
Y al probar el xml firmado también me arroja lo siguiente (con las tools de chilkat):

Código:
Signature is Invalid
Number of Reference Digests = 3
Reference 1 digest is invalid because the computed digest differs from the digest in the XML.
Reference 2 digest is invalid because the computed digest differs from the digest in the XML.
Reference 3 digest is valid.
Eskerrik asko!
Responder Con Cita
  #13  
Antiguo 20-12-2021
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.331
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por musinho Ver Mensaje
Código:
La firma no cumple los requisitos de la política de firma TicketBAI.(El mensaje ha sido modificado en tránsito o la firma no está bien realizada
Y al probar el xml firmado también me arroja lo siguiente (con las tools de chilkat):

Este error suele ir asociado en la mayoría de los casos a la codificación del fichero. O a cambios en la codificación entre que se genera y se firma.
Para lo segundo, tal vez tendrías que poner qué estás enviando en el XML del TicketBAI en la sección de Politicas de firma, para que lo veamos.
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #14  
Antiguo 20-12-2021
Sistel Sistel is offline
Miembro
 
Registrado: nov 2019
Ubicación: Bilbao
Posts: 373
Poder: 5
Sistel Va por buen camino
Cita:
Empezado por musinho Ver Mensaje
Aupa,

Alguien ha implementado la clase firmador que hizo bilbur? yo no consigo validar los documentos.
Al enviarlo a BATUZ me arroja el siguiente error:

Código:
La firma no cumple los requisitos de la política de firma TicketBAI.(El mensaje ha sido modificado en tránsito o la firma no está bien realizada
Y al probar el xml firmado también me arroja lo siguiente (con las tools de chilkat):

Código:
Signature is Invalid
Number of Reference Digests = 3
Reference 1 digest is invalid because the computed digest differs from the digest in the XML.
Reference 2 digest is invalid because the computed digest differs from the digest in the XML.
Reference 3 digest is valid.
Eskerrik asko!
Hola musinho,

A mí me fue perfecta desde el primer momento.

Pero, como muy bien dice Neftali, cualquier cambio de codificación puede arruinarte el fichero.

Saludos
Responder Con Cita
  #15  
Antiguo 12-05-2021
sline sline is offline
Miembro
 
Registrado: may 2021
Posts: 18
Poder: 0
sline Va por buen camino
Gracias bilbur!

todo esto me ha permitido continuar con el proceso, pero me encuentro un contratiempo con el qr.
Para generar el código QR es necesario los 13 primeros caracteres de la firma, en ocasiones la firma contiene caracteres como + y al entrar la url para batuz muestra que es incorrecta.
No encuentro nada (o al menos no lo he visto) que limite qué caracteres usar o no, o si hubiera que reemplazarlos.

Cita:
Empezado por bilbur Ver Mensaje
Nos hemos quedado aquí:
Responder Con Cita
  #16  
Antiguo 12-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
Cita:
Empezado por sline Ver Mensaje
Gracias bilbur!

todo esto me ha permitido continuar con el proceso, pero me encuentro un contratiempo con el qr.
Para generar el código QR es necesario los 13 primeros caracteres de la firma, en ocasiones la firma contiene caracteres como + o / y al entrar la url para batuz muestra que es incorrecta.
No encuentro nada (o al menos no lo he visto) que limite qué caracteres usar o no, o si hubiera que reemplazarlos.

te explico el código de la dirección qr para GIP


$caracterSeparador = '-' // el guión medio o tecla del menos
$cif_340 = cif de la empresa 9 dígitos
$dd$mm$aaa = dia mes año sin separador // 12052021
$SignatureValueFirmaFacturaActua = substr($SignatureValueFirmaFacturaActual,0,13); // 13 primeras posiciones
$TBAIID = utf8_encode($TBAIID); // lo codificas a utf8
$cod_crc8 = crc8($TBAIID); // calculas el crc8
$TBAIID = $TBAIID.$cod_crc8; // se lo añades a la cadena TBAIID
$msg_TBAI = $url_TBAI_QR.'?id='.$TBAIID.'&s='.serie.'&nf='.numero.'&i='.$importe; // creas el enlace TBAI
$msg_TBAI = utf8_encode($msg_TBAI); // otra vez a utf8
$cod_crc8 = crc8($msg_TBAI); // calculas el nuevo crc8
$msg_TBAI = $msg_TBAI.'&cr='.$cod_crc8; // y se lo añades al enalce

Código PHP:
   $msg_TBAI '';
    
$xml_actual_enviado simplexml_load_file($guardado_enviado_tbai);    
    
$signatureNodeActual $xml_actual_enviado->children('ds'true)->Signature;    
    
$SignatureValueFirmaFacturaActual $signatureNodeActual->SignatureValue;
    
$SignatureValueFirmaFacturaActual substr($SignatureValueFirmaFacturaActual,0,13);    
    
$factura_tbai_serie  $xml_actual_enviado->Factura->CabeceraFactura->SerieFactura;    
    
$factura_tbai_numero $xml_actual_enviado->Factura->CabeceraFactura->NumFactura;
    
$factura_tbai_fecha  $xml_actual_enviado->Factura->CabeceraFactura->FechaExpedicionFactura;    
    
$factura_tbai_fecha_dd substr($factura_tbai_fecha,0,2);
    
$factura_tbai_fecha_mm substr($factura_tbai_fecha,3,2);    
    
$factura_tbai_fecha_aa substr($factura_tbai_fecha,-2);        
    
$factura_tbai_importe  $xml_actual_enviado->Factura->DatosFactura->ImporteTotalFactura;        
    
$TBAIID  'TBAI'.$caracterSeparador.$cif_340.$caracterSeparador.$dd;
    
$TBAIID .= $mm.$aaaa.$caracterSeparador;
    
$TBAIID .= $SignatureValueFirmaFacturaActual.$caracterSeparador;
    
$TBAIID utf8_encode($TBAIID);    
    
$cod_crc8 crc8($TBAIID);
    
$TBAIID  $TBAIID.$cod_crc8;
    unset(
$xml_actual_enviado);
    
$msg_TBAI =  $url_TBAI_QR.'?id='.$TBAIID.'&s='.$factura_tbai_serie.'&nf='.$factura_tbai_numero.'&i='.$factura_tbai_importe;
    
$msg_TBAI utf8_encode($msg_TBAI);    
    
$cod_crc8 crc8($msg_TBAI);
    
$msg_TBAI $msg_TBAI.'&cr='.$cod_crc8
Al final queda algo así:

'https://tbai.prep.gipuzkoa.eus/qr/?id=TBAI-B09203993-210421-YQw6BwvgmOe9h-235&s=FR&nf=000115&i=-5.44&cr=012'

Este enlace funciona
Responder Con Cita
  #17  
Antiguo 12-05-2021
sline sline is offline
Miembro
 
Registrado: may 2021
Posts: 18
Poder: 0
sline Va por buen camino
Eso mismo es lo que hago, aquí pongo 2 ejemplos:


OK: https_//batuz.eus/QRTBAI/?id=TBAI-79732487C-120521-ME4g0D7g/iyVk-038&s=HB202105&nf=00020&i=382.67&cr=189
KO: https_//batuz.eus/QRTBAI/?id=TBAI-79732487C-120521-Kv+9Uth14cqcj-236&s=HS202105&nf=00021&i=1209.10&cr=121
Los datos de la URL son incorrectos (ERR_QR_003)

el 3er carácter de la firma es + "Kv+9Uth14cqcj" y el + en una url por GET suele ser un espacio.
parte de la firma en el xml:
....<ds:SignatureValue Id="xmldsig-118aebca-ded6-937b-16cd-782aa4431aab-sigvalue">Kv+9Uth14cqcjZzk286K7h+FLkm8W5UHukR8+GJkmRvJyKV3.....



Cita:
Empezado por bilbur Ver Mensaje
te explico el código de la dirección qr para GIP
Responder Con Cita
  #18  
Antiguo 12-05-2021
bilbur bilbur is offline
Miembro
 
Registrado: dic 2019
Posts: 60
Poder: 5
bilbur Va por buen camino
Cita:
Empezado por sline Ver Mensaje
Eso mismo es lo que hago, aquí pongo 2 ejemplos:


OK: https_//batuz.eus/QRTBAI/?id=TBAI-79732487C-120521-ME4g0D7g/iyVk-038&s=HB202105&nf=00020&i=382.67&cr=189
KO: https_//batuz.eus/QRTBAI/?id=TBAI-79732487C-120521-Kv+9Uth14cqcj-236&s=HS202105&nf=00021&i=1209.10&cr=121

Confirma los crc8
En este validador parace que da otros valores
https://crccalc.com/
Estaré más atontado de lo habitual
Ya me dices
Responder Con Cita
  #19  
Antiguo 27-05-2021
luismartin luismartin is offline
Miembro
 
Registrado: may 2021
Posts: 18
Poder: 0
luismartin Va por buen camino
Estoy usando la librería PHP que publicó Bilbur, la cual es de gran ayuda para la generación de la firma xades enveloped mediante PHP (a la mierda java y Autofirma!).
Sin embargo, lo que estoy recibiendo ahora, es un código http 503, pero con respuesta XML por parte del servidor, en la cual se indica:

Código:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:TicketBaiResponse xmlns:ns2="urn:ticketbai:emision">
<Salida>
<FechaRecepcion>27-05-2021 11:38:02</FechaRecepcion>
<Estado>01</Estado>
<Descripcion>Rechazado</Descripcion>
<Azalpena>Baztertua</Azalpena>
<ResultadosValidacion>
<Codigo>006</Codigo>
<Descripcion>Error inesperado en la verificación del certificado remitente.</Descripcion>
<Azalpena>Ustekabeko errorea bidaltzailearen ziurtagiria egiaztatzean.</Azalpena>
</ResultadosValidacion>
</Salida>
</ns2:TicketBaiResponse>
No he encontrado referencia a este error en la documentación oficial. En ella, el código 006 se refiere a "El servicio de recepción no está disponible. Repita la operación más tarde".
Sabéis algo de esto?
Responder Con Cita
  #20  
Antiguo 27-05-2021
Band Band is offline
Miembro
 
Registrado: may 2021
Posts: 35
Poder: 0
Band Va por buen camino
Cita:
Empezado por luismartin Ver Mensaje
Estoy usando la librería PHP que publicó Bilbur, la cual es de gran ayuda para la generación de la firma xades enveloped mediante PHP (a la mierda java y Autofirma!).
Sin embargo, lo que estoy recibiendo ahora, es un código http 503, pero con respuesta XML por parte del servidor, en la cual se indica:

Código:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:TicketBaiResponse xmlns:ns2="urn:ticketbai:emision">
<Salida>
<FechaRecepcion>27-05-2021 11:38:02</FechaRecepcion>
<Estado>01</Estado>
<Descripcion>Rechazado</Descripcion>
<Azalpena>Baztertua</Azalpena>
<ResultadosValidacion>
<Codigo>006</Codigo>
<Descripcion>Error inesperado en la verificación del certificado remitente.</Descripcion>
<Azalpena>Ustekabeko errorea bidaltzailearen ziurtagiria egiaztatzean.</Azalpena>
</ResultadosValidacion>
</Salida>
</ns2:TicketBaiResponse>
No he encontrado referencia a este error en la documentación oficial. En ella, el código 006 se refiere a "El servicio de recepción no está disponible. Repita la operación más tarde".
Sabéis algo de esto?
Me sucede exactamente lo mismo. Tengo mis dudas en que estemos enviando correctamente el certificado... que en mi caso y con curl lo hago así:

' --cert-type P12 --cert sello_entidad_act.p12:IZDesa2021 '

En este caso es un certificado de izenpe de prueba que cualquiera se puede descargar.

En el xml tengo puesto también, dentro de <Sujetos>:

<EmitidaPorTercerosODestinatario>T</EmitidaPorTercerosODestinatario>

Tal y como muy bien se me aconsejó.

El servicio no parece caído, por lo que si alguien soluciona este tema que comente el motivo o solución que haya encontrado.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
SII -Nuevo sistema de la Agencia Tributaria española de envío de datos vía Webservice newtron Internet 3565 Hace 13 Horas 11:04:13
Como utilizar la ayuda del nuevo Sistema Operativo gluglu Humor 3 24-09-2007 09:39:05
Aplicacion Agencia De Viajes ArdiIIa Varios 9 20-01-2007 16:49:53
El Vasco Aguirre Al González La Taberna 5 26-05-2006 09:22:28
Microsoft ha lanzado su nuevo sistema operativo DarkByte Humor 0 25-01-2004 09:21:14


La franja horaria es GMT +2. Ahora son las 00:22:16.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi