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 17-02-2024
ermendalenda ermendalenda is offline
Miembro
 
Registrado: ago 2021
Posts: 886
Poder: 3
ermendalenda Va por buen camino
Cita:
Empezado por ramherfer Ver Mensaje
Aqui ya me he perdido.... el hash antes de generar el qr de la factura

Si que me gustaría ver un ejemplo de como encapsulas uno o varios xml generados con anterioridad. Me sería de mucha ayuda
Yo te lo pongo pero no sé si te vas a liar más, ya que yo trabajo en Vb6 para generar el xml y despuñess las firmas y encapsulamientos soaps lo hago en php con llamadas desde curl.
En Delphi hay otras formas que los compañeros del foro seguro que te pueden guiar.

Mira el código para generar el XML (A pelo) es de esta forma:
Código:
close #92
Open "C:\xmls\" & nombre_fichero & ".xml" For Output  As #92
 Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
               Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
                If es_anulacion Then
                    
                    Print #92, "<sum:BajaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                Else
                    Print #92, "<sum:AltaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                End If
                Print #92, "<sum1:Cabecera>"
                Print #92, "<sum1:IDVersion>" & version_vfactu & "</sum1:IDVersion>"
 Print #92, "<sum1:ObligadoEmision>"
                Print #92, "<sum1:NombreRazon>" & TEXT_TO_UTF8(nombre_empresa) & "</sum1:NombreRazon>"
                Print #92, "<sum1:NIF>" & nif & "</sum1:NIF>"
                Print #92, "</sum1:ObligadoEmision>"
               select case tipo 

                    "anulacion"
                        Print #92, "<sum1:TipoRegistroAEAT>T3</sum1:TipoRegistroAEAT>"
                    
                     "sustitutiva"
                            Print #92, "<sum1:TipoRegistroAEAT>T1</sum1:TipoRegistroAEAT>"
                     "normal"
                            Print #92, "<sum1:TipoRegistroAEAT>T0</sum1:TipoRegistroAEAT>"
               end select
***Y ahora lo que voy a escribir lo voy guardando en la variable datohash para calcular el hash cuando tenga en la variable lo que necesite
datoxml = "<sum:RegistroFacturacion>"
                datohash = datoxml
                If es_anulacion = False Then
    
                    Print #92, "<sum:RegistroAltaFacturas>" & datoxml;
                Else
                    Print #92, "<sum:RegistroAnulacionFacturas>" & datoxml;
                End If
                
                 datoxml = "<sum1:IDFactura>"
                datohash = datohash & datoxml
                Print #92, datoxml;
                .......
****AL FINAL CALCULO EL HASH USANDO LAS API DE WINDOWS****
***  CryptCreateHash, ¿¿¿CryptAcquireContext, etc... de la libreria  "advapi32.dll"*****

                huella = UCase(CreateHashString(datohash, CALG_SHA_256))
                    
*** Inserto el hash en el xml y el resto de nodos
                   Print #92, "<sum1:Huella>" & huella & "</sum1:Huella>"
                    
                    Print #92, "<sum1:TipoHash>01</sum1:TipoHash>"
                    Print #92, "</sum:DatosControl>"
                    If es_anulacion Then
                        Print #92, "</sum:RegistroAnulacionFacturas>"
                        Print #92, "</sum:BajaFactuSistemaFacturacion>"
                    Else
                        Print #92, "</sum:RegistroAltaFacturas>"
                        Print #92, "</sum:AltaFactuSistemaFacturacion>"
                    End If
                   close #92
Por otro lado puedo encapsular en php, ya que en VB6 desconozco la forma, pero en mi caso hemos pagado a una empresa la programación y el servicio de conservación y le vamos a enviar los xmls sin encapsular para que hagan toda la hilera de verificación del encadenamiento, validación schema xml-xsd, conservación, encapsulamiento, envios y control de errores, el envio lo harán con su certificado y ellos le dan este servicio a cada cliente al que le cobraremos un precio "razonable", y me libero de la parte peor. Cada cliente recibirá o podrá consultar el reporte de los envios y si hay errores se avisará y se tomará las medidas según cada caso, esto ya lo tenemos definido.
Responder Con Cita
  #2  
Antiguo 17-02-2024
ermendalenda ermendalenda is offline
Miembro
 
Registrado: ago 2021
Posts: 886
Poder: 3
ermendalenda Va por buen camino
codigo ejemplo php encapsulamiento y envio

Aquí te dejo un encapsulamiento y envio, totalmente funcional para face y faceb2b en entornos de prueba y producción, si aprendes como funciona lo puedes modificar para cualquier definición que hagan teniendo en cuenta que yo le paso el path donde tengo el fichero y los datos por curl de esta forma:
Código:
curl --connect-timeout 10 --insecure -A "FacturaePHP/1.7.1" -H "SOAPAction: https://webservice.face.gob.es#enviarFactura" --data "@C:\xml\Facturare_FICTICIO_fichero.xml" --cert-type P12 --cert c:\....\fichero_certificado.pfx:clave -H "Content-Type: text/xml" https://se-face-webservice.redsara.es/facturasspp2 -o C:\respuestas\Respuesta_face_o.html -D C:\respuestas\Respuesta_face_D.html
Código PHP:
 <?php 
//ASIGNA EL ENTORNO QUE VAMOS A USAR  $endpoint como variable de uso GLOBALS
//************************************
//*************  FACE   **************
//************************************
//  ENTORNO DE PRODUCCION
//$endpoint= "https://webservice.face.gob.es/facturasspp2" :
      
//  ENTORNO DE PRUEBAS
$endpoint"https://se-face-webservice.redsara.es/facturasspp2";      
//************************************


//************************************
//************  FACEB2B   ************
//************************************
//  ENTORNO DE PRODUCCION
//$endpoint= "https://ws.faceb2b.gob.es/sv1/invoice" :

//  ENTORNO DE PRUEBAS
//$endpoint= "https://se-ws-faceb2b.redsara.es/sv1/invoice";
//************************************





//**Asigna a $datos la variable de la llamada curl (fichero) que contiene 2 variables separadas por signo "="
$datos $_GET['fichero'];

//***Asigno $datos a un array ya que contiene 2 campos 
$varias=explode("=",$datos);
//***El primer campo del array contiene el nombre del fichero del certificado

// **EJEMPLO PFX $dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/certs/Certificado.pfx' );
//variable de uso GLOBALS
$dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/certs/'.$varias[1] );

//***El segundo campo del array contiene el password del certificado
//variable de uso GLOBALS
$clave=$varias[2];

//variable de uso GLOBALS
$filename=$varias[3];
$NombreFichero=$varias[3];

//variable de uso GLOBALS
$xml2=file_get_contents("php://input");


//variable de uso GLOBALS
$version "1.7.1";

// Cargamos la factura en una instancia de FacturaeFile

//$invoice2 = new InvoiceTest();

//$invoice2->EnviarFactura($xml2);
//*****************************
//****** ENVIAR POR FACE ******
//*****************************
    
$invoice = new FacturaeFile();
    
$invoice=$GLOBALS["xml2"];


    
    
$nulo=null;
    
$face = new FaceTrait();

    
$res =$face->sendInvoice("verifactu@gmail.com"$invoice);


