amephia/sri-ec

High-performance Ecuador SRI Electronic Billing Library

Maintainers

Package info

github.com/JonathanTeran/teran-sri-ec

pkg:composer/amephia/sri-ec

Statistics

Installs: 213

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

v1.1.0 2026-02-02 01:55 UTC

This package is auto-updated.

Last update: 2026-03-30 16:33:27 UTC


README

Última Versión en Packagist Licencia de Software Descargas Totales Versión PHP

Librería profesional y de alto rendimiento para Facturación Electrónica del SRI Ecuador. Simplifica el proceso de generación, firma y autorización de documentos electrónicos según los últimos requerimientos técnicos del SRI.

✨ Características Principales

  • Firma Electrónica Universal: Compatible con archivos .p12 o .pfx de cualquier entidad certificadora del Ecuador.
  • Compatibilidad Avanzada: Manejo robusto de cadenas de confianza (certificados intermedios) y números de serie de gran longitud.
  • Algoritmos Modernos: Soporte dinámico para llaves RSA y ECDSA.
  • Todos los Comprobantes: Facturas, Notas de Crédito/Débito, Retenciones y Guías de Remisión.
  • Validación XSD: Validación local contra esquemas oficiales del SRI.
  • Cliente SOAP: Comunicación robusta con servicios web del SRI (Recepción y Autorización).
  • Clave de Acceso: Generación automática con algoritmo Módulo 11.
  • Validación de RUC: Online (SRI) con fallback local.
  • Soporte de Ambientes: pruebas y produccion.

🔐 Proveedores de Firma Soportados

Esta librería ha sido probada y ajustada para soportar certificados de:

  • Security Data (soporte para nuevos números de serie largos)
  • Uanataca (manejo correcto de cadena de confianza)
  • Banco Central del Ecuador (BCE)
  • ANF AC Ecuador
  • Consejo de la Judicatura
  • Datilmedia
  • Eclipsoft
  • Y cualquier otro proveedor que emita certificados estándar X.509 en formato PKCS#12.

📋 Tipos de Comprobantes Soportados

Tipo Código Método
Factura 01 facturaFromArray()
Nota de Crédito 04 notaCreditoFromArray()
Nota de Débito 05 notaDebitoFromArray()
Guía de Remisión 06 guiaRemisionFromArray()
Comprobante de Retención 07 retencionFromArray()

🔄 Flujo de Trabajo

sequenceDiagram
    participant App as Tu App (PHP)
    participant Lib as amephia/sri-ec
    participant SRI_REST as SRI Online (REST)
    participant SRI_SOAP as SRI Recepción (SOAP)

    App->>Lib: 1. Enviar Datos (Array)

    rect rgb(240, 240, 240)
        Note over Lib, SRI_REST: Validación RUC
        Lib->>SRI_REST: 2. Consultar RUC (Online)
        alt RUC Existe
            SRI_REST-->>Lib: OK
        else Fallo / Timeout
            Lib->>Lib: Fallback: Algoritmo Módulo 11
        end
    end

    Lib->>Lib: 3. Generar Clave de Acceso (49 dígitos)
    Lib->>Lib: 4. Generar XML
    Lib->>Lib: 5. Validar XSD
    Lib->>Lib: 6. Firmar XML (XAdES-BES)

    Lib->>SRI_SOAP: 7. Enviar XML Firmado
    SRI_SOAP-->>Lib: 8. Confirmación de Recepción

    Lib->>SRI_SOAP: 9. Solicitar Autorización
    SRI_SOAP-->>Lib: 10. Respuesta (AUTORIZADO/NO AUTORIZADO)

    Lib-->>App: 11. Retornar Resultado
Loading

🚀 Instalación

composer require amephia/sri-ec

🛠 Requisitos

  • PHP: ^8.1
  • Extensiones: ext-curl, ext-dom, ext-libxml, ext-openssl, ext-soap

📖 Uso

Configuración Básica

use Teran\Sri\SRI;

// Inicializar en ambiente 'pruebas' o 'produccion'
$sri = new SRI('pruebas');

// Configurar tu firma digital (.p12)
$p12 = file_get_contents('ruta/a/tu/firma.p12');
$sri->setFirma($p12, 'tu_contraseña_p12');

Procesar una Factura

$facturaData = [
    'infoTributaria' => [
        'ambiente' => '1', // 1=Pruebas, 2=Producción
        'razonSocial' => 'MI EMPRESA S.A.',
        'ruc' => '1790011001001',
        'estab' => '001',
        'ptoEmi' => '001',
        'secuencial' => '000000001',
        'dirMatriz' => 'Quito, Ecuador',
    ],
    'infoFactura' => [
        'fechaEmision' => '26/01/2026',
        'tipoIdentificacionComprador' => '05',
        'razonSocialComprador' => 'CLIENTE FINAL',
        'identificacionComprador' => '9999999999',
        'totalSinImpuestos' => '100.00',
        'totalDescuento' => '0.00',
        'importetotal' => '112.00',
        'totalConImpuestos' => [
            ['codigo' => '2', 'codigoPorcentaje' => '2', 'baseImponible' => '100.00', 'valor' => '12.00']
        ],
        'pagos' => [
            ['formaPago' => '01', 'total' => '112.00']
        ]
    ],
    'detalles' => [
        [
            'codigoPrincipal' => 'PROD001',
            'descripcion' => 'Producto de prueba',
            'cantidad' => '1.00',
            'precioUnitario' => '100.00',
            'descuento' => '0.00',
            'precioTotalSinImpuesto' => '100.00',
            'impuestos' => [
                ['codigo' => '2', 'codigoPorcentaje' => '2', 'tarifa' => '12.00', 'baseImponible' => '100.00', 'valor' => '12.00']
            ]
        ]
    ]
];

