Infoware.SRI.DocumentosElectronicos

Permite trabajar con documentos electrónicos del SRI Ecuador. Puede crear un documento como Factura, Nota de Débito, Nota de Crédito, Comprobante de Retención, Guia de Remisión y Liquidación de compras. Firma documento en modo online y offline. Envia documento al WebService del SRI. Genera RIDE pdf y xml para ser enviados al cliente. Se puede agregar como inyección de dependencia a un proyecto existente.


Keywords
License
MIT
Install
Install-Package Infoware.SRI.DocumentosElectronicos -Version 1.1.45

Documentation

Infoware.SRI

Facturacion Electronica SRI (Servicio de Rentas Internas de Ecuador) compatible con .net5

Debido a la casi nula información para implementar la factura electrónica en un lenguaje diferente a Java, procedí a hacer ingeniería inversa a varios proyectos de código abierto, a estudiar la documentación que provee el SRI (https://www.sri.gob.ec/facturacion-electronica#informaci%C3%B3n) y a generar escenarios de pruebas usando el aplicativo COMPROBANTES ELECTRONICOS OFFLINE.

Obtenlo

NuGet Badge NuGet Badge NuGet Badge NuGet Badge NuGet Badge NuGet Badge NuGet Badge

Hoja de ruta

  • Implementado el firmado electrónico con XadES_BES tipo "Enveloped" usando como base el proyecto https://github.com/ctt-gob-es/FirmaXadesNet45
  • Implementado el XSD factura_V2.1.0.xsd
  • Validación de la factura firmada usando el propio XSD
  • Implementado el modelo básico de factura
  • Comunicación con el servicio SOAP del SRI en modo Test y Producción
  • Implementado el uso de esquema Online y Offline
  • Implementada la generación del RIDE PDF usando PdfSharp http://www.pdfsharp.net/PDFsharp_License.ashx

Cómprame un café

Si quieres recompensar mi esfuerzo, https://www.paypal.com/paypalme/vicosanzdev?locale.x=es_XC

Modo de uso

Para declarar el certificado, como en mi caso que tengo un archivo p12 de una entidad certificadora solo lo deben declarar de la siguiente manera:

            Certificado certificado = new();
            certificado.CargarDesdeP12(@"C:\Certificados\mi_firma.p12", "clavefirma");

En caso de querer cargar el certificado desde el almacén de certificados del computador:

            certificado.CargarDesdeAlmacen(StoreName.My, StoreLocation.CurrentUser, "VICTOR HUGO SANCHEZ SOLORZANO");

Revisar en el almacén de certificados cuál es el Nombre Descriptivo exacto del certificado instalado y que no esté expirado.

Por último podemos seleccionar el certificado desde el almacén de certificados del computador desde un cuadro de diálogo:

            certificado.CargarDesdeDialogo("Seleccionar certificado", "Seleccione el certificado que se usará para firmar los documentos");

Luego inicializaremos la clase que controla el WebService del SRI

        Service service = new(testMode: true);

Por defecto está en modo producción, por lo que debemos especificar testMode en true para el ambiente de pruebas.

Para modelar un objeto factura usaremos una clase Modelo

        private static FacturaModelo.Factura FacturaEjemplo()
        {
            return new()
            {
                InfoTributaria = new()
                {
                    EnumTipoAmbiente = Facturacion.Enumerados.EnumTipoAmbiente.Prueba,
                    EnumTipoEmision = Facturacion.Enumerados.EnumTipoEmision.Normal,
                    RazonSocial = "SANCHEZ SOLORZANO VICTOR HUGO",
                    RUC = "0994545554001",
                    EnumTipoDocumento = Facturacion.Enumerados.EnumTipoDocumento.Factura,
                    Establecimiento = 1,
                    PuntoEmision = 1,
                    Secuencial = 2,
                    DireccionMatriz = "Urb Costa del Este"
                },
                InfoFactura = new()
                {
                    FechaEmision = DateTime.Now,
                    ObligadoContabilidad = false,
                    TipoIdentificadorComprador = Facturacion.Enumerados.EnumTipoIdentificacion.VentaConsumidorFinal,
                    RazonSocialComprador = "CONSUMIDOR FINAL",
                    IdentificacionComprador = "9999999999999",
                    TotalSinImpuestos = 1,
                    TotalDescuento = 0,
                    TotalConImpuestos = new List<FacturaModelo.Impuesto>() {
                        new FacturaModelo.ImpuestoIVA()
                        {
                            Codigo = Facturacion.Enumerados.EnumTipoImpuesto.IVA,
                            CodigoPorcentaje = Facturacion.Enumerados.EnumTipoImpuestoIVA._12,
                            BaseImponible = 1,
                            Tarifa = 12,
                            Valor = 0.12m
                        }
                    },
                    Propina = 0,
                    ImporteTotal = 1.12m,
                    Moneda = "DOLAR",
                    Pagos = new()
                    {
                        new FacturaModelo.Pago()
                        {
                            FormaPago = Facturacion.Enumerados.EnumFormaPago.SinUtilizarSistemaFinanciero,
                            Total = 1.12m
                        }
                    }
                },

                Detalles = new()
                {
                    new FacturaModelo.Detalle()
                    {
                        CodigoPrincipal = "1",
                        CodigoAuxiliar = "1",
                        Descripcion = "MANTENIMIENTO",
                        Cantidad = 1,
                        PrecioUnitario = 1.0m,
                        Descuento = 0.0m,
                        PrecioTotalSinImpuesto = 1.00m,
                        Impuestos = new()
                        {
                            new FacturaModelo.ImpuestoIVA()
                            {
                                Codigo = Facturacion.Enumerados.EnumTipoImpuesto.IVA,
                                CodigoPorcentaje = Facturacion.Enumerados.EnumTipoImpuestoIVA._12,
                                Tarifa = 12,
                                BaseImponible = 1.00m,
                                Valor = 0.12m
                            }
                        }
                    }
                }
            };
        }

El modelo contiene varios enumerados que harán fácil el modelado de datos.

Para firmar una factura deberemos:

  • Mapear el modelo a la clase derivada del XSD Factura
            var facturaContract = FacturaMapper.Map(factura);
  • Firmar el documento usando el contrato, creando un XmlDocument firmado
            var xmlDocumentFirmado = certificado.FirmarDocumento(facturaContract);

Con estos pasos tendremos un documento XML debidamente firmado por nuestro certificado en memoria, evitando la generación indiscriminada de archivos y de operaciones I/O.

  • (Opcional) Para Validar nuestro XML resultante usaremos el XSD que está embebido en los fuentes.
            SchemasValidador.ValidarFactura(xmlDocumentFirmado, SchemaValidationHandler);
        }

        private static void SchemaValidationHandler(object sender, ValidationEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

En este punto ya podemos enviar nuestro RIDE Auto Autorizado en el esquema offline al Cliente usando lo siguiente:

            var response = service.UsingOffline().AutoAutorizacionComprobante(
                xmlFirmado, 
                DateTime.Now, 
                facturaContract.infoTributaria.claveAcceso);

            var numeroAutorizacion = response.Ok ? response.Data.NumeroAutorizacion : null;

            Console.WriteLine("Enviar al cliente");
            var xmlDocumentoaEnviar = response.Data.ToXmlDocument();
            var rutaArchivoPDF = RIDE.Generar.DesdeFactura(facturaContract, numeroAutorizacion, fechaAutorizacion);

En este esquema la clave de Acceso del documento se convertirá en el Número de Autorización

Con nuestro documento firmado podemos validarlo usando el WebService del SRI de la siguiente forma

            var response = await service.UsingOffline()
                .ValidarComprobanteAsync(xmlDocumentFirmado);
            var claveAcceso = response.Ok ? response.Data.Comprobantes.Comprobante.ClaveAcceso : null; 

La expresión response.Ok siempre nos devolverá True si la operación ha sido satisfactoria. Estado == "RECIBIDA" Por defecto usa el método Online por lo que deberemos emplear .UsingOffline() para cambiarlo a Offline

Si queremos verificar la Autorización de nuestro documento validado en el paso anterior:

            var response = await service.UsingOffline()
                .AutorizacionComprobanteAsync(claveAcceso);
            return response.Ok;

La expresión response.Ok siempre nos devolverá True si la operación ha sido satisfactoria. Estado == "AUTORIZADO"

ToDos

  • Implementar con inyección de dependencia
  • Implementar los XSD restantes
  • Proyectos de Test

Siéntanse en libertad de enviar sus PRs.