//*****************************
//***** ENVIAR POR FACEB2B ****
//*****************************

//    $invoice = new FacturaeFile();
//    $invoice=$GLOBALS["xml2"];
//    $nulo=null;
//    $face = new FaceB2BTrait();

//    $res =$face->sendInvoice("verifactu@gmail.com", $invoice);




/**
 * Gets both public and private keys from a PKCS#12 certificate store or a PEM
 * file (X.509 certificate).
 */
class KeyPairReader {
  private 
$publicChain = [];
  private 
$privateKey null;


  
/**
   * Get public certificates chain from child to top CA
   * @return string[] Array of PEM strings
   */
  
public function getPublicChain() {
    return 
$this->publicChain;
  }


  
/**
   * Get public key
   * @return string|null Certificate for the Public Key in PEM format
   */
  
public function getPublicKey() {
    return empty(
$this->publicChain) ? null $this->publicChain[0];
  }


  
/**
   * Get private key
   * @return \OpenSSLAsymmetricKey|resource|null Decrypted Private Key
   */
  
public function getPrivateKey() {
    return 
$this->privateKey;
  }


  
/**
   * KeyPairReader constructor
   *
   * @param string      $publicPath  Path to public key in PEM or PKCS#12 file
   * @param string|null $privatePath Path to private key (null for PKCS#12)
   * @param string      $passphrase  Private key passphrase
   */
  
public function __construct($publicPath$privatePath=null$passphrase="") {
    if (
is_null($privatePath)) {
      
$this->readPkcs12($GLOBALS["dir_cert"], $passphrase);
    } else {
      
$this->readX509($GLOBALS["dir_cert"], $privatePath$passphrase);
    }
  }


  
/**
   * Read a X.509 certificate and PEM encoded private key
   *
   * @param string $publicPath  Path to public key PEM file
   * @param string $privatePath Path to private key PEM file
   * @param string $passphrase  Private key passphrase
   */
  
private function readX509($publicPath$privatePath$passphrase) {
    if (!
is_file($GLOBALS["dir_cert"]) || !is_file($privatePath)) return;

    
// Validate and normalize public key
    
$publicKey openssl_x509_read(file_get_contents($GLOBALS["dir_cert"]));
    if (empty(
$publicKey)) return;
    
openssl_x509_export($publicKey$publicKeyPem);
    
$this->publicChain = array($publicKeyPem);
    
    
// Decrypt private key
    
$this->privateKey openssl_pkey_get_private(file_get_contents($privatePath), $passphrase);
  }


  
/**
   * Read a PKCS#12 Certificate Store
   *
   * @param string $certPath   The certificate store file name
   * @param string $passphrase Password for unlocking the PKCS#12 file
   */
  
private function readPkcs12($certPath$passphrase) {
    if (!
is_file($certPath)) return;
    if (
openssl_pkcs12_read(file_get_contents($certPath), $store$passphrase)) {
      
$this->publicChain = array($store['cert']);
      if (!empty(
$store['extracerts'])) {
        
$this->publicChain array_merge($this->publicChain$store['extracerts']);
      }
      
$this->privateKey openssl_pkey_get_private($store['pkey']);
      unset(
$store);
    }
  }

}
class 
XmlTools {

  
/**
   * Escape XML value
   * @param  string $value Input value
   * @return string        Escaped input
   */
  
public function escape($value) {
    return 
htmlspecialchars($valueENT_XML1'UTF-8');
  }


  
/**
   * Generate random ID
   *
   * This method is used for generating random IDs required when signing the
   * document.
   *
   * @return int Random number
   */
  
public function randomId() {
    if (
function_exists('random_int')) return random_int(0x100000000x7FFFFFFF);
    return 
rand(100000999999);
  }


  
/**
   * Inject namespaces
   * @param  string          $xml   Input XML
   * @param  string|string[] $newNs Namespaces
   * @return string                 Canonicalized XML with new namespaces
   */
  
public function injectNamespaces($xml$newNs) {
    if (!
is_array($newNs)) $newNs = array($newNs);
    
$xml explode(">"$xml2);
    
$oldNs explode(" "$xml[0]);
    
$elementName array_shift($oldNs);

    
// Combine and sort namespaces
    
$xmlns = array();
    
$attributes = array();
    foreach (
array_merge($oldNs$newNs) as $name) {
      if (
strpos($name'xmlns:') === 0) {
        
$xmlns[] = $name;
      } else {
        
$attributes[] = $name;
      }
    }
    
sort($xmlns);
    
sort($attributes);
    
$ns array_merge($xmlns$attributes);

    
// Generate new XML element
    
$xml $elementName " " implode(' '$ns) . ">" $xml[1];
    return 
$xml;
  }


  
/**
   * To Base64
   * @param  string  $bytes  Input
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Base64 response
   */
  
public function toBase64($bytes$pretty=false) {
    
$res base64_encode($bytes);
    return 
$pretty $this->prettify($res) : $res;
  }


  
/**
   * Prettify
   * @param  string $input Input string
   * @return string        Multi-line resposne
   */
  
private function prettify($input) {
    return 
chunk_split($input76"\n");
  }


  
/**
   * Get digest in SHA-512
   * @param  string  $input  Input string
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Digest
   */
  
public function getDigest($input$pretty=false) {
    return 
$this->toBase64(hash("sha512"$inputtrue), $pretty);
  }


  
/**
   * Get certificate
   * @param  string  $pem    Certificate for the public key in PEM format
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Base64 Certificate
   */
  
public function getCert($pem$pretty=true) {
    
$pem str_replace("-----BEGIN CERTIFICATE-----"""$pem);
    
$pem str_replace("-----END CERTIFICATE-----"""$pem);
    
$pem str_replace("\n"""str_replace("\r"""$pem));
    if (
$pretty$pem $this->prettify($pem);
    return 
$pem;
  }




  
/**
   * Get signature in SHA-1
   * @param  string  $payload    Data to sign
   * @param  string  $privateKey Private Key
   * @param  boolean $pretty     Pretty Base64 response
   * @return string              Base64 Signature
   */
  
public function getSignature($payload$privateKey$pretty=true) {
    
openssl_sign($payload$signature$privateKey);
    return 
$this->toBase64($signature$pretty);
  }


}

Class 
Faceb2bTrait {
  
/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.faceb2b.gob.es";
  }


  
/**
   * Send invoice
   * @param  FacturaeFile      $invoice    Invoice
   * @param  FacturaeFile|null $attachment Optional attachment
   * @return SimpleXMLElement              Response
   */
  
public function sendInvoice($invoice$attachment=null) {
    
$tools = new XmlTools();
    
$req '<web:SendInvoice><request>';

    
$req .= '<invoiceFile>' .
        
'<content>' $tools->toBase64($GLOBALS["xml2"]) . '</content>' .
        
'<name>' $GLOBALS["NombreFichero"] . '</name>' .
        
'<mime>text/xml</mime>' // Mandatory MIME type
      
'</invoiceFile>';

    if (!
is_null($attachment)) {
      
$req .= '<attachmentFile>' .
          
'<content>' $tools->toBase64($attachment->getData()) . '</content>' .
          
'<name>' $attachment->getFilename() . '</name>' .
          
'<mime>' $attachment->getMimeType() . '</mime>' .
        
'</attachmentFile>';
    }

    
$req .= '</request></web:SendInvoice>';
    
//$soap=new SoapClient1();
$soap = new FacturaeFile();
      
    return 
$soap->request($req);
  }


  
/**
   * Get invoice details
   * @param  string           $regId Registry number
   * @return SimpleXMLElement        Response
   */
  
public function getInvoiceDetails($regId) {
    return 
$this->request('<web:GetInvoiceDetails><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:GetInvoiceDetails>');
  }


  
/**
   * Request invoice cancellation
   * @param  string           $regId   Registry number
   * @param  string           $reason  Reason code
   * @param  string|null      $comment Optional comments
   * @return SimpleXMLElement          Response
   */
  
public function requestInvoiceCancellation($regId$reason$comment=null) {
    
$req '<web:RequestInvoiceCancellation><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    
$req .= '<reason>' $reason '</reason>';
    if (!
is_null($comment)) {
      
$req .= '<comment>' $comment '</comment>';
    }
    
$req .= '</request></web:RequestInvoiceCancellation>';

    return 
$this->request($req);
  }


  
/**
   * Get registered invoices
   * @param  string|null      $receivingUnit Receiving unit code
   * @return SimpleXMLElement                Response
   */
  
public function getRegisteredInvoices($receivingUnit=null) {
    
$req '<web:GetRegisteredInvoices><request>';
    if (
is_null($receivingUnit)) {
      
$req .= '<receivingUnit>' $receivingUnit '</receivingUnit>';
    }
    
$req .= '</request></web:GetRegisteredInvoices>';
    return 
$this->request($req);
  }


  
/**
   * Get invoice cancellations
   * @return SimpleXMLElement Response
   */
  
public function getInvoiceCancellations() {
    return 
$this->request('<web:GetInvoiceCancellations><request>' .
      
'</request></web:GetInvoiceCancellations>');
  }


  
/**
   * Download invoice
   * @param  string           $regId    Registry number
   * @param  boolean          $validate Validate invoice
   * @return SimpleXMLElement           Response
   */
  
public function downloadInvoice($regId$validate=true) {
    
$req '<web:DownloadInvoice><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    if (
$validate) {
      
$req .= '<signatureValidationMode>validate</signatureValidationMode>';
    }
    
$req .= '</request></web:DownloadInvoice>';
    return 
$this->request($req);
  }


  
