Sin dependencias de vendors
100% open-source y MIT. No hay licencias, suscripciones ni lock-in con ningún proveedor.
Esta guía te ayuda a migrar a UruFactura SDK desde diferentes puntos de partida, ya sea que estés usando una solución propietaria, integrando SOAP directamente, o usando otra librería.
Sin dependencias de vendors
100% open-source y MIT. No hay licencias, suscripciones ni lock-in con ningún proveedor.
API idiomática en C#
Objetos tipados, métodos async/await, DI-friendly. No más SOAP ni XML manual.
Mantenido con .NET 10
Soporte para las últimas versiones de .NET. Sin librerías legacy ni WCF.
Todo incluido
XML, firma digital, SOAP, CAE, PDFs. Una sola dependencia.
Si actualmente construís los XML y llamadas SOAP a mano:
// ❌ Antes: construir XML manualmente y llamar SOAPvar xml = $@"<?xml version=""1.0"" encoding=""UTF-8""?><CFE xmlns=""http://www.dgi.gub.uy/wdgi/CFEv1""> <eTck> <TmstFirma>{DateTime.UtcNow:o}</TmstFirma> <Encabezado> <IdDoc> <TipoCFE>101</TipoCFE> <Serie>A</Serie> <Nro>1</Nro> ... </IdDoc> </Encabezado> ... </eTck></CFE>";
// Firmar XML con XmlDsig... (código extenso)var soapEnvelope = WrapInSoapEnvelope(signedXml);var response = await httpClient.PostAsync(dgiEndpoint, soapContent);// Parsear respuesta SOAP manualmente...// ✅ Después: API de alto nivelvar eticket = client.CrearETicket();eticket.Numero = 1;eticket.Detalle.Add(new LineaDetalle{ NroLinea = 1, NombreItem = "Servicio", Cantidad = 1, PrecioUnitario = 1000m, IndFactIva = TipoIva.Basico,});
var respuesta = await client.EnviarCfeAsync(eticket);Si estás migrando desde un módulo de facturación electrónica de un ERP (Biscuit, Pragma, ContaPyme, etc.):
| Tu sistema actual | UruFactura SDK |
|---|---|
| Comprobante / Documento | Cfe (base) + ETicket, EFactura, etc. |
| Línea de artículo / ítem | LineaDetalle |
| Proveedor / Receptor | Receptor |
| Rango CAE / Talonario | Cae con RangoDesde / RangoHasta |
| Estado del comprobante | RespuestaDgi.Exitoso + RespuestaDgi.Codigo |
| Representación impresa | client.GenerarPdfA4() / GenerarPdfTermico() |
Mantener ambos sistemas en paralelo
No apagues el sistema anterior hasta validar el nuevo en homologación.
Mapear los tipos de CFE
// Mapeo desde tu sistema a TipoCfeTipoCfe MapearTipo(string tipoSistemaAnterior) => tipoSistemaAnterior switch{ "TICKET" => TipoCfe.ETicket, "FACTURA" => TipoCfe.EFactura, "NC_TICKET" => TipoCfe.NotaCreditoETicket, "NC_FACTURA" => TipoCfe.NotaCreditoEFactura, _ => throw new ArgumentException($"Tipo desconocido: {tipoSistemaAnterior}")};Adaptar la estructura de datos
// Convertir entidad de tu sistema a LineaDetalle del SDKstatic LineaDetalle ConvertirLinea(MiLineaFactura linea, int nroLinea) => new LineaDetalle { NroLinea = nroLinea, NombreItem = linea.DescripcionProducto, Cantidad = linea.Cantidad, PrecioUnitario = linea.PrecioUnitario, IndFactIva = linea.EsExento ? TipoIva.Exento : linea.IvaMinimo ? TipoIva.Minimo : TipoIva.Basico, };Implementar una capa de servicio
public class FacturacionService{ private readonly UruFacturaClient _client;
public async Task<ResultadoEmision> EmitirAsync(ComprobanteDTO dto) { var cfe = dto.Tipo switch { "TICKET" => (Cfe)_client.CrearETicket(), "FACTURA" => _client.CrearEFactura(), _ => throw new ArgumentException($"Tipo no soportado: {dto.Tipo}") };
cfe.Numero = dto.Numero;
if (dto.Receptor != null) { cfe.Receptor = new Receptor { Documento = dto.Receptor.Rut, RazonSocial = dto.Receptor.Nombre, Direccion = dto.Receptor.Direccion, Ciudad = dto.Receptor.Ciudad, }; }
int nroLinea = 1; foreach (var linea in dto.Lineas) cfe.Detalle.Add(ConvertirLinea(linea, nroLinea++));
var respuesta = await _client.EnviarCfeAsync(cfe);
return new ResultadoEmision { Exitoso = respuesta.Exitoso, Codigo = respuesta.Codigo, Mensaje = respuesta.Mensaje, PdfA4 = respuesta.Exitoso ? _client.GenerarPdfA4(cfe) : null, }; }}Probar en homologación
Reproducí los escenarios más comunes de tu operación: ventas simples, notas de crédito, exportación.
Migrar los CAEs
Solicitá nuevos CAEs en DGI o trasladá los existentes. Registralos con:
client.Cae.RegistrarCae(new Cae { ... });Cambiar a producción
Ambiente = Ambiente.ProduccionSi estás usando otra librería .NET de facturación electrónica uruguaya:
| Operación | Librería genérica | UruFactura SDK |
|---|---|---|
| Crear comprobante | new Comprobante(tipo) | client.CrearETicket() |
| Agregar ítem | comprobante.AddItem(...) | cfe.Detalle.Add(new LineaDetalle {...}) |
| Firmar XML | firma.Sign(xml, cert) | Automático en EnviarCfeAsync |
| Enviar a DGI | soap.Send(xml) | await client.EnviarCfeAsync(cfe) |
| Generar PDF | pdf.Render(comprobante) | client.GenerarPdfA4(cfe) |
| Estado CFE | soap.ConsultarEstado(id) | await client.ConsultarEstadoCfeAsync(cfe) |
// UruFactura SDK — respuesta tipadavar respuesta = await client.EnviarCfeAsync(cfe);
// respuesta.Exitoso: bool// respuesta.Codigo: string ("00", "01", "05", ...)// respuesta.Mensaje: string (descripción DGI)
if (respuesta.Exitoso){ // CFE aceptado (código 00 o 01)}else{ // Revisar respuesta.Codigo y respuesta.Mensaje}Antes de ir a producción, verificá: