C / C++.

 

La siguiente guía comprende la conexión con el servicio de timbrado utilizando C / C++, en el caso de Windows es necesario tener instalado Visual Studio 2005 o superior y para Unix/Linux/OSX gcc y cURL.

El código de esta guía se encuentra disponible para su descarga en el repositorio de ejemplos para Timbre Fiscal.


Generar Timbre

Para generar un timbre utilizando el servidor de pruebas es necesario tener los siguientes datos del servidor a la mano:

 Servidor de prueba: https://staging.diverza.com/stamp
 Token de prueba: ABCD1234
 Metodo HTTP: POST
 Header HTTP: x-auth-token

Así como también el CFDI de prueba que usaremos en este ejercicio:

<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante 
    xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd" 
    xmlns:cfdi="http://www.sat.gob.mx/cfd/3" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    LugarExpedicion="D.F.,MEXICO" 
    NumCtaPago="DESCONOCIDO" 
    formaDePago="PAGO EN UNA SOLA EXHIBICION" 
    metodoDePago="TRANSFERENCIA ELECTRONICA"
    subTotal="1000.00" 
    total="1160.00" 
    fecha="2013-12-02T22:18:24" 
    certificado="MIIEdDCCA1ygAwIBAgIUMjAwMDEwMDAwMDAxMDAwMDU4NjcwDQYJKoZIhvcNAQEFBQAwggFvMRgwFgYDVQQDDA9BLkMuIGRlIHBydWViYXMxLzAtBgNVBAoMJlNlcnZpY2lvIGRlIEFkbWluaXN0cmFjacOzbiBUcmlidXRhcmlhMTgwNgYDVQQLDC9BZG1pbmlzdHJhY2nDs24gZGUgU2VndXJpZGFkIGRlIGxhIEluZm9ybWFjacOzbjEpMCcGCSqGSIb3DQEJARYaYXNpc25ldEBwcnVlYmFzLnNhdC5nb2IubXgxJjAkBgNVBAkMHUF2LiBIaWRhbGdvIDc3LCBDb2wuIEd1ZXJyZXJvMQ4wDAYDVQQRDAUwNjMwMDELMAkGA1UEBhMCTVgxGTAXBgNVBAgMEERpc3RyaXRvIEZlZGVyYWwxEjAQBgNVBAcMCUNveW9hY8OhbjEVMBMGA1UELRMMU0FUOTcwNzAxTk4zMTIwMAYJKoZIhvcNAQkCDCNSZXNwb25zYWJsZTogSMOpY3RvciBPcm5lbGFzIEFyY2lnYTAeFw0xMjA3MjcxNzAyMDBaFw0xNjA3MjcxNzAyMDBaMIHbMSkwJwYDVQQDEyBBQ0NFTSBTRVJWSUNJT1MgRU1QUkVTQVJJQUxFUyBTQzEpMCcGA1UEKRMgQUNDRU0gU0VSVklDSU9TIEVNUFJFU0FSSUFMRVMgU0MxKTAnBgNVBAoTIEFDQ0VNIFNFUlZJQ0lPUyBFTVBSRVNBUklBTEVTIFNDMSUwIwYDVQQtExxBQUEwMTAxMDFBQUEgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxETAPBgNVBAsTCFVuaWRhZCAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2TTQSPONBOVxpXv9wLYo8jezBrb34i/tLx8jGdtyy27BcesOav2c1NS/Gdv10u9SkWtwdy34uRAVe7H0a3VMRLHAkvp2qMCHaZc4T8k47Jtb9wrOEh/XFS8LgT4y5OQYo6civfXXdlvxWU/gdM/e6I2lg6FGorP8H4GPAJ/qCNwIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQUFAAOCAQEATxMecTpMbdhSHo6KVUg4QVF4Op2IBhiMaOrtrXBdJgzGotUFcJgdBCMjtTZXSlq1S4DG1jr8p4NzQlzxsdTxaB8nSKJ4KEMgIT7E62xRUj15jI49qFz7f2uMttZLNThipunsN/NF1XtvESMTDwQFvas/Ugig6qwEfSZc0MDxMpKLEkEePmQwtZD+zXFSMVa6hmOu4M+FzGiRXbj4YJXn9Myjd8xbL/c+9UIcrYoZskxDvMxc6/6M3rNNDY3OFhBK+V/sPMzWWGt8S1yjmtPfXgFs1t65AZ2hcTwTAuHrKwDatJ1ZPfa482ZBROAAX1waz7WwXp0gso7sDCm2/yUVww==" 
    noCertificado="20001000000100005867" 
    sello="qTzEwNUDvk/WpeFstpf/FLNmiHMxiL8pDTXGNb+DCFO0Z7SXMZJCim3JAlBw8Astvr0/jiVfo3WdWbaX88cC1l1+iipOLdedbFNHZUmsW86nC1YQHWw0S6mEiGH0ZxGa5KOl/1mrvPlDweeCiyYavNQeEuO1r0/ELobMi07w6ps=" 
    tipoDeComprobante="ingreso"
    version="3.2" >
    <cfdi:Emisor nombre="EMPRESA DEMO" rfc="AAA010101AAA">
        <cfdi:DomicilioFiscal codigoPostal="34343" pais="MEXICO" estado="DISTRITO FEDERAL" municipio="BENITO JUAREZ" calle="REFORMA"/>
        <cfdi:RegimenFiscal Regimen="PERSONA FISCA"/>
    </cfdi:Emisor>
    <cfdi:Receptor nombre="PUBLICO EN GENERAL" rfc="XAXX010101000">
        <cfdi:Domicilio pais="MEXICO" calle="INSURGENTES"/>
    </cfdi:Receptor>
    <cfdi:Conceptos>
        <cfdi:Concepto importe="1000.00" valorUnitario="1000.00" descripcion="PZA" unidad="CANT" cantidad="1"/>
    </cfdi:Conceptos>
    <cfdi:Impuestos>
        <cfdi:Traslados>
            <cfdi:Traslado importe="160.00" tasa="160.00" impuesto="IVA"/>
        </cfdi:Traslados>
    </cfdi:Impuestos>
    <cfdi:Addenda/>