/**
   * Confirm invoice download
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function confirmInvoiceDownload($regId) {
    return 
$this->request('<web:ConfirmInvoiceDownload><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:ConfirmInvoiceDownload>');
  }


  
/**
   * Reject invoice
   * @param  string           $regId   Registry number
   * @param  string           $reason  Reason code
   * @param  string|null      $comment Optional comments
   * @return SimpleXMLElement          Response
   */
  
public function rejectInvoice($regId$reason$comment=null) {
    
$req '<web:RejectInvoice><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    
$req .= '<reason>' $reason '</reason>';
    if (!
is_null($comment)) {
      
$req .= '<comment>' $comment '</comment>';
    }
    
$req .= '</request></web:RejectInvoice>';
    return 
$this->request($req);
  }


  
/**
   * Mark invoice as paid
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function markInvoiceAsPaid($regId) {
    return 
$this->request('<web:MarkInvoiceAsPaid><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:MarkInvoiceAsPaid>');
  }


  
/**
   * Accept invoice cancellation
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function acceptInvoiceCancellation($regId) {
    return 
$this->request('<web:AcceptInvoiceCancellation><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:AcceptInvoiceCancellation>');
  }


  
/**
   * Reject invoice cancellation
   * @param  string           $regId   Registry number
   * @param  string           $comment Comment
   * @return SimpleXMLElement          Response
   */
  
public function rejectInvoiceCancellation($regId$comment) {
    return 
$this->request('<web:RejectInvoiceCancellation><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'<comment>' $comment '</comment>' .
      
'</request></web:RejectInvoiceCancellation>');
  }



  
/**
   * Get codes
   * @param  string           $type Code type
   * @return SimpleXMLElement       Response
   */
  
public function getCodes($type="") {
    return 
$this->request('<web:GetCodes><request>' .
      
'<codeType>' $type '</codeType>' .
      
'</request></web:GetCodes>');
  }
}
//trait FaceTrait {
class FaceTrait {
  
/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.face.gob.es";
  }
  
/**
   * Send invoice
   * @param  string           $email       Email address
   * @param  FacturaeFile     $invoice     Invoice
   * @param  FacturaeFile[]   $attachments Attachments
   * @return SimpleXMLElement              Response
   */
  
public function sendInvoice($email$invoice$attachments=array()) {
    
$tools = new XmlTools();
    
$req '<web:enviarFactura><request>';
    
$req .= '<correo>' $email '</correo>';
    
$req .= '<factura>' .
        
'<factura>' $tools->toBase64($GLOBALS["xml2"]) . '</factura>' .
        
'<nombre>' $GLOBALS["NombreFichero"] . '</nombre>' .
        
'<mime>application/xml</mime>' // Mandatory MIME type
      
'</factura>';
    
$req .= '<anexos>';
    foreach (
$attachments as $file) {
      
$req .= '<anexo>' .
          
'<anexo>' $tools->toBase64($file->getData()) . '</anexo>' .
          
'<nombre>' $file->getFilename() . '</nombre>' .
          
'<mime>' $file->getMimeType() . '</mime>' .
        
'</anexo>';
    }
    
$req .= '</anexos>';
    
$req .= '</request></web:enviarFactura>';

//echo "*** Esta es la variable de envio req: ";
//echo $req;
//echo " *** FIN VARIABLE REQ *** ";


    //$soap=new SoapClient1();
    
$soap = new FacturaeFile();
      
    
$ok=$soap->request($req);
  }


  
/**
   * Cancel invoice 
   * @param  string           $regId  Invoice register ID
   * @param  string           $reason Cancelation reason
   * @return SimpleXMLElement         Response
   */
  
public function cancelInvoice($regId$reason) {
    return 
$this->request('<web:anularFactura>' .
      
'<numeroRegistro>' $regId '</numeroRegistro>' .
      
'<motivo>' $reason '</motivo>' .
      
'</web:anularFactura>');
  }

  
/**
   * Get invoice status codes
   * @return SimpleXMLElement Response
   */
  
public function getStatus() {
    return 
$this->request('<web:consultarEstados></web:consultarEstados>');
  }


  
/**
   * Get administrations
   * @param  boolean          $onlyTopLevel Get only top level administrations
   * @return SimpleXMLElement               Response
   */
  
public function getAdministrations($onlyTopLevel=true) {
    
$tag "consultarAdministraciones";
    if (!
$onlyTopLevel$tag .= "Repositorio";
    return 
$this->request("<web:$tag></web:$tag>");
  }


  
/**
   * Get units
   * @param  string|null      $code Administration code
   * @return SimpleXMLElement       Response
   */
  
public function getUnits($code=null) {
    if (
is_null($code)) return $this->request('<web:consultarUnidades></web:consultarUnidades>');
    return 
$this->request('<web:consultarUnidadesPorAdministracion>' .
      
'<codigoDir>' $code '</codigoDir>' .
      
'</web:consultarUnidadesPorAdministracion>');
  }


  
/**
   * Get NIFs
   * @param  string|null      $code Administration code
   * @return SimpleXMLElement       Response
   */
  
public function getNifs($code=null) {
    if (
is_null($code)) return $this->request('<web:consultarNIFs></web:consultarNIFs>');
    return 
$this->request('<web:consultarNIFsPorAdministracion>' .
      
'<codigoDir>' $code '</codigoDir>' .
      
'</web:consultarNIFsPorAdministracion>');
  }


  
/**
   * Get invoice
   * @param  string|string[]  $regId Invoice register ID(s)
   * @return SimpleXMLElement        Response
   */
  
public function getInvoices($regId) {
    if (
is_string($regId)) {
      return 
$this->request('<web:consultarFactura>' .
        
'<numeroRegistro>' $regId '</numeroRegistro>' .
        
'</web:consultarFactura>');
    }
    
$req '<web:consultarListadoFacturas><request>';
    foreach (
$regId as $id$req .= '<numeroRegistro>' $id '</numeroRegistro>';
    
$req .= '</request></web:consultarListadoFacturas>';
    return 
$this->request($req);
  }



}
trait 
StageableTrait {
  private 
$production true;

  
/**
   * Set production environment
   * @param boolean $production Is production
   */
  
public function setProduction($production) {
    
$this->production $production;
  }


  
/**
   * Is production
   * @return boolean Is production
   */
  
public function isProduction() {
    return 
$this->production;
  }
}
/**
 * Facturae File
 *
 * Represents a file that can be used as an attachment for an invoice or to
 * send information to a Web Service.
 */
class FacturaeFile {
  const 
REQUEST_EXPIRATION 60// In seconds

  
private $publicKey;
  private 
$privateKey;

  private 
$filename;
  private 
$data;
  private 
$mime;

/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.face.gob.es";
  }


public function 
request($body) {

$tools = new XmlTools();
    

$nulo=null;


//DATOS SIGN

$policy= array(
    
"name" => "Politica de Firma FacturaE v3.1",
    
"url" => "http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf",
    
"digest" => "Ohixl6upD6av8N7pEvDABhEL6hM=");
    
// Generate random IDs
    
    // Load public and private keys
    
$reader = new KeyPairReader($GLOBALS["dir_cert"], $nulo$GLOBALS["clave"]);
    
$publicChain2 $reader->getPublicChain();
    
$privateKey2 $reader->getPrivateKey();
    
$signPolicy2 $policy;
    unset(
$reader);


    
//No usado Comprueba si hay key publica y privada y devueleve 1=hay 0=no hay
    //return (!empty($publicChain2) && !empty($privateKey2));


    
$reader = new KeyPairReader($GLOBALS["dir_cert"], null$GLOBALS["clave"]);
    
//$publicChain1 = $reader->getPublicChain();
    
$publicKey1 $publicChain2;
     
$publicChain1 $publicChain2;

    
$privateKey1 $reader->getPrivateKey();
    
$signPolicy1 $signPolicy2;
    unset(
$reader);

    
$tools = new XmlTools();

    
// Generate random IDs for this request
    
$bodyId "BodyId-" $tools->randomId();
    
$certId "CertId-" $tools->randomId();
    
$keyId "KeyId-" $tools->randomId();
    
$strId "SecTokId-" $tools->randomId();
    
$timestampId "TimestampId-" $tools->randomId();
    
$sigId "SignatureId-" $tools->randomId();

    
// Define namespaces array
    
$ns = array(
      
"soapenv" => 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"',
      
"web" => 'xmlns:web="' $this->getWebNamespace() . '"',
      
"ds" => 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"',
      
"wsu" => 'xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"',
      
"wsse" => 'xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"'
    
);

    
// Generate request body
    
$reqBody '<soapenv:Body wsu:Id="' $bodyId '">' $body '</soapenv:Body>';
    
$bodyDigest $tools->getDigest($tools->injectNamespaces($reqBody$ns));

    
// Generate timestamp
    
$timeCreated time();
    
$timeExpires $timeCreated self::REQUEST_EXPIRATION;
    
$reqTimestamp '<wsu:Timestamp wsu:Id="' $timestampId '">' .
        
'<wsu:Created>' date('c'$timeCreated) . '</wsu:Created>' .
        
'<wsu:Expires>' date('c'$timeExpires) . '</wsu:Expires>' .
      
'</wsu:Timestamp>';
    
$timestampDigest $tools->getDigest(
      
$tools->injectNamespaces($reqTimestamp$ns)
    );

    
// Generate request header
    
$reqHeader '<soapenv:Header>';
    
$reqHeader .= '<wsse:Security soapenv:mustUnderstand="1">' ;
    
$reqHeader .= '<wsse:BinarySecurityToken ' .
      
'EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ' .
      
'wsu:Id="' $certId '" ' .
      
'ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">' .
        
$tools->getCert($publicKey1[0], false) .
      
'</wsse:BinarySecurityToken>';

    
// Generate signed info
    
$signedInfo '<ds:SignedInfo>' .
        
'<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">' .
        
'</ds:CanonicalizationMethod>' .
        
'<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>' .
        
'<ds:Reference URI="#' $timestampId '">' .
          
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"></ds:DigestMethod>' .
          
'<ds:DigestValue>' $timestampDigest '</ds:DigestValue>' .
        
'</ds:Reference>' .
        
'<ds:Reference URI="#' $bodyId '">' .
          
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"></ds:DigestMethod>' .
          
'<ds:DigestValue>' $bodyDigest '</ds:DigestValue>' .
        
'</ds:Reference>' .
      
'</ds:SignedInfo>';
    
$signedInfoPayload $tools->injectNamespaces($signedInfo$ns);

    
// Add signature and KeyInfo to header
    
$reqHeader .= '<ds:Signature Id="' $sigId '">' .
      
$signedInfo .
      
'<ds:SignatureValue>' .
        
$tools->getSignature($signedInfoPayload$privateKey1false) .
      
'</ds:SignatureValue>';
    
$reqHeader .= '<ds:KeyInfo Id="' $keyId '">' .
      
'<wsse:SecurityTokenReference wsu:Id="' $strId '">' .
        
'<wsse:Reference URI="#' $certId '" ' .
        
'ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">' .
        
'</wsse:Reference>' .
      
'</wsse:SecurityTokenReference>' .
      
'</ds:KeyInfo>';
    
$reqHeader .= '</ds:Signature>';

    
// Add timestamp and close header
    
$reqHeader .= $reqTimestamp;
    
$reqHeader .= '</wsse:Security>';
    
$reqHeader .= '</soapenv:Header>';

    
// Generate final request
    
$req '<soapenv:Envelope>' $reqHeader $reqBody '</soapenv:Envelope>';
    
$req $tools->injectNamespaces($req$ns);
    
$req '<?xml version="1.0" encoding="UTF-8"?>' $req;

    
// Extract SOAP action from "<web:ACTION></web:ACTION>"
    
$soapAction substr($body5strpos($body'>')-5);
    
$soapAction $this->getWebNamespace() . "#$soapAction";

    
$ch curl_init();
    
curl_setopt_array($ch, array(
      
CURLOPT_URL => $GLOBALS['endpoint'],
      
CURLOPT_RETURNTRANSFER => 1,
      
CURLOPT_SSL_VERIFYPEER => 0,
      
CURLOPT_TIMEOUT => 30,
      
CURLOPT_POST => 1,
      
CURLOPT_POSTFIELDS => $req,
      
CURLOPT_HTTPHEADER => array(
        
"Content-Type: text/xml",
        
"SOAPAction: " $soapAction
      
),
      
CURLOPT_USERAGENT => "FacturaePHP/" $GLOBALS["version"]
    ));
    
$res curl_exec($ch);
    
curl_close($ch);
    unset(
$ch);


    
//// Parse response
    
    
$xml = new \DOMDocument();
    
$xml->loadXML($res);
    
$xml $xml->getElementsByTagName('Body')->item(0)->getElementsByTagName('*')->item(0);
$child $xml->getElementsByTagName('codigo');
 
foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('descripcion');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('codigo Seguimiento');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('codigoSeguimiento');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }


//echo  "---- FIN RESULTADO ----"  . "\r\n" . "---- RESPUESTA COMPLETA  ----"  . "\r\n" . $res . "\r\n" . "---- FIN RESPUESTA COMPLETA ----" .  $req;

//if ($res->resultado->codigo == 0) {
//  // La factura ha sido aceptada
//  echo "Número de registro => " . $res->factura->numeroRegistro;
//} else {
//  // FACe ha rechazado la factura
//}

//return $req;  
}



  
/**
   * Get data
   * @return string Data
   */
  
public function getData() {
    return 
$this->data;
  }


  
/**
   * Get filename
   * @return string Filename
   */
  
public function getFilename() {
    return 
$this->filename;
  }


  
/**
   * Get MIME type
   * @return string MIME type
   */
  
public function getMimeType() {
    return 
$this->mime;
  }
}




?>
[/php]
Responder Con Cita
  #3  
Antiguo 19-02-2024
Avatar de ramherfer
ramherfer ramherfer is offline
Miembro
 
Registrado: may 2013
Ubicación: Valencia
Posts: 51
Poder: 11
ramherfer Va por buen camino
Cita:
Empezado por ermendalenda Ver Mensaje
Yo te lo pongo pero no sé si te vas a liar más, ya que yo trabajo en Vb6 para generar el xml y despuñess las firmas y encapsulamientos soaps lo hago en php con llamadas desde curl.
En Delphi hay otras formas que los compañeros del foro seguro que te pueden guiar.

Mira el código para generar el XML (A pelo) es de esta forma:
Código:
close #92
Open "C:\xmls\" & nombre_fichero & ".xml" For Output  As #92
 Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
               Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
                If es_anulacion Then
                    
                    Print #92, "<sum:BajaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                Else
                    Print #92, "<sum:AltaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                End If
                Print #92, "<sum1:Cabecera>"
                Print #92, "<sum1:IDVersion>" & version_vfactu & "</sum1:IDVersion>"
 Print #92, "<sum1:ObligadoEmision>"
                Print #92, "<sum1:NombreRazon>" & TEXT_TO_UTF8(nombre_empresa) & "</sum1:NombreRazon>"
                Print #92, "<sum1:NIF>" & nif & "</sum1:NIF>"
                Print #92, "</sum1:ObligadoEmision>"
               select case tipo 

                    "anulacion"
                        Print #92, "<sum1:TipoRegistroAEAT>T3</sum1:TipoRegistroAEAT>"
                    
                     "sustitutiva"
                            Print #92, "<sum1:TipoRegistroAEAT>T1</sum1:TipoRegistroAEAT>"
                     "normal"
                            Print #92, "<sum1:TipoRegistroAEAT>T0</sum1:TipoRegistroAEAT>"
               end select
***Y ahora lo que voy a escribir lo voy guardando en la variable datohash para calcular el hash cuando tenga en la variable lo que necesite
datoxml = "<sum:RegistroFacturacion>"
                datohash = datoxml
                If es_anulacion = False Then
    
                    Print #92, "<sum:RegistroAltaFacturas>" & datoxml;
                Else
                    Print #92, "<sum:RegistroAnulacionFacturas>" & datoxml;
                End If
                
                 datoxml = "<sum1:IDFactura>"
                datohash = datohash & datoxml
                Print #92, datoxml;
                .......
****AL FINAL CALCULO EL HASH USANDO LAS API DE WINDOWS****
***  CryptCreateHash, ¿¿¿CryptAcquireContext, etc... de la libreria  "advapi32.dll"*****

                huella = UCase(CreateHashString(datohash, CALG_SHA_256))
                    
*** Inserto el hash en el xml y el resto de nodos
                   Print #92, "<sum1:Huella>" & huella & "</sum1:Huella>"
                    
                    Print #92, "<sum1:TipoHash>01</sum1:TipoHash>"
                    Print #92, "</sum:DatosControl>"
                    If es_anulacion Then
                        Print #92, "</sum:RegistroAnulacionFacturas>"
                        Print #92, "</sum:BajaFactuSistemaFacturacion>"
                    Else
                        Print #92, "</sum:RegistroAltaFacturas>"
                        Print #92, "</sum:AltaFactuSistemaFacturacion>"
                    End If
                   close #92
Por otro lado puedo encapsular en php, ya que en VB6 desconozco la forma, pero en mi caso hemos pagado a una empresa la programación y el servicio de conservación y le vamos a enviar los xmls sin encapsular para que hagan toda la hilera de verificación del encadenamiento, validación schema xml-xsd, conservación, encapsulamiento, envios y control de errores, el envio lo harán con su certificado y ellos le dan este servicio a cada cliente al que le cobraremos un precio "razonable", y me libero de la parte peor. Cada cliente recibirá o podrá consultar el reporte de los envios y si hay errores se avisará y se tomará las medidas según cada caso, esto ya lo tenemos definido.
Gracias @ermendalenda
__________________
Se humilde para admitir tus errores, inteligente para aprender de ellos y maduro para corregirlos.
Responder Con Cita
  #4  
Antiguo 22-02-2024
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.289
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
Se publican las presentaciones realizadas en el seminario del día 11 de febrero de 2024.
Durante la próxima semana, se irán incorporando el resto de contenidos asociados a la sesión de divulgación, tales como el documento de preguntas y respuestas, grabación al vídeo, entre otros.

Parece que hay una de la primera parte más teórica y otra de la segunda que era más técnica.

Los subo al FTP y añadiré el link al primer mensaje del hilo.
__________________
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
  #5  
Antiguo 22-02-2024
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.473
Poder: 21
newtron Va camino a la fama
Gracias Germán.
__________________
Be water my friend.
Responder Con Cita
  #6  
Antiguo 22-02-2024
ermendalenda ermendalenda is offline
Miembro
 
Registrado: ago 2021
Posts: 886
Poder: 3
ermendalenda Va por buen camino
Cita:
Empezado por Neftali [Germán.Estévez] Ver Mensaje
Se publican las presentaciones realizadas en el seminario del día 11 de febrero de 2024.
Durante la próxima semana, se irán incorporando el resto de contenidos asociados a la sesión de divulgación, tales como el documento de preguntas y respuestas, grabación al vídeo, entre otros.

Parece que hay una de la primera parte más teórica y otra de la segunda que era más técnica.