try {
    $resultado = $sri->facturaFromArray($facturaData);

    echo "Clave de Acceso: " . $resultado['claveAcceso'] . "\n";
    echo "Estado: " . $resultado['autorizacion']->estado . "\n";

    if ($resultado['autorizacion']->estado === 'AUTORIZADO') {
        echo "Número de Autorización: " . $resultado['autorizacion']->numeroAutorizacion . "\n";
        echo "Fecha de Autorización: " . $resultado['autorizacion']->fechaAutorizacion . "\n";
    } else {
        foreach ($resultado['autorizacion']->mensajes as $mensaje) {
            echo "Error [{$mensaje->identificador}]: {$mensaje->mensaje}\n";
        }
    }
} catch (\Teran\Sri\Exceptions\ValidationException $e) {
    echo "Error de validación: " . $e->getMessage() . "\n";
    foreach ($e->getErrors() as $error) {
        echo "- $error\n";
    }
}

Procesar Nota de Crédito

$notaCreditoData = [
    'infoTributaria' => [
        'ambiente' => '1',
        'razonSocial' => 'MI EMPRESA S.A.',
        'ruc' => '1790011001001',
        'estab' => '001',
        'ptoEmi' => '001',
        'secuencial' => '000000001',
        'dirMatriz' => 'Quito, Ecuador',
    ],
    'infoNotaCredito' => [
        'fechaEmision' => '26/01/2026',
        'tipoIdentificacionComprador' => '05',
        'razonSocialComprador' => 'CLIENTE FINAL',
        'identificacionComprador' => '9999999999',
        'codDocModificado' => '01', // Factura
        'numDocModificado' => '001-001-000000001',
        'fechaEmisionDocSustento' => '25/01/2026',
        'totalSinImpuestos' => '50.00',
        'valorModificacion' => '56.00',
        'moneda' => 'DOLAR',
        'totalConImpuestos' => [
            ['codigo' => '2', 'codigoPorcentaje' => '2', 'baseImponible' => '50.00', 'valor' => '6.00']
        ],
        'motivo' => 'Devolución parcial de mercadería'
    ],
    'detalles' => [/* ... */]
];

$resultado = $sri->notaCreditoFromArray($notaCreditoData);

Procesar Comprobante de Retención

$retencionData = [
    'infoTributaria' => [
        'ambiente' => '1',
        'razonSocial' => 'MI EMPRESA S.A.',
        'ruc' => '1790011001001',
        'estab' => '001',
        'ptoEmi' => '001',
        'secuencial' => '000000001',
        'dirMatriz' => 'Quito, Ecuador',
    ],
    'infoCompRetencion' => [
        'fechaEmision' => '26/01/2026',
        'tipoIdentificacionSujetoRetenido' => '04',
        'razonSocialSujetoRetenido' => 'PROVEEDOR S.A.',
        'identificacionSujetoRetenido' => '1790011001001',
        'periodoFiscal' => '01/2026',
    ],
    'docsSustento' => [
        [
            'codSustento' => '01',
            'codDocSustento' => '01',
            'numDocSustento' => '001-001-000000001',
            'fechaEmisionDocSustento' => '25/01/2026',
            'totalSinImpuestos' => '1000.00',
            'importeTotal' => '1120.00',
            'retenciones' => [
                [
                    'codigo' => '1', // Renta
                    'codigoRetencion' => '303',
                    'baseImponible' => '1000.00',
                    'porcentajeRetener' => '10.00',
                    'valorRetenido' => '100.00'
                ]
            ]
        ]
    ]
];

$resultado = $sri->retencionFromArray($retencionData);

Consultar Estado de Autorización

$claveAcceso = '2601202601179001100100110010010000000011234567811';
$autorizacion = $sri->consultarAutorizacion($claveAcceso);

if ($autorizacion->estado === 'AUTORIZADO') {
    echo "Comprobante autorizado\n";
} else {
    echo "No autorizado: " . $autorizacion->mensajes[0]->mensaje . "\n";
}

Solo Firmar XML (Sin Enviar)

$xmlFirmado = $sri->firmarXml($xmlSinFirma);

🏗 Uso Avanzado

Para implementaciones personalizadas, puedes usar ComprobanteInterface:

use Teran\Sri\Strategies\ComprobanteInterface;