</cfdi:Comprobante>

Nota: Para conocer más acerca de como construir un CFDI, te recomendamos visitar la siguiente guía: Como generar un CFDI.


Inicio

Primeramente necesitamos crear una nueva carpeta con el nombre timbrar y crear dos archivos:

  • cfdi.xml - Deberemos guardar el contenido del CFDI a timbrar en el:
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante 
    xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd" 
    xmlns:cfdi="http://www.sat.gob.mx/cfd/3" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    LugarExpedicion="D.F.,MEXICO" 
    NumCtaPago="DESCONOCIDO" 
    formaDePago="PAGO EN UNA SOLA EXHIBICION" 
    metodoDePago="TRANSFERENCIA ELECTRONICA"
    subTotal="1000.00" 
    total="1160.00" 
    fecha="2013-12-02T22:18:24" 
    certificado="MIIEdDCCA1ygAwIBAgIUMjAwMDEwMDAwMDAxMDAwMDU4NjcwDQYJKoZIhvcNAQEFBQAwggFvMRgwFgYDVQQDDA9BLkMuIGRlIHBydWViYXMxLzAtBgNVBAoMJlNlcnZpY2lvIGRlIEFkbWluaXN0cmFjacOzbiBUcmlidXRhcmlhMTgwNgYDVQQLDC9BZG1pbmlzdHJhY2nDs24gZGUgU2VndXJpZGFkIGRlIGxhIEluZm9ybWFjacOzbjEpMCcGCSqGSIb3DQEJARYaYXNpc25ldEBwcnVlYmFzLnNhdC5nb2IubXgxJjAkBgNVBAkMHUF2LiBIaWRhbGdvIDc3LCBDb2wuIEd1ZXJyZXJvMQ4wDAYDVQQRDAUwNjMwMDELMAkGA1UEBhMCTVgxGTAXBgNVBAgMEERpc3RyaXRvIEZlZGVyYWwxEjAQBgNVBAcMCUNveW9hY8OhbjEVMBMGA1UELRMMU0FUOTcwNzAxTk4zMTIwMAYJKoZIhvcNAQkCDCNSZXNwb25zYWJsZTogSMOpY3RvciBPcm5lbGFzIEFyY2lnYTAeFw0xMjA3MjcxNzAyMDBaFw0xNjA3MjcxNzAyMDBaMIHbMSkwJwYDVQQDEyBBQ0NFTSBTRVJWSUNJT1MgRU1QUkVTQVJJQUxFUyBTQzEpMCcGA1UEKRMgQUNDRU0gU0VSVklDSU9TIEVNUFJFU0FSSUFMRVMgU0MxKTAnBgNVBAoTIEFDQ0VNIFNFUlZJQ0lPUyBFTVBSRVNBUklBTEVTIFNDMSUwIwYDVQQtExxBQUEwMTAxMDFBQUEgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxETAPBgNVBAsTCFVuaWRhZCAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2TTQSPONBOVxpXv9wLYo8jezBrb34i/tLx8jGdtyy27BcesOav2c1NS/Gdv10u9SkWtwdy34uRAVe7H0a3VMRLHAkvp2qMCHaZc4T8k47Jtb9wrOEh/XFS8LgT4y5OQYo6civfXXdlvxWU/gdM/e6I2lg6FGorP8H4GPAJ/qCNwIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQUFAAOCAQEATxMecTpMbdhSHo6KVUg4QVF4Op2IBhiMaOrtrXBdJgzGotUFcJgdBCMjtTZXSlq1S4DG1jr8p4NzQlzxsdTxaB8nSKJ4KEMgIT7E62xRUj15jI49qFz7f2uMttZLNThipunsN/NF1XtvESMTDwQFvas/Ugig6qwEfSZc0MDxMpKLEkEePmQwtZD+zXFSMVa6hmOu4M+FzGiRXbj4YJXn9Myjd8xbL/c+9UIcrYoZskxDvMxc6/6M3rNNDY3OFhBK+V/sPMzWWGt8S1yjmtPfXgFs1t65AZ2hcTwTAuHrKwDatJ1ZPfa482ZBROAAX1waz7WwXp0gso7sDCm2/yUVww==" 
    noCertificado="20001000000100005867" 
    sello="qTzEwNUDvk/WpeFstpf/FLNmiHMxiL8pDTXGNb+DCFO0Z7SXMZJCim3JAlBw8Astvr0/jiVfo3WdWbaX88cC1l1+iipOLdedbFNHZUmsW86nC1YQHWw0S6mEiGH0ZxGa5KOl/1mrvPlDweeCiyYavNQeEuO1r0/ELobMi07w6ps=" 
    tipoDeComprobante="ingreso"
    version="3.2" >
    <cfdi:Emisor nombre="EMPRESA DEMO" rfc="AAA010101AAA">
        <cfdi:DomicilioFiscal codigoPostal="34343" pais="MEXICO" estado="DISTRITO FEDERAL" municipio="BENITO JUAREZ" calle="REFORMA"/>
        <cfdi:RegimenFiscal Regimen="PERSONA FISCA"/>
    </cfdi:Emisor>
    <cfdi:Receptor nombre="PUBLICO EN GENERAL" rfc="XAXX010101000">
        <cfdi:Domicilio pais="MEXICO" calle="INSURGENTES"/>
    </cfdi:Receptor>
    <cfdi:Conceptos>
        <cfdi:Concepto importe="1000.00" valorUnitario="1000.00" descripcion="PZA" unidad="CANT" cantidad="1"/>
    </cfdi:Conceptos>
    <cfdi:Impuestos>
        <cfdi:Traslados>
            <cfdi:Traslado importe="160.00" tasa="160.00" impuesto="IVA"/>
        </cfdi:Traslados>
    </cfdi:Impuestos>
    <cfdi:Addenda/>