Los subo al FTP y añadiré el link al primer mensaje del hilo.
gRACIAS GERMAN
Responder Con Cita
  #7  
Antiguo 23-02-2024
espinete espinete is offline
Miembro
 
Registrado: mar 2009
Posts: 233
Poder: 16
espinete Va camino a la fama
Duda sobre si cumplir con la ética o con la Ley Antifraude

Buenas...

Nos ha surgido una duda un poco rara en la empresa, relacionada en parte con la Ley Antifraude y "la prohibición de suministrar software que no cumpla con la nueva ley". Intentaré explicarlo brevemente a ver qué opináis...

Nosotros desarrollamos un software de facturación desde hace 20 años. Obviamente se van lanzando actualizaciones cada año, etc. pero siempre hay clientes que se quedan con versiones antiguas, o versiones "pirata", etc. así que hay clientes usando versiones de 2015, 2010 o incluso 2008 que simplemente no quieren actualizar.
Respetable, supongo.

- Esas versiones no eran compatibles obviamente con la Ley Antifraude: podías borrar facturas, modificarlas, no había registro de cambios, etc.
- Esas versiones se registraban enviándole un código al cliente por email (si, en aquella época no todo el mundo tenía internet en el negocio).

Dicho esto... Si uno de esos clientes, hoy en día, necesita reinstalar, o un nuevo código porque ha formateado el disco, etc. ¿estaríamos nosotros como desarrolladores infringiendo la normativa que impide suministrar software que no cumpla con la Ley Antifraude?
¿Estaríamos en nuestro derecho de no facilitar números de serie de versiones tan antiguas y obsoletas para las que no se ofrece asistencia técnica? ¿Sigue por ejemplo Microsoft facilitando números de serie, oficiales y legales, de Windows XP?

Como veis, no tiene relación directa, o tal vez sí, pero lo cierto es que ha generado debate en la empresa y no sabemos muy bien cómo proceder. Yo voto por descatalogar definitivamente esas versiones antiguas y punto, pero hay quien opina que esos clientes tienen derecho a usarla porque la pagaron en su momento.

No sé... si yo compré el Office 2003, tengo derecho a seguir instalándolo en 2024? ¿Es incluso posible hacerlo si el número de serie lo he perdido y necesito otro, o si he cambiado de ordenador?

Pues eso. Me gustaría saber vuestras opiniones, que hoy es viernes y a lo mejor esto relaja un poco
Responder Con Cita
  #8  
Antiguo 23-02-2024
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.473
Poder: 21
newtron Va camino a la fama
Buenas.


Pues efectivamente es un tema peliagudo y que seguramente estará a criterio del inspector de turno.


Obviando el tema de que el cliente si está usando un programa antiguo que no esté adaptado a la nueva normativa le pueden dar un estacazo bueno, también tiene derecho a seguir usando un programa del que tiene licencia así que yo voto porque habría que proporcionarle la licencia para poder usarlo pero no llegar más allá, o sea, no hacer ningún tipo de actuación, instalación ni mantenimiento del mismo porque entonces si te podrías buscar las cosquillas.


Saludos.
__________________
Be water my friend.
Responder Con Cita
  #9  
Antiguo 23-02-2024
edari edari is offline
Miembro
 
Registrado: jun 2021
Posts: 178
Poder: 3
edari Va por buen camino
Yo voto también voto por descatalogar versiones antiguas y más con la burrada de multas que deberíamos asumir. Hasta que se les rompa. Ni un soporte de ellas damos ya.

Por otro lado...

Qué empresa va a aceptar recibir una factura ilegal al no tener código QR?
Responder Con Cita
  #10  
Antiguo 23-02-2024
Avatar de ramherfer
ramherfer ramherfer is offline
Miembro
 
Registrado: may 2013
Ubicación: Valencia
Posts: 51
Poder: 11
ramherfer Va por buen camino
Cita:
Empezado por espinete Ver Mensaje
Buenas...

Nos ha surgido una duda un poco rara en la empresa, relacionada en parte con la Ley Antifraude y "la prohibición de suministrar software que no cumpla con la nueva ley". Intentaré explicarlo brevemente a ver qué opináis...

Nosotros desarrollamos un software de facturación desde hace 20 años. Obviamente se van lanzando actualizaciones cada año, etc. pero siempre hay clientes que se quedan con versiones antiguas, o versiones "pirata", etc. así que hay clientes usando versiones de 2015, 2010 o incluso 2008 que simplemente no quieren actualizar.
Respetable, supongo.

- Esas versiones no eran compatibles obviamente con la Ley Antifraude: podías borrar facturas, modificarlas, no había registro de cambios, etc.
- Esas versiones se registraban enviándole un código al cliente por email (si, en aquella época no todo el mundo tenía internet en el negocio).

Dicho esto... Si uno de esos clientes, hoy en día, necesita reinstalar, o un nuevo código porque ha formateado el disco, etc. ¿estaríamos nosotros como desarrolladores infringiendo la normativa que impide suministrar software que no cumpla con la Ley Antifraude?
¿Estaríamos en nuestro derecho de no facilitar números de serie de versiones tan antiguas y obsoletas para las que no se ofrece asistencia técnica? ¿Sigue por ejemplo Microsoft facilitando números de serie, oficiales y legales, de Windows XP?

Como veis, no tiene relación directa, o tal vez sí, pero lo cierto es que ha generado debate en la empresa y no sabemos muy bien cómo proceder. Yo voto por descatalogar definitivamente esas versiones antiguas y punto, pero hay quien opina que esos clientes tienen derecho a usarla porque la pagaron en su momento.

No sé... si yo compré el Office 2003, tengo derecho a seguir instalándolo en 2024? ¿Es incluso posible hacerlo si el número de serie lo he perdido y necesito otro, o si he cambiado de ordenador?

Pues eso. Me gustaría saber vuestras opiniones, que hoy es viernes y a lo mejor esto relaja un poco
Cualquier opinión es respetable. La mia es que si no tiene contrato de mantenimiento demostrable con facturas la empresa desarrolladora no esta infringiendo nada, y más cuando son empresas que no hay contacto. Las que hay con contacto se les puede avisar vía email que deben actualizar o desinstalar la aplicación.
Si alguien pide un codigo de instalación de versiones antiguas que haberlas las habrá, perfectamente se les informará a los usuarios de que esas versiones no cumple con la legislación vigente y que no se les puede facilitar ningún código de instalación. Aunque ya he comentado que si no tiene contrato de mantenimiento mensual, anual, demostrable con facturas la empresa desarrolladora no pueden hacerla responsable, si aquella empresa que sabiendo como está el tema, la use.

Avisar a usuarios con contacto y sin mantenimiento que actualización ($$$) o desinstalación.
Clientes sin contacto y que hagan petición de un codigo de instalación, o actualizar pagando lo que se estipule o que la desinstalen, codigos ni uno, es más el algoritmo interno va a ser cambiado en nuevas versiones para que no hayan despistes.
Evidentemente los usuarios con contrato de mantenimiento una vez adaptada la aplicación se les implementará.