class MiDocumentoPersonalizado implements ComprobanteInterface {
    public function getTipo(): string { return '01'; }
    public function generarXml(): string { /* ... */ }
    public function getXsdPath(): string { /* ... */ }
    public function getDatosClave(): array { /* ... */ }
}

$resultado = $sri->procesar(new MiDocumentoPersonalizado());

📂 Estructura del Proyecto

src/
├── SRI.php                    # Clase principal
├── Generators/                # Generadores de XML
│   ├── FacturaGenerator.php
│   ├── NotaCreditoGenerator.php
│   ├── NotaDebitoGenerator.php
│   ├── RetencionGenerator.php
│   └── GuiaRemisionGenerator.php
├── Signature/
│   └── XadesSignature.php     # Firma XAdES-BES
├── Soap/
│   └── SriSoapClient.php      # Cliente SOAP
├── Schema/
│   ├── XsdValidator.php
│   └── BusinessValidator.php
├── Dto/
│   ├── RecepcionResponse.php
│   ├── AutorizacionResponse.php
│   └── Mensaje.php
├── Utils/
│   ├── ClaveAcceso.php        # Generador Módulo 11
│   └── RucValidator.php
└── Exceptions/
    └── SriException.php

🔐 Estructura de Firma XAdES-BES

La firma digital cumple con el estándar XAdES-BES requerido por el SRI:

<ds:Signature>
    <ds:SignedInfo>
        <ds:Reference URI="#comprobante">...</ds:Reference>
        <ds:Reference URI="#SignedProperties-...">...</ds:Reference>
        <ds:Reference URI="#Certificate-...">...</ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>...</ds:SignatureValue>
    <ds:KeyInfo>
        <ds:X509Data>
            <ds:X509Certificate>...</ds:X509Certificate>
        </ds:X509Data>
        <ds:KeyValue>
            <ds:RSAKeyValue>
                <ds:Modulus>...</ds:Modulus>
                <ds:Exponent>...</ds:Exponent>
            </ds:RSAKeyValue>
        </ds:KeyValue>
    </ds:KeyInfo>
    <ds:Object>
        <xades:QualifyingProperties>
            <xades:SignedProperties>
                <xades:SignedSignatureProperties>
                    <xades:SigningTime>...</xades:SigningTime>
                    <xades:SigningCertificate>
                        <xades:Cert>
                            <xades:CertDigest>...</xades:CertDigest>
                            <xades:IssuerSerial>...</xades:IssuerSerial>
                        </xades:Cert>
                    </xades:SigningCertificate>
                </xades:SignedSignatureProperties>
                <xades:SignedDataObjectProperties>
                    <xades:DataObjectFormat>
                        <xades:Description>Comprobante electrónico</xades:Description>
                        <xades:MimeType>text/xml</xades:MimeType>
                        <xades:Encoding>UTF-8</xades:Encoding>
                    </xades:DataObjectFormat>
                </xades:SignedDataObjectProperties>
            </xades:SignedProperties>
        </xades:QualifyingProperties>
    </ds:Object>
</ds:Signature>

🔧 Troubleshooting

Error: "Could not read p12 file" o "error:0308010C:digital envelope routines::unsupported"

Causa: Certificados P12 legacy (pre-2024) usan algoritmos de cifrado RC2/3DES que OpenSSL 3.0+ rechaza por defecto.

Solución: Esta librería automáticamente usa OpenSSL 1.1 cuando está disponible. En macOS con Homebrew:

brew install openssl@1.1

La librería detectará automáticamente la instalación y la usará para certificados legacy.

Error: "FECHA EMISIÓN EXTEMPORÁNEA"

Causa: El SRI rechaza facturas con fechas que no coinciden con la fecha/hora actual del servidor SRI.

Solución:

  1. Generar y enviar la factura inmediatamente (no guardar para enviar después)
  2. Usar la zona horaria de Ecuador: America/Guayaquil
  3. Formato de fecha correcto: dd/MM/yyyy (ej: 01/02/2026)
// Correcto
date_default_timezone_set('America/Guayaquil');
$fecha = date('d/m/Y'); // Fecha actual en Ecuador

Error: "Class 'Teran\Sri\Exceptions\SignatureException' not found"

Causa: Problema de autoloading (solo en versiones antiguas del paquete).

Solución: Actualizar a la última versión:

composer update amephia/sri-ec

Error: "No matching global element declaration available"

Causa: XSD con validación strict para firma digital (solo en versiones antiguas).

Solución: Actualizar a la última versión que incluye XSD con processContents="lax".

Certificados Soportados

Funcionan correctamente:

  • Certificados legacy (2020-2024) con OpenSSL 1.1
  • Certificados modernos (2025+) con OpenSSL 3.0+
  • Todos los proveedores ecuatorianos (Uanataca, Security Data, BCE, ANF AC, etc.)

🤝 Contribuir

¡Las contribuciones son bienvenidas! No dudes en enviar un Pull Request.

📄 Licencia

Licencia MIT. Por favor consulta el Archivo de Licencia para más información.

Desarrollado con ❤️ por Jonathan Terán