<?php

// Ejemplo de uso de libfacturista para sellar un CFDI
// Para usar estas funciones, se debe tener libfacturista.so
// asimismo se debe agregar a la configuracion de php la extension modfacturista.so:
// extension=modfacturista.so en el archivo php.ini

$xml1="cfdi_ejemplo.xml";
$xml2="/tmp/cfdi_timbrado.xml";
$h=0;

$rutaLlavePrivada="/tmp/aaa010101aaa__csd_01.key";
$contrasena="12345678a";
$rutaCertificado="/tmp/aaa010101aaa__csd_01.cer";
$rutaDestino="/tmp/cfdi_sellado_php.xml";
$rutaCFDI="/tmp/cfdi_sinsello_php.xml";

$h=cfdi_comprobante("3.2", "A", "1234", "2013-01-12T18:43:11", "Pago en una sola exhibición", "6172.50", "12.34", "USD", "7124.75", "Efectivo", "ingreso", "Campeche, Campeche", "3849", "3463", "ABC", "2012-01-11T11:11:11", "24493.38");

$he=cfdi_emisor($h,"AAA010101AAA","facturista.com");
if($he==0) { printf("<p/>%s<p/>",cfdi_error($h)); return -1;}
cfdi_emisor_regimen($he,"Regimen General de Ley");
cfdi_emisor_regimen($he,"Otro regimen (opcional)");

$hr=cfdi_receptor($h,"X&XX010101AAA","José Ángel & 'Niño' & \"Niña\"");
cfdi_receptor_domicilio($hr,"Paseo de Montejo", "1234", "456", "Col. €uropea", "Ciudad de los Niños", "Municipio de Mérida", "Yucatán", "México", "38294", "Por la cascada");

