Librería CFDI 3.3
¿Qué es?
Es una librería Freeware desarrollada en C# con Visual Studio Community .NET Framework 4.5.2 la cual permite generar el archivo XML de un CFDI3 a partir de las clases que componen un objeto TMDCfdi33
¿Por qué Freeware y no Open Source?
Porque a pesar de que el código es un 95% desarrollado por mi (el otro 5% partes de códigos de ejemplo tomados de internet, con sus respectivas referencias), secciones forma parte de otros proyectos que son de código propietario y mis convenios estipulan la no divulgación de ese código fuente.
¿Por qué lo puse a disposición de todo el que quisiera usarlo?
El programa se ha sometido a pruebas con variaciones en los datos de los Cfdis y se ha ajustado cuando han existido inconguencias al momento de timbrar, como no es posible para nosotros el hacer todas y cada una de las combinaciones tomamos la decisión de liberar esta librería (que es completamente funcional) y que las personas lo utilicen para su beneficio y si se detectarán errores nos los comuniquen corregimos y volver a liberar la nueva versión con sus correcciones, teniendo un beneficio mutuo.
¿Quién soy?
Mi nombre es Denny Infante Juárez (denny_infante@hotmail.com - @dennyinfante), aunque no programador de profesión el desarrollo de software es una de mis grandes pasiones; hace ya muchos años colaboraba en los foros de programación (principalmente los de Microsoft) y algunos artículos; de hecho, algunas demis aportaciones siguen apareciendo en google y otros sitios.
Agradecimientos:
Quiero agradecer a SW Smarter Web, que tienen un ambiente de pruebas gratuito y sin registro para realizar las pruebas del timbrado del cfdi version 3.3
¿Qué se puede hacer y qué no con la librería?
Con esta librería se puede:
¿Cómo se crea un objeto para un CFDI 3.3?
La clase base para el CFDI 3.3 es TMDCfdi33, en código el ejemplo para generar un archivos sería:
//Creamos el objecto
TMDCfdi33 _cfdi = new TMDCfdi33();
//Capturamos los datos del cfdi
_cfdi.LugarExpedicion = "25010";
_cfdi.MetodoPago = "PPD";
_cfdi.TipoDeComprobante = "I";
_cfdi.Total = 2900;
_cfdi.Moneda = "MXN";
_cfdi.SubTotal = 2500;
_cfdi.FormaPago = "99";
_cfdi.Fecha = DateTime.Now;
_cfdi.Folio = "0113";
//Emisor (el objeto emisor es creado automáticamente)
_cfdi.Emisor.Rfc = "AAGG791104IP2";
_cfdi.Emisor.Nombre = "Alguien interesado";
_cfdi.Emisor.RegimenFiscal = "612";
//Receptor (el objeto receptos es creado automáticamente)
_cfdi.Receptor.Rfc = "LSI150130GZ8";
_cfdi.Receptor.Nombre = "LOGISTICA SIMPLIFICADA SAPI DE CV";
_cfdi.Receptor.UsoCFDI = "P01";
#region Concepto 01
//El objecto para los conceptos es: TMDCfdi33ConceptoItem
//Creamos el objeto concepto (se agrega automáticamente a la colección de concepto)
TMDCfdi33ConceptoItem _concepto = _cfdi.Conceptos.Concepto.Add();
//Llenamos los datos del concepto
_concepto.NoIdentificacion = "01";
_concepto.ClaveProdServ = "72103300";
_concepto.Cantidad = 1;
_concepto.ClaveUnidad = "E48";
_concepto.Unidad = "SERVICIO";
_concepto.Descripcion = "MANO DE OBRA POR REPARACIÓN DE FALLA ELÉCTRICA";
_concepto.ValorUnitario = 2500;
_concepto.Importe = 2500;
//Impuestos del concepto
// Creamos un objeto que representa el impuesto trasladado (TMDCfdi33TrasladoItem) igual que se creo el objeto concepto
// OJO: para que el objeto impuesto se creé para el concepto debe utilizarse la referencia al objecto del concepto
TMDCfdi33TrasladoItem _traslado = _concepto.Impuestos.Traslados.Traslado.Add();
_traslado.Base = 2500;
_traslado.Impuesto = "002";
_traslado.TipoFactor = "Tasa";
_traslado.TasaOCuota = 0.16m;
_traslado.Importe = 400;
#endregion
#region Concepto 02
//Creamos un segundo cocepto
_concepto = _cfdi.Conceptos.Concepto.Add();
_concepto.NoIdentificacion = "02";
_concepto.ClaveProdServ = "72103300";
_concepto.Cantidad = 1;
_concepto.ClaveUnidad = "E48";
_concepto.Unidad = "SERVICIO";
_concepto.Descripcion = "Concepto de prueba";
_concepto.ValorUnitario = 2250000;
_concepto.Importe = 2250000;
//Impuestos del concepto
TMDCfdi33RetencionItem _retencion = _concepto.Impuestos.Retenciones.Retencion.Add();
_retencion.Base = 2250000;
_retencion.Impuesto = "001";
_retencion.TipoFactor = "Tasa";
_retencion.TasaOCuota = 0.32m;
_retencion.Importe = 720000m;
#endregion
//Impuestos del Cfdi
_cfdi.Impuestos.TotalImpuestosTrasladados = 400;
//Creamos el objeto del impuesto trasladado, ojo, como es el impuesto del cfdi
//La referencia debe ser del _cfdi
_traslado = _cfdi.Impuestos.Traslados.Traslado.Add();
_traslado.Impuesto = "002";
_traslado.TipoFactor = "Tasa";
_traslado.TasaOCuota = 0.16m;
_traslado.Importe = 400;
¿Cómo agregar un Complemento del Concepto?
//Obtenemos la referencia al concepto al que queremos agregar el complemento
TMDCfdi33ConceptoItem _concepto = (TMDCfdi33ConceptoItem)cfdi33.Conceptos.Concepto[0];
//Creamos el objecto del complemento del concepto, en este caso Insituticiones Educativas, ojo, se referencía a un concepto
TMDCfdiCCInstEducativas _complementoConcepto;
_complementoConcepto = (TMDCfdiCCInstEducativas)_concepto.ComplementoConcepto.Add("iedu:instEducativas", "1.0");
//Llenamos los datos del complemento
_complementoConcepto.NombreAlumno = "Denny Infante Juárez";
_complementoConcepto.CURP = "AIDJ760213HNLIUY04";
_complementoConcepto.NivelEducativo = "Secundaria";
_complementoConcepto.AutRVOE = "ASDFI23";
_complementoConcepto.RFCPago = "AIDJ760213UJ2";
¿Cómo agrear un complemento al CFDI 3.3?
Nota: los complementos Nomina 1.2 y Pagos 1.0 se encuentran en una librería independiente de la librería "base" (MDICore.dll) por lo que el código fuente está disponible (no está comentado por el momento pero es muy sencillo de entender)
Para crear un objeto de complemento el código necesario es el siguiente:
TMDComplementoNomina12 _nomina12 = (TMDComplementoNomina12)_cfdi.Complemento.Any.Add("nomina12:Nomina", "1.2");
Al ejecutar el código anterior, se busca en todas las librerías "cargadas" en memoria si existe el complemento especificado por eso es importante que la librería esté cargada en memoria; para esto existen diferentes métodos entre los cuales el más sencillo es crear un objeto de ese ensamblado o utilizar la función Assembly.Load("nombre del ensamblado"); sí existe el complemento regresará un objeto del complemento creado; ah!! se me olvidaba, si ustedes crean sus propias librerías de complementos tendrán que iniciar el nombre de la librearia con "MD" ya que es uno de los filtros al buscar los objetos que son complemento
TMDComplementoNomina12 _nomina12 = (TMDComplementoNomina12)_cfdi.Complemento.Any.Add("nomina12:Nomina", "1.2");
if (_nomina12 != null)
{
//El complemento existe y se puede capturar la información requerida
_nomina12.TipoNomina = "XXX"
_nomina12.Emisor.Curp = "XXXXX";
_nomina12.Emisor.RegistroPatronal = "XXXX";
_nomina12.Receptor.Curp = "XXXX";
//Subcontratacion
TMDNomina12SubContratacionItem _subcontratacion = _nomina12.Receptor.SubContratacion.Add();
_subcontratacion.RfcLabora = "XXXX";
//Percepciones
TMDNomina12PercepcionItem _percepcion = _nomina12.Receptor.Percepciones.Percepcion.Add();
_percepcion.TipoPercepcion = "XXXXX";
//Horas Extras
TMDNomina12HorasExtraItem _horaExtra = _percepcion.HorasExtra.Add();
_horaExtra... = "XXXXX";
}
else throw new Exception("Complemento no implementado");
¿Cómo Generar el XML y Sellarlo?
Para poder sellar el cfdi es necesario primero establecer algunas configuraciones; esto se hacemediante una clase configuración como sigue:
//El objeto TMDCfdiConfig no necesita ser creado
TMDCfdiConfig.FIELDirectory = string.Format(@"C:\Users\{0}\Desktop\MDTestCfdiV3\Fiel", TMDWinUtils.WindowsUserName);
TMDCfdiConfig.CerFile = "CSD_Pruebas_CFDI_LAN7008173R5.cer";
TMDCfdiConfig.KeyFile = "CSD_Pruebas_CFDI_LAN7008173R5.key";
TMDCfdiConfig.KeyFilePassword = "12345678a;
TMDCfdiConfig.UseOnLineXsltFiles = false;
TMDCfdiConfig.XsltFilesDirectory = string.Format(@"C:\Users\{0}\Desktop\MDTestCfdiV3\XSL Files", TMDWinUtils.WindowsUserName);
El parámetro UseOnLineXsltFiles si es "true" se usarán los archivos xslt en linea, este método es "tardado" porque descarga todos los archivos necesarios para realizar la transformación xslt; en cambio con el valor "false" utilizará la copia, que deberá existir, de los archivos xslt locales ubicados en el directorio establecido en la variable XsltFilesDirectory
TMDCfdi33 _cfdi = new TMDCfdi33();
_cfdi.... //cargar datos.
_cfdi.SellaCfdi() //_cfdi.SellaCfdi(false);
El método SellaCfdi(bool setDataFromCertificate = true) tiene un parámetro opcional (establecido en "true") el cual cuando tiene un valor verdadero cambia los siguientes valores del objeto cfdi:
Si el valor del parámetro es falso, no ocurre cambio alguno.
El cfdi en Xml se puede obtener de 2 maneras:
//obtenerlo como texto
string _cfdiXml = _cfdi.GetXmlCfdi();
//grabarlos directamente a un archivo
_cfdi.SaveXmlCfdi("nombre del archivo.xml")
¿Cómo timbrar un Cfdi?
Para timbrar el Cfdi es necesario utilizar los servicios de un PAC autorizado por parte del SAT, algunos tienen web services o kit de conectividad que nos permiten usar sus servicios y poder utilizarlos desde nuestras aplicaciones; afortunadamente encontré un servicio con "Ambiente de Pruebas" gratis por lo que pude hacer las pruebas necesarias y validar los Cfdi generados con la librería.
El procedimiento necesarios para ejecutar los servicios del PAC se implementan en una clase derivada de la clase TMDPAC la cual cuenta con dos métodos que deben de implementarse
- int TrimbraCfdi(string xmlString, out object customResult)
Los parámetros son un string con el xml del cfdi y el customResult es el resultado específico de cada PAC
- XmlNode GetXmlTrimbreFiscal()
Devuelve el XmlNode del timbre Fiscal
El ambiente de pruebas para las pruebas de timbrado con un PAC autorizado se llevaron a cabo con SW Smarter Web, la clase creada para su uso es:
public class TMDPAC_SmarterWebpRUEBAS: TMDPAC
{
AuthResponse m_authResponse = null;
StampResponseV4 m_response;
public TMDPAC_SmarterWebpRUEBAS()
{ }
public override int TimbraCfdi(string xmlString, out object customResult)
{
customResult = null;
int _result = -1;
m_response = null;
Stamp stamp = new Stamp("http://services.test.sw.com.mx", "demo", "123456789");
m_response = stamp.TimbrarV4(xmlString);
customResult = m_response;
if (m_response.status == "success")
_result = 0;
return _result;
}
public override XmlNode GetXmlTimbreFiscal()
{
XmlNode _result = null;
XmlDocument _xmlDoc = new XmlDocument();
try { _xmlDoc.LoadXml(m_response.data.cfdi); } catch { }
XmlElement _xmlComplemento = _xmlDoc.DocumentElement["cfdi:Complemento"];
foreach (XmlElement _nodX in _xmlComplemento)
if (_nodX.Name == "tfd:TimbreFiscalDigital")
{
_result = _nodX;
break;
}
return _result;
}
}
Y el código para trimbar el cfdi
TMDCfdi33 _cfdi = new TMDCfdi33()
//cargar los datos...
//Sellamos el cfdi si es necesario...
_cfdi.SellaCfdi(true);
//Creamos el objeto para usar el PAC
TMDPAC _pac = new TMDPAC_SmarterWebpRUEBAS();
object _customResult;
//Si el valor de _cfdi.Timbra es verdadero quiere decir que se timbró y se agregó el Complemento TFD al objeto
//si el valor es falso, pudo haberse timbrado pero no se agrego el TFD al objeto Cfdi
//si el valor es falso, pudo no haberse timbrado y no se agregó el TFD al objeto Cfdi
// esa es la función del customResult, que el usuario pueda evaluar el resultado de la consulta del PAC
if (_cfdi.Timbra(_pac, out _customResult))
_cfdi.SaveXmlCfdi(_saveAsFile);
¿Cargar un archivo Xml de un Cfdi 3.3, válido, a un objeto TMDCfdi33?
Cargar un archivo xml de un cfdi 3.3 válido dentro de un objeto TMDCfdi33 es de lo más sencillo:
TMDCfdi33 _cfdi = new TMDCfdi33();
_cfdi.Load(new FileInfo("Nombre del archivo"));
//Por qué el parámetro como FileInfo; porque hay una función "overload" del metodo Load que usa un string
string _xmlString = File.ReadAllText("nombre del archivo");
_cfdi.Load(_xmlString);
Programa de ejemplo
Librería y código fuente del ejemplo y de los Complementos Pagos 1.0 y Nomina 1.2
Es una librería Freeware desarrollada en C# con Visual Studio Community .NET Framework 4.5.2 la cual permite generar el archivo XML de un CFDI3 a partir de las clases que componen un objeto TMDCfdi33
¿Por qué Freeware y no Open Source?
Porque a pesar de que el código es un 95% desarrollado por mi (el otro 5% partes de códigos de ejemplo tomados de internet, con sus respectivas referencias), secciones forma parte de otros proyectos que son de código propietario y mis convenios estipulan la no divulgación de ese código fuente.
¿Por qué lo puse a disposición de todo el que quisiera usarlo?
El programa se ha sometido a pruebas con variaciones en los datos de los Cfdis y se ha ajustado cuando han existido inconguencias al momento de timbrar, como no es posible para nosotros el hacer todas y cada una de las combinaciones tomamos la decisión de liberar esta librería (que es completamente funcional) y que las personas lo utilicen para su beneficio y si se detectarán errores nos los comuniquen corregimos y volver a liberar la nueva versión con sus correcciones, teniendo un beneficio mutuo.
¿Quién soy?
Mi nombre es Denny Infante Juárez (denny_infante@hotmail.com - @dennyinfante), aunque no programador de profesión el desarrollo de software es una de mis grandes pasiones; hace ya muchos años colaboraba en los foros de programación (principalmente los de Microsoft) y algunos artículos; de hecho, algunas demis aportaciones siguen apareciendo en google y otros sitios.
Agradecimientos:
Quiero agradecer a SW Smarter Web, que tienen un ambiente de pruebas gratuito y sin registro para realizar las pruebas del timbrado del cfdi version 3.3
¿Qué se puede hacer y qué no con la librería?
Con esta librería se puede:
- Generar el archivo XML de un CFDI versión 3.3
- Agregar los Complementos de Conceptos (Acreditamiento IEPS 1.0, Instituciones Educativas 1.0, Por Cuenta de Terceros 1.1 y Venta de Vehículos 1.1)
- Incluye los complementos Nomina 1.2 y Complemento Pagos 1.0 (por el momento)
- Incluye los complementos Timbre Fiscal Digital 1.0 y 1.1
- Obtener resumen de los impuestos
- Obtiene la cadena original
- Sellar el CFDI (no necesita librerías adicionales para el uso del archivo ".key" - llave privada-)
- Verificar el Sello del CFDI
- Timbrar el CFDI - Requiere clase para conectarse con el PAC autorizado (incluye ejemplo)
- Cargar los datos desde un archivo XML de un CFDI 3.3 válido
- Utiliza la Transformacion XSLT con archivos locales o en línea (para generar la cadena original)
- Obtener del certificado "Uso de la clave" (<<Key Usage>)
- Obtener del certificado "Uso mejorado de claves" (<<Enhanced Key Usage>>)
- Obtener del certificado la información del "Sujeto" (<<Subject Data>>)
- CREAR TUS PROPIOS COMPLEMENTOS (incluye código de ejemplo)
- No verifica que los datos capturados sean los requeridos
- No verifica que los datos capturados sean los correctos (no verifica los datos contra los catálogos del SAT)
¿Cómo se crea un objeto para un CFDI 3.3?
La clase base para el CFDI 3.3 es TMDCfdi33, en código el ejemplo para generar un archivos sería:
//Creamos el objecto
TMDCfdi33 _cfdi = new TMDCfdi33();
//Capturamos los datos del cfdi
_cfdi.LugarExpedicion = "25010";
_cfdi.MetodoPago = "PPD";
_cfdi.TipoDeComprobante = "I";
_cfdi.Total = 2900;
_cfdi.Moneda = "MXN";
_cfdi.SubTotal = 2500;
_cfdi.FormaPago = "99";
_cfdi.Fecha = DateTime.Now;
_cfdi.Folio = "0113";
//Emisor (el objeto emisor es creado automáticamente)
_cfdi.Emisor.Rfc = "AAGG791104IP2";
_cfdi.Emisor.Nombre = "Alguien interesado";
_cfdi.Emisor.RegimenFiscal = "612";
//Receptor (el objeto receptos es creado automáticamente)
_cfdi.Receptor.Rfc = "LSI150130GZ8";
_cfdi.Receptor.Nombre = "LOGISTICA SIMPLIFICADA SAPI DE CV";
_cfdi.Receptor.UsoCFDI = "P01";
#region Concepto 01
//El objecto para los conceptos es: TMDCfdi33ConceptoItem
//Creamos el objeto concepto (se agrega automáticamente a la colección de concepto)
TMDCfdi33ConceptoItem _concepto = _cfdi.Conceptos.Concepto.Add();
//Llenamos los datos del concepto
_concepto.NoIdentificacion = "01";
_concepto.ClaveProdServ = "72103300";
_concepto.Cantidad = 1;
_concepto.ClaveUnidad = "E48";
_concepto.Unidad = "SERVICIO";
_concepto.Descripcion = "MANO DE OBRA POR REPARACIÓN DE FALLA ELÉCTRICA";
_concepto.ValorUnitario = 2500;
_concepto.Importe = 2500;
//Impuestos del concepto
// Creamos un objeto que representa el impuesto trasladado (TMDCfdi33TrasladoItem) igual que se creo el objeto concepto
// OJO: para que el objeto impuesto se creé para el concepto debe utilizarse la referencia al objecto del concepto
TMDCfdi33TrasladoItem _traslado = _concepto.Impuestos.Traslados.Traslado.Add();
_traslado.Base = 2500;
_traslado.Impuesto = "002";
_traslado.TipoFactor = "Tasa";
_traslado.TasaOCuota = 0.16m;
_traslado.Importe = 400;
#endregion
#region Concepto 02
//Creamos un segundo cocepto
_concepto = _cfdi.Conceptos.Concepto.Add();
_concepto.NoIdentificacion = "02";
_concepto.ClaveProdServ = "72103300";
_concepto.Cantidad = 1;
_concepto.ClaveUnidad = "E48";
_concepto.Unidad = "SERVICIO";
_concepto.Descripcion = "Concepto de prueba";
_concepto.ValorUnitario = 2250000;
_concepto.Importe = 2250000;
//Impuestos del concepto
TMDCfdi33RetencionItem _retencion = _concepto.Impuestos.Retenciones.Retencion.Add();
_retencion.Base = 2250000;
_retencion.Impuesto = "001";
_retencion.TipoFactor = "Tasa";
_retencion.TasaOCuota = 0.32m;
_retencion.Importe = 720000m;
#endregion
//Impuestos del Cfdi
_cfdi.Impuestos.TotalImpuestosTrasladados = 400;
//Creamos el objeto del impuesto trasladado, ojo, como es el impuesto del cfdi
//La referencia debe ser del _cfdi
_traslado = _cfdi.Impuestos.Traslados.Traslado.Add();
_traslado.Impuesto = "002";
_traslado.TipoFactor = "Tasa";
_traslado.TasaOCuota = 0.16m;
_traslado.Importe = 400;
¿Cómo agregar un Complemento del Concepto?
//Obtenemos la referencia al concepto al que queremos agregar el complemento
TMDCfdi33ConceptoItem _concepto = (TMDCfdi33ConceptoItem)cfdi33.Conceptos.Concepto[0];
//Creamos el objecto del complemento del concepto, en este caso Insituticiones Educativas, ojo, se referencía a un concepto
TMDCfdiCCInstEducativas _complementoConcepto;
_complementoConcepto = (TMDCfdiCCInstEducativas)_concepto.ComplementoConcepto.Add("iedu:instEducativas", "1.0");
//Llenamos los datos del complemento
_complementoConcepto.NombreAlumno = "Denny Infante Juárez";
_complementoConcepto.CURP = "AIDJ760213HNLIUY04";
_complementoConcepto.NivelEducativo = "Secundaria";
_complementoConcepto.AutRVOE = "ASDFI23";
_complementoConcepto.RFCPago = "AIDJ760213UJ2";
¿Cómo agrear un complemento al CFDI 3.3?
Nota: los complementos Nomina 1.2 y Pagos 1.0 se encuentran en una librería independiente de la librería "base" (MDICore.dll) por lo que el código fuente está disponible (no está comentado por el momento pero es muy sencillo de entender)
Para crear un objeto de complemento el código necesario es el siguiente:
TMDComplementoNomina12 _nomina12 = (TMDComplementoNomina12)_cfdi.Complemento.Any.Add("nomina12:Nomina", "1.2");
Al ejecutar el código anterior, se busca en todas las librerías "cargadas" en memoria si existe el complemento especificado por eso es importante que la librería esté cargada en memoria; para esto existen diferentes métodos entre los cuales el más sencillo es crear un objeto de ese ensamblado o utilizar la función Assembly.Load("nombre del ensamblado"); sí existe el complemento regresará un objeto del complemento creado; ah!! se me olvidaba, si ustedes crean sus propias librerías de complementos tendrán que iniciar el nombre de la librearia con "MD" ya que es uno de los filtros al buscar los objetos que son complemento
TMDComplementoNomina12 _nomina12 = (TMDComplementoNomina12)_cfdi.Complemento.Any.Add("nomina12:Nomina", "1.2");
if (_nomina12 != null)
{
//El complemento existe y se puede capturar la información requerida
_nomina12.TipoNomina = "XXX"
_nomina12.Emisor.Curp = "XXXXX";
_nomina12.Emisor.RegistroPatronal = "XXXX";
_nomina12.Receptor.Curp = "XXXX";
//Subcontratacion
TMDNomina12SubContratacionItem _subcontratacion = _nomina12.Receptor.SubContratacion.Add();
_subcontratacion.RfcLabora = "XXXX";
//Percepciones
TMDNomina12PercepcionItem _percepcion = _nomina12.Receptor.Percepciones.Percepcion.Add();
_percepcion.TipoPercepcion = "XXXXX";
//Horas Extras
TMDNomina12HorasExtraItem _horaExtra = _percepcion.HorasExtra.Add();
_horaExtra... = "XXXXX";
}
else throw new Exception("Complemento no implementado");
¿Cómo Generar el XML y Sellarlo?
Para poder sellar el cfdi es necesario primero establecer algunas configuraciones; esto se hacemediante una clase configuración como sigue:
//El objeto TMDCfdiConfig no necesita ser creado
TMDCfdiConfig.FIELDirectory = string.Format(@"C:\Users\{0}\Desktop\MDTestCfdiV3\Fiel", TMDWinUtils.WindowsUserName);
TMDCfdiConfig.CerFile = "CSD_Pruebas_CFDI_LAN7008173R5.cer";
TMDCfdiConfig.KeyFile = "CSD_Pruebas_CFDI_LAN7008173R5.key";
TMDCfdiConfig.KeyFilePassword = "12345678a;
TMDCfdiConfig.UseOnLineXsltFiles = false;
TMDCfdiConfig.XsltFilesDirectory = string.Format(@"C:\Users\{0}\Desktop\MDTestCfdiV3\XSL Files", TMDWinUtils.WindowsUserName);
El parámetro UseOnLineXsltFiles si es "true" se usarán los archivos xslt en linea, este método es "tardado" porque descarga todos los archivos necesarios para realizar la transformación xslt; en cambio con el valor "false" utilizará la copia, que deberá existir, de los archivos xslt locales ubicados en el directorio establecido en la variable XsltFilesDirectory
TMDCfdi33 _cfdi = new TMDCfdi33();
_cfdi.... //cargar datos.
_cfdi.SellaCfdi() //_cfdi.SellaCfdi(false);
El método SellaCfdi(bool setDataFromCertificate = true) tiene un parámetro opcional (establecido en "true") el cual cuando tiene un valor verdadero cambia los siguientes valores del objeto cfdi:
- NoCertificado
- Certificado (base64)
- Emisor.Rfc
- Emisor.Nombre
El cfdi en Xml se puede obtener de 2 maneras:
//obtenerlo como texto
string _cfdiXml = _cfdi.GetXmlCfdi();
//grabarlos directamente a un archivo
_cfdi.SaveXmlCfdi("nombre del archivo.xml")
¿Cómo timbrar un Cfdi?
Para timbrar el Cfdi es necesario utilizar los servicios de un PAC autorizado por parte del SAT, algunos tienen web services o kit de conectividad que nos permiten usar sus servicios y poder utilizarlos desde nuestras aplicaciones; afortunadamente encontré un servicio con "Ambiente de Pruebas" gratis por lo que pude hacer las pruebas necesarias y validar los Cfdi generados con la librería.
El procedimiento necesarios para ejecutar los servicios del PAC se implementan en una clase derivada de la clase TMDPAC la cual cuenta con dos métodos que deben de implementarse
- int TrimbraCfdi(string xmlString, out object customResult)
Los parámetros son un string con el xml del cfdi y el customResult es el resultado específico de cada PAC
- XmlNode GetXmlTrimbreFiscal()
Devuelve el XmlNode del timbre Fiscal
El ambiente de pruebas para las pruebas de timbrado con un PAC autorizado se llevaron a cabo con SW Smarter Web, la clase creada para su uso es:
public class TMDPAC_SmarterWebpRUEBAS: TMDPAC
{
AuthResponse m_authResponse = null;
StampResponseV4 m_response;
public TMDPAC_SmarterWebpRUEBAS()
{ }
public override int TimbraCfdi(string xmlString, out object customResult)
{
customResult = null;
int _result = -1;
m_response = null;
Stamp stamp = new Stamp("http://services.test.sw.com.mx", "demo", "123456789");
m_response = stamp.TimbrarV4(xmlString);
customResult = m_response;
if (m_response.status == "success")
_result = 0;
return _result;
}
public override XmlNode GetXmlTimbreFiscal()
{
XmlNode _result = null;
XmlDocument _xmlDoc = new XmlDocument();
try { _xmlDoc.LoadXml(m_response.data.cfdi); } catch { }
XmlElement _xmlComplemento = _xmlDoc.DocumentElement["cfdi:Complemento"];
foreach (XmlElement _nodX in _xmlComplemento)
if (_nodX.Name == "tfd:TimbreFiscalDigital")
{
_result = _nodX;
break;
}
return _result;
}
}
Y el código para trimbar el cfdi
TMDCfdi33 _cfdi = new TMDCfdi33()
//cargar los datos...
//Sellamos el cfdi si es necesario...
_cfdi.SellaCfdi(true);
//Creamos el objeto para usar el PAC
TMDPAC _pac = new TMDPAC_SmarterWebpRUEBAS();
object _customResult;
//Si el valor de _cfdi.Timbra es verdadero quiere decir que se timbró y se agregó el Complemento TFD al objeto
//si el valor es falso, pudo haberse timbrado pero no se agrego el TFD al objeto Cfdi
//si el valor es falso, pudo no haberse timbrado y no se agregó el TFD al objeto Cfdi
// esa es la función del customResult, que el usuario pueda evaluar el resultado de la consulta del PAC
if (_cfdi.Timbra(_pac, out _customResult))
_cfdi.SaveXmlCfdi(_saveAsFile);
¿Cargar un archivo Xml de un Cfdi 3.3, válido, a un objeto TMDCfdi33?
Cargar un archivo xml de un cfdi 3.3 válido dentro de un objeto TMDCfdi33 es de lo más sencillo:
TMDCfdi33 _cfdi = new TMDCfdi33();
_cfdi.Load(new FileInfo("Nombre del archivo"));
//Por qué el parámetro como FileInfo; porque hay una función "overload" del metodo Load que usa un string
string _xmlString = File.ReadAllText("nombre del archivo");
_cfdi.Load(_xmlString);
Programa de ejemplo
Librería y código fuente del ejemplo y de los Complementos Pagos 1.0 y Nomina 1.2
EL SOFTWARE SE PROPORCIONA "TAL CUAL" Y EL AUTOR RECHAZA TODAS LAS GARANTÍAS CON RESPECTO A ESTE SOFTWARE, INCLUIDAS TODAS LAS GARANTÍAS IMPLÍCITAS DE COMERCIABILIDAD Y ADECUACIÓN. EN NINGÚN CASO EL AUTOR SERÁ RESPONSABLE POR CUALQUIER DAÑO ESPECIAL, DIRECTO, INDIRECTO O CONSECUENTE, O CUALQUIER DAÑO QUE RESULTE DE LA PÉRDIDA DE USO, DATOS O BENEFICIOS, YA SEA EN UNA ACCIÓN DE CONTRATO, NEGLIGENCIA U OTRA ACCIÓN EXTRACONTRACTUAL QUE SURJA DE O EN CONEXIÓN CON EL USO O RENDIMIENTO DE ESTE SOFTWARE.
/* ********************************************** */
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIESWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Excelente aporte, te lo agradezco mucho Denny!!!!
ResponderEliminarLo que no he podido hacer es armar el xml, el schemma de nómina no me queda en el comprobante solo en la raiz; serias tan amable de compartime el "TMDXmlGenerator"?