</cfdi:Comprobante>
  • timbrar.c - El archivo de codigo fuente que estaremos modificando en este ejercicio.

Unicamente para Windows: Se debera descargar el archivo comprimido includes.zip y descomprimirlo dentro de la carpeta timbrar

El siguiente paso es incluir las librerias que utilizaremos en el proyecto:

#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>

Ahora es necesario agregar algunas funciones de soporte para el resto de nuestro codigo:

Windows

// Estructura necesaria para la escritura del cuerpo de la petición
struct WriteStructure 
{
  const char *readptr;
  long sizeleft;
};

// Funcion de lectura para la respuesta del servicio de timbrado
static void write_callback_function(void *ptr, size_t size, size_t nmemb, void *userp)
{
  char **response_ptr =  (char**)userp;
  *response_ptr = strdup(ptr);
}

// Funcion de escritura para el cuerpo de la petición HTTP
static size_t read_callback_function(void *ptr, size_t size, size_t nmemb, void *userp)
{ 
  struct WriteStructure *writeStructure = (struct WriteStructure *)userp;

  if(size*nmemb < 1)
  {
   return 0;
  }

  if(writeStructure->sizeleft) 
  {
    *(char *)ptr = writeStructure->readptr[0]; 
    writeStructure->readptr++;                 
    writeStructure->sizeleft--;               
    return 1;                        
  }
  return 0;                          
}