$hc=cfdi_concepto($h,"10", "PZA", "1", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_informacionaduanera($hc,"12345", "2011-01-01","Aduana nogales");

$hc=cfdi_concepto($h,"10", "PZA", "2", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_cuentapredial($hc,"3836463729385495");

$hc=cfdi_concepto($h,"10", "PZA", "3", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_parte($h,"10", "PZA", "3", "Parte 1", "123.45", "1234.50");
cfdi_concepto_parte($h,"10", "PZA", "3", "Parte 2", "123.45", "1234.50");

$hc=cfdi_concepto($h,"10", "PZA", "4", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_ComplementoConcepto($hc);

$hc=cfdi_concepto($h,"10", "PZA", "5", "Memoria USB", "123.45", "1234.50");

$hi=cfdi_impuestos($h,"35.35","987.60");

cfdi_impuestos_retencion($hi,"ISR","12.12");
cfdi_impuestos_retencion($hi,"IVA","23.23");

cfdi_impuestos_traslado($hi,"IVA", "987.60", "16.00");
cfdi_impuestos_traslado($hi,"IEPS", "0.00", "0.00");

echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';

if(cfdi_xml_guardar($h,$rutaCFDI,1)!=0)
        {
                $s=file_get_contents($rutaCFDI);
                $s=str_replace("<","<",$s);
                $s=str_replace(">",">",$s);
                echo "<hr/>CFDI generado:<br/><pre>$s</pre><br/>";
        }
else
        {
        echo "<p/>Error al guardar: ".cfdi_error($h);
        }


printf("<hr/>Cadena original:<br/>\n%s\n",cfdi_cadena_original($h));

if(cfdi_sellar_pkcs8($h, $rutaLlavePrivada, $contrasena, $rutaCertificado, $rutaDestino,1)!=0)
	{
		$s=file_get_contents($rutaDestino);
		$s=str_replace("<","<",$s);
		$s=str_replace(">",">",$s);
		echo "<hr/>CFDI sellado:<br/><pre>$s</pre><br/>";
	}
else
	{
	echo "<p/>Error al sellar: ".cfdi_error($h);
	}

echo "<br/><br/><hr/>facturista.com<br/><br/>";


?>

//<?php

// libfacturista
// biblioteca (dll o libreria) para generar, sellar y timbrar CFDI 3.3 (XML)
// Ariel Alonzo Medina Vazquez - facturista.com

// Declaración/descripción de las funciones
// != significa distinto, == significa igual, '' significa cadena vacía

// En modo DEMO (sin licencia) las funciones para cargar el XML, sellar y timbrar cambian el RFC a AAA010101AAA,
// de manera que todos los XML que quieran timbrarse, deben haber sido sellados con ese RFC.

// En modo DEMO las funciones de sellado guardan a disco y dejan también el XML sellado en memoria.
// Para timbrar lo que hay en memoria ponga la cadena vacia en el segundo parámetro de la función de timbrado

// libfacturista.dll se compila con la convención de llamada cdecl
// para usar las funciones en entornos que requieran stdcall , debe enlazar con _libfacturista.dll
// la cual está compilada con stdcall y con los nombres de las funciones precedidos por _
// ej.: _libfacturista_version()
// si su entorno permite poner un alias a las funciones, podria usarlas sin el prefijo mencionado
// Algunos entornos que requieren stdcall y permiten alias: VB 6 y PowerBuilder

/*
 - Manejadores
 
 La DLL fue diseñada para ejecutarse desde aplicaciones simples de escritorio
 hasta aplicaciones de servidor con multihilo, como IIS+ASP o Apache+PHP, Windows o Linux.
 
 Por ello en casi todas las funciones se usa como primer argumento un manejador,
 el cual es un número que identifica o representa a la variable u objeto en memoria
 que corresponde al CFDI con el que trabajemos.
 
 Más específicamente, ese número es una dirección de memoria, por lo cual debemos ser cuidadosos
 al usar manejadores y no asignarles valores inadecuados, para evitar errores de acceso a memoria.

 Cuando se proporciona una manejador inválido, las funciones afectarán al manejador global o
 no realizaran la tarea, de modo que el cambio no será visible.
 
 De manera predeterminada esta desactivado el soporte multihilo y se asigna un manejador global
 cuando usamos las funciones cfdi_crear()
 
 Activando el multihilo con la funcion set_mt(1), podremos crear distintos manejadores
 y usarlos simultáneamente con las funciones de la DLL.
 
 Si su aplicacion planea usar el soporte multihilo, cada uno de los hilos debe llamar una sola vez
 al principio de su ejecucion a la funcion set_mt(1)
 
 Activar el multihilo no significa que se creen más hilos en el proceso que usa la DLL
 sino que varios hilos podrán acceder a diferentes manejadores y usar las funciones al mismo tiempo
 afectando cada uno a su manejador creado.
 
 El manejador principal o manejador al nodo raiz, puede crearse mediante la función cfdi_crear()
 este es el padre de todos los nodos creados en un CFDI especifico,
 si ya esta creado, puede obtenerse con la funcion cfdi_raiz(h),
 donde h es cualquier nodo hijo del manejador raiz.
 
 
 Cuando termine de usar un cfdi debera destruirlo con cfdi_destruir( cfdi_raiz(h) ) para no perder memoria .
 
 Si no esta activado el multihilo, no necesita destruir los manejadores ya que siempre
 se usa el manejador global.
  
 Cuando otras funciones devuelven manejadores, lo son para nodos abajo de la raíz,
 como el nodo Comprobante, el nodo Impuestos, etc. 
 
 
 - Orden en el formado del XML
 
 Para formar el XML del CFDI debemos seguir este orden:
 
 manejador raiz: hroot = cfdi_crear()
 <Comprobante>	xml_node_create(hroot, "cfdi:Comprobante", "Version = 3.3 | Total = 1.0 | ... ", "")
	<Emisor>	xml_node_create(hroot, "cfdi:Comprobante/cfdi:Emisor", "Rfc = AAA010101AAA | Nombre = A B C | ... ", "")
		 
	<Receptor>	xml_node_create(hroot, "cfdi:Comprobante/cfdi:Receptor", "Rfc = BBB010101BBB | Nombre = A B C | ... ", "")
		
	<Concepto1> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto", "Descripcion = DLL | ... ", "")
		<informacion_aduanera>	xml_node_create(hroot, ...)
		<cuenta_predial>	xml_node_create(hroot, ...)
		<concepto_parte1>	xml_node_create(hroot, ...)
		<concepto_parte2>	xml_node_create(hroot, ...)
		...
		<concepto_parteN>	xml_node_create(hroot, ...)
		
		<Traslado> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado", "Importe = 1.0 | ... ", "")
		<Retencion> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto/cfdi:Impuestos/cfdi:Retenciones/cfdi:Retencion", "Importe = 1.0 | ... ", "")
		
	<Concepto2> xml_node_create(hroot, ...)
	...
	<ConceptoN> xml_node_create(hroot, ...)

	<Impuestos> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Impuestos", "TotalImpuestosTrasladados = 1.0 | ... ", "")
		<Retencion1> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Impuestos/cfdi:Retenciones/cfdi:Retencion", "Importe = 1.0 | ... ", "")
		<Retencion2> xml_node_create(hroot, ...)
		...
		<RetencionN> xml_node_create(hroot, ...)
		
		<Traslado1> xml_node_create(hroot, "cfdi:Comprobante/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado", "Importe = 1.0 | ... ", "")
		<Traslado2> xml_node_create(hroot, ...)
		...
		<TrasladoN> xml_node_create(hroot, ...)

 Cuando un nodo no aplique, por ejemplo retenciones o información aduanera, se puede omitir.
 
 Si falta algún nodo que es obligatorio, dará error cuando intente timbrar.
 		

 Cuando termine de usar el manejador, llamar a cfdi_destruir(hroot)
 

 - Sellado y timbrado
 
 Puede usar 3 funciones de sellado: cfdi_sellar(), cfdi_sellar_pem() y cfdi_sellar_pkcs8()
 Se aconseja el uso de la última nombrada, pues va de acuerdo con el formato en que el SAT
 entrega los certificados.
 
 Una vez sellado su CFDI sólo llame a la función cfdi_timbrar() con los parámetros adecuados
 para el PAC y listo ! Tendrá el CFDI en su disco duro.
 
 
 - Valores devueltos
 
 En general un valor igual a 0 indica falla
 y distinto de 0 indica éxito.
 
 Debe revisar los valores devueltos y en caso de falla, usar la función cfdi_error(h)
 para conocer la descripción del error.
 
 
 
*/

// Devuelve la versión de libfacturista
string libfacturista_version();

// Manejo multihilo, permite que cfdi_crear() o cfdi_comprobante entreguen distintos manejadores
// Necesario llamarla en entornos multihilo, como webservers con ASP o PHP
// o cuando quiera usar en su aplicación varios manejadores al mismo tiempo
// Si no se llama, todas las funciones afectan al manejador de CFDI global
int set_mt(int mt);

// Crear un manejador (raiz) para CFDI y lo devuelve
// Si usa la funcion cfdi_comprobante() no debe usar esta, pues ambas devuelven un manejador nuevo
// Se aconseja usar cfdi_crear() y cfdi_comprobante_ex()
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_crear();

// Destruye el manejador asociado con h
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_destruir(int h);


// Crea un nodo Concepto/ComplementoConcepto
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto_ComplementoConcepto(hconcepto hc);


// Carga el XML del archivo rutaFuente en el manejador h, devuelve el nuevo valor para el manejador
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_cargar(int h, string rutaFuente);

// Guarda el XML del manejador h en rutaDestino, decorar=1 indica si dejará espacios y saltos de línea entre las etiquetas
// Se usa para mejorar la legibilidad en un editor simple
// decorar=0 es la opción recomendada por compatibilidad con otros analizadores XML
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_guardar(int h, string rutaDestino, int decorar);

// Valida archivoXML con el esquema archivoXSD
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_validar(int h, string archivoXML, string archivoXSD, string parametros);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PKCS8 y la contraseña se pasa en el tercer parámetro
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar_pkcs8(int h, string rutaLlavePrivada, string contrasena, string rutaCertificado, string rutaDestino, int decorar);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PEM y la contraseña se pasa en el tercer parámetro
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar_pem(int h, string rutaLlavePrivada, string contrasena, string rutaCertificado, string rutaDestino, int decorar);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PEM sin contraseña para la llave privada
//decorar=1 indica si dejará espacios y saltos de línea entre las etiquetas
// Se usa para mejorar la legibilidad en un editor simple
// decorar=0 es la opción recomendada por compatibilidad con otros analizadores XML
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar(int h, string rutaLlavePrivada, string rutaCertificado, string rutaDestino, int decorar);

// Timbra el CFDI guardado en rutaFuente; el CFDI timbrado se guarda en rutaDestino
// Para timbrar un documento previamente cargado (cfdi_xml_cargar) o sellado (cfdi_sellar) en memoria
// ponga la cadena vacía en el segundo parámetro y pase el manejador del CFDI (h) en el primer parámetro

// La cadena 'parametros' son pares nombre=valor separados por ';', varios están relacionados con el webservice del PAC
// Si omite Servidor y Puerto se usara el servidor de producción. Es preferible especificarlos porque el PAC
// podría cambiar el nombre o puerto de su servidor
// numeroPAC: 1, Ecodex; 2: FoliosDigitales; 3: Sefactura; 6: Diverza; 13: SW
// Ej.: cfdi_timbrar(h,"cfdi_ejemplo.xml","cfdi_ejemplo_timbrado.xml",1,"RFC=AAA010101AAA");
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_timbrar(int h, string rutaFuente, string rutaDestino, int numeroPAC, string parametros);

// Cancela el CFDI cuyos datos se pasan en los parametros
// Ej.: cfdi_cancelar(h,1,"RFC=AAA010101AAA;UUID=E4C5CF3-D4D5C4;ArchivoLlavePrivada=archivo.key;Contrasena=XX;ArchivoCertificado=archivo.cer");
// La primera vez que un emisor sella con la DLL se guarda la ruta del CSD en el archivo facturista.conf
// Por lo que pueden omitirse los parámetros ArchivoLlavePrivada, Contrasena y ArchivoCertificado
// Si los archivos de CSD cambian de nombre, deberá actualizar ese archivo o especificar tales parámetros
// Si la función tiene éxito, cfdi_resultado(h) le devuelve el acuse
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_cancelar(int h, int numeroPAC, string parametros);

//Recupera el CFDI cuyos datos se pasan en los parametros; el CFDI recuperado se guarda en rutaDestino
// Ej.: cfdi_recuperar(h,"cfdi_recuperado.xml",1,"RFC=AAA010101AAA;ArchivoOriginal=sellado.xml");
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_recuperar(int h, string rutaDestino, int numeroPAC, string parametros);

// Obtiene el estado de cuenta del RFC indicado
// Ej.: cfdi_estado_cuenta(h,1,"RFC=AAA010101AAA")
// Valores devueltos: != '' éxito , == '' falla
string cfdi_estado_cuenta(int h, int numeroPAC, string parametros);

// Devuelve la cadena que describe el error relacionado con el manejador h
string cfdi_error(int h);

// Devuelve la cadena de resultado de la ultima operación relacionada con el manejador h
// La ultima operación debió ser exitosa
// Sólo debe usarse después de cancelar con el PAC 2
string cfdi_resultado(int h);


// Devuelve una cadena con el valor del atributo llamado nombre, correspondiente al nodo ubicado en ruta
string cfdi_xml_atributo(int h, string ruta, string nombre);

// Agrega un atributo en el nodo ubicado en ruta, el tercer y cuarto parámetros definen su nombre y valor
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_atributo_agregar(int h, string ruta, string nombre, string valor);

// Borra un atributo en el nodo ubicado en ruta, el tercer parámetro indica su nombre
// Valores devueltos: != 0 éxito , == 0 falla
// Si la ruta no existía, devuelve 0
int cfdi_xml_atributo_borrar(int h, string ruta, string nombre);

// Devuelve la cadena original del CFDI relacionado con el manejador h
string cfdi_cadena_original(int h);

// Devuelve la cadena original del SAT del CFDI relacionado con el manejador h
string cfdi_cadena_original_sat(int h);

// Devuelve el folio fiscal del CFDI relacionado con el manejador h
string cfdi_uuid(int h);

// Devuelve la fecha de timbrado del CFDI relacionado con el manejador h
string cfdi_fecha_timbrado(int h);

// Devuelve el número de certificado del SAT del CFDI relacionado con el manejador h
string cfdi_numero_certificado_sat(int h);

// Devuelve el sello del CFDI relacionado con el manejador h, lo toma del nodo TimbreFiscalDigital
string cfdi_sello_cfd(int h);

// Devuelve el sello del SAT del CFDI relacionado con el manejador h
string cfdi_sello_sat(int h);

// Devuelve el sello del CFDI relacionado con el manejador h, lo toma del nodo Comprobante
string cfdi_sello(int h);

// Devuelve la fecha de emisión del CFDI relacionado con el manejador h
string cfdi_fecha(int h);

// Devuelve el número de certificado del CFDI relacionado con el manejador h
// Si rutaCertificado se refiere a un archivo de certificado existente, nos da el número de certificado de ese archivo
string cfdi_numero_certificado(int h, string rutaCertificado);


// Las siguientes funciones sirven para manipular con más detalle el XML del CFDI

// En la notación pathX describimos la ruta de un nodo anteponiéndole el nombre de cada uno de sus
// nodos superiores y separando los nombres con una diagonal.

// Por ej. la ruta del nodo cfdi:Traslado sería: cfdi:Comprobante/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado

// Es la misma notación que usamos dentro de los corchetes de una sección INI
// [cfdi:Comprobante/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado]

// hnode es un int de 32 bits, que se usa como manejador de nodo


// Devuelve el manejador de nodo para la ruta especificada partiendo del nodo con manejador h, si h=0 se devolvera el nodo raíz
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node(hnode h, string path);

// Devuelve el número de nodos hijo
int xml_node_children_number(hnode h);

// Obtiene el manejador de nodo para el hijo con índice index, el índice está basado en 1
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node_by_index(hnode h, int index);

// Devuelve el nombre del nodo
string xml_node_name(hnode h);

// Devuelve el manejador de nodo para el hijo con nombre name
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node_by_name(hnode h, string name);

// Devuelve el valor del atributo con nombre name
string xml_node_attribute(hnode h, string name);

// Convierte el XML correspondiente al nodo h en una cadena de caracteres
// decorate=1 indica si dejará espacios y saltos de línea entre las etiquetas

// Un ejemplo de uso es cuando queremos extraer el nodo del timbre de un CFDI
string xml_serialize(int h, int decorate);

// Inserta en el nodo path el XML contenido en XMLstring
// Si varios nodos coinciden con path, se usa el de la posicion indexFather, 0 indica al ultimo
// Si ya hay nodos hijos, se insertan los nuevos en la posicion indexChildren, 0 indica al ultimo
// Devuelve el manejador al nodo path o 0 si hubo falla

// Un ejemplo de uso es cuando queremos agregar o pegar una Addenda o Complemento
int xml_insert(int h, string path, string XMLstring, int indexFather, int indexChildren);


// Funcion para fijar la administracion de memoria de las cadenas devueltas (returned string memory management)
// los valores pueden ser
// "" : No hay asignacion de memoria, las cadenas devueltas pertenecen a la DLL
//		Este es el valor predeterminado y la mayoria de los entornos nativos funcionan bien asi,
//		ya que crean una copia de la cadena sin preocuparse de liberar la original
// "c" : La cadena es asignada con malloc() y debe ser liberada por el cliente con free()
// "bstr" : La cadena es asignada con SysAllocStringByteLen() y debe ser liberada por el cliente con SysFreeString()
//		VB 6 y .Net la liberan automaticamente,
// "com"  : La cadena es asignada con CoTaskMemAlloc() y debe ser liberada por el cliente con CoTaskMemFree()

// En VB 6 es IMPORTANTE llamar esta funcion con "bstr" antes de usar las demas funciones de la dll, ej.
// rsmm = set_rsmm("bstr")
// Basta con llamarla una vez, En el ejemplo la llamamos en Form_Initialize() (inicializacion del formulario)

// En C# o VBnet esta función es llamada dentro de la función de inicialización ( ansiApi.init() o utf16Api.init() )
int set_rsmm(string rsmm);

// Decimos a la DLL la codificacion de las cadenas que recibirá y entregará a nuestro programa
// 0: utf8, 1: ansi, 2: utf16le
// Para Windows Ansi es la predeterminada, para Linux es utf8
// Aunque se comunique con una codificación distinta con nuestro programa,
// el XML producido siempre será UTF8
int set_client_charset(int charsetNumber);


// Realiza validaciones al CFDI, con estas opciones para los parametros:
// "Tipo=Sello" lo cual verifica el Sello
// "Tipo=Vigencia" para saber si está vigente
// "Tipo=Semantica" para verificar la matriz de errores del SAT
// Si falla, debería consultar cfdi_error(h)
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_validar(int h, string archivoXML, string parametros);

// cfdi_timbrar_lote permite timbrar una lista de CFDs o CFDIs, al momento de la llamada o
// iniciando el monitoreo de directorios (hotfolder)
// Si las facturas no estan selladas, se puede proporcionar informacion de los certificados
// a usar para el sellado.

// El monitoreo de directorios permite que el programa cliente de la dll funcione como un servidor de timbres

// Para no saturar al PAC, se encola la lista de archivos a timbrar y se espera una fraccion de segundo entre cada operacion

// Si rutaFuente es un .txt, cada linea debe contener un nombre de archivo para timbrar
// Si rutaFuente es un directorio, este sera monitoreado por nuevos archivos xml para timbrar
// rutaDestino debe ser el directorio en donde se colocaran los archivos timbrados
// si rutaDestino esta vacio se deja en el mismo directorio

// parametrosLote puede tener parametros (separados por ;) como:

// Sufijo=_timbrado.xml , cadena que se agrega al nombre de archivo nuevo en vez de la terminacion
// .xml ; si sufijo esta vacio, se sobrescribe el archivo origen
//  En este caso, cfdi_ejemplo.xml quedaria como cfdi_ejemplo_timbrado.xml en el directorio destino

// Repeticiones=N , para el caso de que rutaFuente sea un directorio,
//  N = 0 hara que se monitoree el directorio por archivos nuevos siempre
//  N > 0 hara que se monitoree solo ese numero de veces
//  N = -1 hara que se intenten timbrar por una vez todos los archivos en ese directorio

// Certificados=RFC1|rutaCertificado1|rutaLlavePrivada1|contrasenaLlavePrivada1|RFC2|rutaCertificado2|rutaLlavePrivada2|contrasenaLlavePrivada2|...|RFCN|rutaCertificadoN|rutaLlavePrivadaN|contrasenaLlavePrivadaN|
//  Contiene informacion separada por '|' relacionada con los certificados, Ej.:
//  Certificados=AAA010101AAA|aaa010101aaa__csd_01.cer|aaa010101aaa__csd_01.key|12345678a;


// parametrosPAC son los parametros para el PAC que se usan en la funcion cfdi_timbrar, con una caracteristica adicional
//  si pone la cadena <RFC>, sera sustituida por el RFC del emisor
//  de esta manera podra timbrar CFDIs de distintos emisores

// Si hay errores el archivo original no se mueve y se genera un archivo en el mismo directorio 
// con un nombre igual mas la terminacion .log , este ultimo contiene el texto del error

// Devuelve 1 en caso de exito y 0 en caso de error

// Ej. en linea de comandos para timbrar los archivos de un directorio al instante:
// facturista.exe --timbrar_lote lote/ lote/tmp/ "Sufijo=_timbrado.xml;Repeticiones=-1;Certificados=AAA010101AAA|aaa010101aaa__csd_01.cer|aaa010101aaa__csd_01.key|12345678a" "RFC=<RFC>;Servidor=ejemplo.org;Puerto=2044"
int cfdi_timbrar_lote(int h, string rutaFuente, string rutaDestino, string parametrosLote, int numeroPAC, string parametrosPAC);


// Devuelve el manejador raiz del nodo h
int cfdi_raiz(int h);

// Devuelve el número de cfdis activos en multihilo, ya sean los creados con cfdi_crear() o con cfdi_comprobante()
// Si esta desactivado el multihilo devuelve 0
int cfdis_activos();


// Un parámetro mayor que 0 activa el recolector de memoria sin uso
// Si esta activado, las llamadas a cfdi_destruir(h) liberan la memoria de cadenas dinámicas asociadas a h
// Para que obtengamos cadenas dinámicas, debemos llamar a set_rsmm(), esto no es necesario en general
// ya que muchos lenguajes crean su copia de las cadenas devueltas por la DLL
// No se debe activar el recolector si nuestro lenguaje se encarga de liberar la memoria, como es el caso de VB6
int set_gc(int enable);


// Complemento iedu (Instituciones Educativas) del Concepto
int cfdi_iedu(int h, string version, string nombreAlumno, string CURP, string nivelEducativo, string autRVOE, string rfcPago, string atributosExtra);


// Complemento implocal (Impuestos Locales) del CFDI
int cfdi_implocal(int h, string version, string TotaldeRetenciones, string TotaldeTraslados, string atributosExtra);

int cfdi_implocal_retenciones_locales(int h, string ImpLocRetenido, string TasadeRetencion, string Importe, string atributosExtra);

int cfdi_implocal_traslados_locales(int h, string ImpLocTrasladado, string TasadeTraslado, string Importe, string atributosExtra);


// Funciones para crear texto con formato INI
// Inicializa el texto a ;ini
int ini_start(int h);

// Agrega una linea con un valor: atributo=valor
int ini_value(int h, string atributo, string valor);

// Agrega una linea con una seccion: [seccion]
int ini_section(int h, string seccion);

// Agrega un comentario: ;comentario
int ini_comment(int h, string comentario);

// Devuelve la cadena construida
string ini_finish(int h);

// Pone en el nodo del primer parámetro un atributo con el nombre y valor indicados
// Devuelve 1 si tuvo éxito
int xml_node_set_attribute(hnode h, string attrname, string value);

// Guarda el INI construido con las funciones ini_* en el archivo indicado
// Devuelve el numero de caracteres escritos
int ini_save(hcfdi h, string rutaDestino);


// Con la funcion xml_node_create() puede crear cualquier estructura XML de un CFDI o complemento
// Usted va dando forma a su XML sin necesidad de objetos COM o de estructuras INI

// xml_node_create crea un nodo con su ruta partiendo del nodo h
// values es una lista de pares nombre=valor separados por | que se agregarán como
// atributos al nodo nuevo
// También puede usarse un par NombreNodo /= texto , lo cual se traduce al xml:
// <NombreNodo>texto</NombreNodo>
// es decir, en vez de crear un atributo, creamos un subnodo con texto
// Si NombreNodo esta vacío ( /= texto ), el texto se pone debajo del nodo actual.

// Cuando uno de los valores de los atributos CONTENGA un | será INDISPENSABLE indicar OTRO separador

// El último parámetro puede ser la cadena vacía o puede indicar un separador distinto de |
// Por ej. hnode = xml_node_create(hroot, "cfdi:Comprobante/cfdi:Emisor", "RFC=AAA# nombre=FC", "separatorKeyValueRow=#")

// Devuelve el manejador (!=0) al nuevo nodo o 0 en caso de falla

// Al usar xml_node_create, si no existe la ruta, se va creando.
// Cada nombre de nodo es un componente de la ruta
// si ya existe ese nodo o componente, se toma el último creado con ese nombre,
// a excepción del último componente que de manera predeterminada siempre se crea.

// Por ej. la ruta del nodo cfdi:Traslado sería: cfdi:Comprobante/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado
// que si lo pusiéramos 2 veces en xml_node_create(), solo habría 1 nodo cfdi:Comprobante,
// 1 nodo cfdi:Impuestos, 1 nodo cfdi:Traslados y 2 nodos cfdi:Traslado
// <cfdi:Comprobante><cfdi:Impuestos><cfdi:Traslados>
//	<cfdi:Traslado Impuesto="001" TipoFactor="Tasa" TasaOCuota="0.000000" Importe="1.0"></cfdi:Traslado/>
//	<cfdi:Traslado Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.000000" Importe="2.0"></cfdi:Traslado/>
// </cfdi:Traslados></cfdi:Impuestos></cfdi:Comprobante>

// Si va repetir un nodo, solo debe poner la misma ruta con los atributos correspondientes
// Antes de repetirlo, ya debería haber agregado los subnodos del anterior, si es que los hubiera,
// por ejemplo si tenemos dos nodos cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto
// y el primero tiene un traslado de impuesto, antes de agregar el segundo concepto debería
// haber agregado el traslado:
// cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado

// Para evitar o forzar que el último componente (o componente final) de la ruta se cree
// El 22 de marzo del 2017 se han introducido funcionalidades nuevas
// la funcion lf_config() que puede leer lineas abajo y los operadores ++ y --
// Si llama a lf_config(0,"ReusarUltimoComponentePathx=1"), cuando quiera crear un nuevo nodo
// o componente final y ya exista otro, deberá usar el operador ++

hnode xml_node_create(hnode h, string path, string values, string params);

// Devuelve el manejador (!=0) al nodo padre o 0 en caso de falla
hnode xml_node_father(hnode h);


// Permite cambiar en ejecución la configuración de la DLL
// lf_config(0,"ReusarUltimoComponentePathx=1")
// Indica que reusaremos el componente final de las rutas, cuando este exista
// Puede omitirse esta llamada si agregamos a facturista.conf esta linea: ReusarUltimoComponentePathx=1 

// Esto implica que cuando queramos crear un segundo componente final, le pondremos el sufijo ++
// Por ejemplo el primer producto se crea con esta ruta cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto
// Y el segundo con esta cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto++

// El operador ++ es valido en notacion pathx, los archivos INI por ahora no usan ese operador
// y cuando lo usen habrá que poner ;version=2.0 en las lineas iniciales del INI

//El operador -- indica que debemos tomar el nodo final anterior. Lo cual es predeterminado
//con ReusarUltimoComponentePathx=1, pero si no estamos usando esta configuración y queremos
//referirnos al nodo final anterior, entonces podríamos usar --

string lf_config(hcfdi h, string params);

//?>