Repito es mi humilde y discutible opninión, pero es lo que aquí se va a hacer ya que la cosa es seria y no está para andar jugando (150000€) Antes de lamentarme yo, tienen dos opciones o actualizarse o lamentarse pero ellos.
__________________
Se humilde para admitir tus errores, inteligente para aprender de ellos y maduro para corregirlos.
Responder Con Cita
  #11  
Antiguo 26-02-2024
antoine0 antoine0 is offline
Miembro
 
Registrado: oct 2021
Posts: 144
Poder: 3
antoine0 Va por buen camino
Cita:
Empezado por ramherfer Ver Mensaje
Si alguien pide un codigo de instalación de versiones antiguas que haberlas las habrá, perfectamente se les informará a los usuarios de que esas versiones no cumple con la legislación vigente y que no se les puede facilitar ningún código de instalación.
Suponemos que estamos en el año 2026 y este cliente te llama por qué su instalación antigua, que cubre los años 2022 hasta 2024, se le ha quebrado el disco duro y ahora viene una inspección y necesitan recuperar los datos anteriores para sacar datos y mostrar que las declaraciones de 2023 eran las correctas... Quieren reinstalarlo en un ordenador que no era el original licenciado, y te piden que lo "activas" para darle acceso al inspector.

Si el inspector les multa porqué el programa antiguo no cumple con los requisitos vigentes para 2026, creo que... se estará pasando un poco.


Cita:
Avisar a usuarios con contacto y sin mantenimiento que actualización ($$$) o desinstalación.
Creo que «desinstalación» no es legal. Debes guardar los programas y sus datos de alguna forma por 4 o 5 años.
Responder Con Cita
  #12  
Antiguo 23-02-2024
ermendalenda ermendalenda is offline
Miembro
 
Registrado: ago 2021
Posts: 886
Poder: 3
ermendalenda Va por buen camino
Cita:
Empezado por espinete Ver Mensaje
Buenas...

Nos ha surgido una duda un poco rara en la empresa, relacionada en parte con la Ley Antifraude y "la prohibición de suministrar software que no cumpla con la nueva ley". Intentaré explicarlo brevemente a ver qué opináis...

Nosotros desarrollamos un software de facturación desde hace 20 años. Obviamente se van lanzando actualizaciones cada año, etc. pero siempre hay clientes que se quedan con versiones antiguas, o versiones "pirata", etc. así que hay clientes usando versiones de 2015, 2010 o incluso 2008 que simplemente no quieren actualizar.
Respetable, supongo.

- Esas versiones no eran compatibles obviamente con la Ley Antifraude: podías borrar facturas, modificarlas, no había registro de cambios, etc.
- Esas versiones se registraban enviándole un código al cliente por email (si, en aquella época no todo el mundo tenía internet en el negocio).

Dicho esto... Si uno de esos clientes, hoy en día, necesita reinstalar, o un nuevo código porque ha formateado el disco, etc. ¿estaríamos nosotros como desarrolladores infringiendo la normativa que impide suministrar software que no cumpla con la Ley Antifraude?
¿Estaríamos en nuestro derecho de no facilitar números de serie de versiones tan antiguas y obsoletas para las que no se ofrece asistencia técnica? ¿Sigue por ejemplo Microsoft facilitando números de serie, oficiales y legales, de Windows XP?

Como veis, no tiene relación directa, o tal vez sí, pero lo cierto es que ha generado debate en la empresa y no sabemos muy bien cómo proceder. Yo voto por descatalogar definitivamente esas versiones antiguas y punto, pero hay quien opina que esos clientes tienen derecho a usarla porque la pagaron en su momento.

No sé... si yo compré el Office 2003, tengo derecho a seguir instalándolo en 2024? ¿Es incluso posible hacerlo si el número de serie lo he perdido y necesito otro, o si he cambiado de ordenador?

Pues eso. Me gustaría saber vuestras opiniones, que hoy es viernes y a lo mejor esto relaja un poco
Infringir la ley antifraude por darle soporte aunque sea una consulta, la infringes seguro. Como tengan inspección y lleguen hasta vosotros por que vean cualquier acceso actual te van a poner el supositorio.
Responder Con Cita
  #13  
Antiguo 23-02-2024
Avatar de keys
keys keys is offline
Miembro
 
Registrado: sep 2003
Ubicación: Bilbao
Posts: 1.035
Poder: 22
keys Va por buen camino
Nosotros en el contrato que firman al comprar la aplicación indicamos que sólo nos hacemos responsables si el software esta actualizado. Esto no sólo ocurre con verifactu, puede afectar a mas cosas, como impuestos (IVA, SII, etc), que por cambio de normativa ya no sean válidos en la versión que tienen ellos.

Lógicamente tu no te puedes hacer responsable del uso de un programa que vendíste hace 10 años.
Responder Con Cita
  #14  
Antiguo 23-02-2024
antoine0 antoine0 is offline
Miembro
 
Registrado: oct 2021
Posts: 144
Poder: 3
antoine0 Va por buen camino
Cita:
Empezado por espinete Ver Mensaje
¿estaríamos nosotros como desarrolladores infringiendo la normativa que impide suministrar software que no cumpla con la Ley Antifraude?
Buena pregunta. Muy buena.
Creo que lo de los números de serie (si lo haces gratis) no entra como «suministrar software», solo cumples una obligación nacida de una venta anterior.

Cita:
¿Estaríamos en nuestro derecho de no facilitar números de serie de versiones tan antiguas y obsoletas para las que no se ofrece asistencia técnica?
Si al vender estas licencias hace años no has puesto clausulas de reserva, no puedes poner tal clausula retroactivamente. Entonces la única razón para no dar estos números (que claramente es parte de lo que has vendido históricamente) sería si existe una normativa que te prohíbe suministrarlos. La LGT es obviamente tal normativa; queda por determinar si el texto de la ley 11/2021 (artículo 13) prohíbe (a los desarrolladores) cumplir con los contratos anteriores, con el motivo que los programas anteriores ya no cumplen lo que dice la normativa que los corresponde.

Solo he visto el nuevo artículo 201 bis de la LGT que dice primero que los desarrolladores están en infracción si fabrican, producen o comercializan programas que no cumplen con la normativa anti-fraude; entiendo que dar respuesta a una consulta en aplicación de un contrato anterior no entra en estos tres supuestos (pero no soy letrado y seguramente habrán letrados que darán interpretaciones correctas al respecto).
La segunda parte del artículo es más interesante: prohíbe «la tenencia de los sistemas o programas informáticos o electrónicos que no se ajusten a lo establecido [...]» Aquí claramente hay posibilidad de avisar a estos clientes que están/estarán en infracción con la LGT, con cuantiosas multas por detrás (lo que no sé es si estás obligado a avisarlos; o si hay obligación, o autorización, de denunciarlos a Hacienda). Pero avisar los clientes es una cosa, y cumplir con la petición regular de un cliente es otra. Creo que en este caso el desarrollador no comete ninguna infracción en sí dando un tal número de serie; al máximo podría ser posible cómplice, y no he visto que siga motivo de infracción (en la redacción actual).

Una muy buena pregunta par un viernes, es cierto.

Cita:
¿Sigue por ejemplo Microsoft facilitando números de serie, oficiales y legales, de Windows XP?
Nunca ha necesitado facilitar números de serie después de la compra. Es por esto que ha sido posible el pirateo: porqué el mecanismo era fijado en el momento de la compra inicial.