// Function de lectura para el archivo XML que contiene el CFDI a timbrar
static char* read_cfd_file()
{
  char *cfd;
  long cfd_file_size;

  FILE *cfd_file = fopen("cfdi.xml", "rb");

  fseek(cfd_file, 0, SEEK_END);
  cfd_file_size = ftell(cfd_file);
  rewind(cfd_file);
  cfd = malloc(cfd_file_size * (sizeof(char)));
  fread(cfd, sizeof(char), cfd_file_size, cfd_file);
  fclose(cfd_file);

  return cfd;
}

Unix/Linux/OSX

// Estructura necesaria para la escritura del cuerpo de la petición
struct WriteStructure 
{
  const char *readptr;
  long sizeleft;
};

// Funcion de lectura para la respuesta del servicio de timbrado
static void write_callback_function(void *ptr, size_t size, size_t nmemb, void *userp)
{
  char **response_ptr =  (char**)userp;
  *response_ptr = strndup(ptr, (size_t)(size *nmemb));
}

// Funcion de escritura para el cuerpo de la petición HTTP
static size_t read_callback_function(void *ptr, size_t size, size_t nmemb, void *userp)
{ 
  struct WriteStructure *writeStructure = (struct WriteStructure *)userp;

  if(size*nmemb < 1)
  {
   return 0;
  }

  if(writeStructure->sizeleft) 
  {
    *(char *)ptr = writeStructure->readptr[0]; 
    writeStructure->readptr++;                 
    writeStructure->sizeleft--;               
    return 1;                        
  }
  return 0;                          
}

// Function de lectura para el archivo XML que contiene el CFDI a timbrar
static char* read_cfd_file()
{
  char *cfd;
  long cfd_file_size;

  FILE *cfd_file = fopen("cfd.xml", "rb");

  fseek(cfd_file, 0, SEEK_END);
  cfd_file_size = ftell(cfd_file);
  rewind(cfd_file);
  cfd = malloc(cfd_file_size * (sizeof(char)));
  fread(cfd, sizeof(char), cfd_file_size, cfd_file);
  fclose(cfd_file);

  return cfd;
}

Nota: Por favor seleccione la version del sistema operativo que le corresponde para las funciones de ayuda.


Petición HTTP

Es momento de crear nuestra funcion main y declarar las variables que utilizaremos en ella:

int main(void)
{
  char *cfd;
  char *stamp;
  long response_code;
  CURL *curl;
  CURLcode result;
  struct curl_slist *headers = NULL;
  struct WriteStructure writeStructure;

Ahora deberemos inicializar las librerias de CURL:

result = curl_global_init(CURL_GLOBAL_DEFAULT);
if(result != CURLE_OK) 
{
  fprintf(stderr, "Error en curl_global_init(): %s\n", curl_easy_strerror(result));
  return 1;
}

El siguiente paso es inicializar una petición de cURL:

curl = curl_easy_init();
if(curl) 
{

Incluimos el CFDI leyendo el archivo cfdi.xml y lo guardamos en una estructura que utilizaremos posteriormente:

cfd = read_cfd_file();

writeStructure.readptr = cfd;
writeStructure.sizeleft = (long)strlen(cfd);

Agregamos a la petición de cURL la URL del servicio de timbrado:

curl_easy_setopt(curl, CURLOPT_URL, "https://staging.diverza.com/stamp");

Es necesario que la petición use el metodo HTTP post:

curl_easy_setopt(curl, CURLOPT_POST, 1L);

Por motivos de seguridad es necesario que agreguemos un token de seguridad a la petición, en esta guía utilizaremos el de prueba ABCD1234 y este deberá ser cambiado cuando deseemos pasar el código a producción:

headers = curl_slist_append(headers, "x-auth-token: ABCD1234");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER,headers);

Es necesario decirle a la petición de cURL que utilizaremos dos funciones una para la escritura del mensaje en el servicio de timbrado y la otra para la escritura:

curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback_function);
curl_easy_setopt(curl, CURLOPT_READDATA, &writeStructure);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, writeStructure.sizeleft);

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_function);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stamp);

Finalmente ejecutamos la petición:

result = curl_easy_perform(curl);

Obtener el timbre

Para obtener los datos de respuesta del servidor simplemente se necesita lo siguiente:

    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
    curl_easy_cleanup(curl);

    printf("Codigo HTTP: %lu\n", response_code);
    printf("Timbre: %s", stamp);  
  }

  curl_global_cleanup();
  return 0;
}

Si ejecutamos el código utilizando:

Windows

C:\> cl timbrar.c libcurl.lib /I include
C:\> timbrar

Nota: Se debe utilizar la Developer Command Prompt que instala Visual Studio.

Unix/Linux/OSX

$ gcc timbrar.c -o timbrar -lcurl
$ ./timbrar

Podremos observar que el timbre es devuelto por el servicio en el cuerpo de la respuesta, y al imprimir la variable stamp debe observarse algo similar a lo siguiente:

<tfd:TimbreFiscalDigital 
  xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" 
  xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" 

  selloSAT="Ae0K1DyTpecq8xZAB8SSCccx5Gzrqr+HaD1tEQ/dFNqobiZDfJ2U9eJ9BRxYn1K6Zw4A0W2PbBs3VUFFasuJHkfw5nLxb+M/hu55Gomhw9OjhKsH0ABnOGa3vQHWPHHDFB9zb4/sMxdUTqEubent8Zvb3nfKaxdgX9BkVFYgd+c=" 
  noCertificadoSAT="20001000000100005761" 
  selloCFD="qTzEwNUDvk/WpeFstpf/FLNmiHMxiL8pDTXGNb+DCFO0Z7SXMZJCim3JAlBw8Astvr0/jiVfo3WdWbaX88cC1l1+iipOLdedbFNHZUmsW86nC1YQHWw0S6mEiGH0ZxGa5KOl/1mrvPlDweeCiyYavNQeEuO1r0/ELobMi07w6ps=" 
  FechaTimbrado="2014-08-27T19:33:42" 
  UUID="e52d9982-1cd1-4b99-aa3c-0f6172d07412" 

  version="1.0"/>

El código de respuesta del servidor que se encuentra en la variable response_code deberá ser 200 OK cuando la petición sea exitosa, en caso contrario te invitamos a revisar la Lista de Códigos de Respuesta, que contiene todos los posibles códigos de respuesta del servicio de timbrado y sus posibles soluciones.