Cita:
Yo voto por descatalogar definitivamente esas versiones antiguas y punto, pero hay quien opina que esos clientes tienen derecho a usarla porque la pagaron en su momento.
Estoy con la segunda opción.

Cita:
No sé... si yo compré el Office 2003, tengo derecho a seguir instalándolo en 2024?
Los tres únicos casos que conozco par impedirlo es si lo utilizas en otro ordenador, si la licencia está ligada a un ordenador determinado (licencia «OEM», más barata), o si has utilizado esta licencia de Office 2003 para obtener un descuento en una versión ulterior; pero fuera de estos casos, claramente sí puedes instalarlo en 2024.
También puedes instalar Word para CP/M en un Zilog Z-80, si tienes licencia.

Creo que un mejor ejemplo sería Napster en lugar de Office 2003... pero claro Napster como compañía ya no existe.

Cita:
¿Es incluso posible hacerlo si el número de serie lo he perdido y necesito otro, o si he cambiado de ordenador?
En tal caso, con la prueba de la compra, creo que Microsoft te debe dar una mano, sobre todo porqué no hay razones técnicas que impide a Microsoft hacerlo (prueba: se puede piratear). Evidentemente, debes estar dentro de los parámetros para una posible instalación (es decir: en un Windows 10 x64, no te van a ayudar, está fuera de especificaciones.)

El caso de la ley anti-fraude es distinto del de Office 2003: con la ley antifraude sí existe una razón que podría oponerse al hacerlo: el hecho que instalándolo estás claramente infringiendo la LGT.
Responder Con Cita
  #15  
Antiguo 23-02-2024
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.289
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 espinete Ver Mensaje
Nosotros desarrollamos un software de facturación desde hace 20 años. Obviamente se van lanzando actualizaciones cada año, etc. pero siempre hay clientes que se quedan con versiones antiguas, o versiones "pirata", etc. así que hay clientes usando versiones de 2015, 2010 o incluso 2008 que simplemente no quieren actualizar.
Respetable, supongo.

- Esas versiones no eran compatibles obviamente con la Ley Antifraude: podías borrar facturas, modificarlas, no había registro de cambios, etc.
- Esas versiones se registraban enviándole un código al cliente por email (si, en aquella época no todo el mundo tenía internet en el negocio).

Pues eso. Me gustaría saber vuestras opiniones, que hoy es viernes y a lo mejor esto relaja un poco

Creo que el otro día en la empresa comentaban que lo habían consultado y la clave está en que tú no ofrezcas ni soporte, ni ayuda, ni tengas "ganancia" sobre esas versiones obsoletas, una vez que entre en vigor la ley.

Si el cliente instala esa versión antigua que no está preparada es problema suyo y a él le caerán las sanciones.
A ti te podrían caer también, si se demuestra que se los has vendido, si le has ayudado, si le has cobrado por mantenimiento, soporte,etc, etc,... todo esto después de la fecha especificada.
__________________
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
  #16  
Antiguo 23-02-2024
Sistel Sistel is offline
Miembro
 
Registrado: nov 2019
Ubicación: Bilbao
Posts: 373
Poder: 5
Sistel Va por buen camino
Cita:
Empezado por espinete Ver Mensaje
Nosotros desarrollamos un software de facturación desde hace 20 años. Obviamente se van lanzando actualizaciones cada año, etc. pero siempre hay clientes que se quedan con versiones antiguas, o versiones "pirata", etc. así que hay clientes usando versiones de 2015, 2010 o incluso 2008 que simplemente no quieren actualizar.
Respetable, supongo.

- Esas versiones no eran compatibles obviamente con la Ley Antifraude: podías borrar facturas, modificarlas, no había registro de cambios, etc.
- Esas versiones se registraban enviándole un código al cliente por email (si, en aquella época no todo el mundo tenía internet en el negocio).

Dicho esto... Si uno de esos clientes, hoy en día, necesita reinstalar, o un nuevo código porque ha formateado el disco, etc. ¿estaríamos nosotros como desarrolladores infringiendo la normativa que impide suministrar software que no cumpla con la Ley Antifraude?
¿Estaríamos en nuestro derecho de no facilitar números de serie de versiones tan antiguas y obsoletas para las que no se ofrece asistencia técnica? ¿Sigue por ejemplo Microsoft facilitando números de serie, oficiales y legales, de Windows XP?

Como veis, no tiene relación directa, o tal vez sí, pero lo cierto es que ha generado debate en la empresa y no sabemos muy bien cómo proceder. Yo voto por descatalogar definitivamente esas versiones antiguas y punto, pero hay quien opina que esos clientes tienen derecho a usarla porque la pagaron en su momento.

No sé... si yo compré el Office 2003, tengo derecho a seguir instalándolo en 2024? ¿Es incluso posible hacerlo si el número de serie lo he perdido y necesito otro, o si he cambiado de ordenador?

Pues eso. Me gustaría saber vuestras opiniones, que hoy es viernes y a lo mejor esto relaja un poco
Hola,

Por lo que me pareció entender en la charla del otro día, de la Agencia Tributaria, el desarrollador del software debe hacer una auditoría externa o una declaración responsable de que cumple con la nueva Ley Antifraude.

Entiendo que en este caso, haría la declaración responsable del software que cumple (versión actual) no de las versiones anteriores.
Por ejemplo de "Facturación Pepe, versión 5 (Antifraude) y posteriores"
Y, por tanto, quedarían exentas de cumplir la nueva normativa las versiones anteriores, como "Facturación Pepe, versión 4".

Si un cliente usa "Facturación Pepe, versión 4" debe saber que es un software antiguo que no cumple con la nueva ley y por tanto puede ser sancionado.

Supongo que con eso el desarrollador queda exento de responsabilidad.

Saludos
Responder Con Cita
  #17  
Antiguo 24-02-2024
xevi xevi is offline
Registrado
 
Registrado: feb 2024
Posts: 7
Poder: 0
xevi Va por buen camino
Una consulta a ver si alguien me puede aportar un poco de luz

En un software de Contabilidad, simplemente Contabilidad (Cuentas, Asientos, Balances, Libros...)
¿Sabeis como afecta o el alcance de la ley Anti Fraude?

Porque el tema por lo que voy leyendo e informando, todo gira entorno a la facturación y más concretamente al emitir la factura, pero queda un poco a nivel de programador o desarrollador todo el tema de trazabilidad, integridad... por lo que yo solamente he desarrollado un registro de eventos y además le he incluido una integridad a mi manera en cada apunte de la base de datos "asientos", pero como digo, no veo que haya una normativa específica, detallada para los sitemas de Contabilidad.

Agradezco cualquier aporte al respecto.

Gracias.

Un Saludo,
Xevi
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
Hijo de Informáticos gluglu Humor 3 13-03-2007 11:05:35
Adictos informaticos ... Trigger Humor 2 11-10-2004 12:18:32
Nosotros los Informáticos Trigger Humor 1 10-10-2004 14:58:09
Patrón de los Informáticos. obiwuan Varios 20 10-09-2003 14:44:54
Chistes Informaticos jhonny Humor 2 11-08-2003 21:59:09


La franja horaria es GMT +2. Ahora son las 13:42:50.


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