PHP code example of grodtech / ecf-php

1. Go to this page and download the library: Download grodtech/ecf-php library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

grodtech / ecf-php example snippets



Grodtech\Ecf\Client;
use Grodtech\Ecf\ResultInterpreter;

$client = new Client(
    'https://ecf.grodtech.com/certeCF',
    getenv('ECF_GRODTECH_API_KEY') ?: throw new RuntimeException('Falta ECF_GRODTECH_API_KEY')
);

$payload = [
    'ECF' => [
        'Encabezado' => [
            'Version' => '1.0',
            'IdDoc' => [
                'TipoeCF' => 31,
                'eNCF' => 'E310000000001',
                'FechaVencimientoSecuencia' => '31-12-2028',
                'IndicadorMontoGravado' => '0',
                'TipoIngresos' => '05',
                'TipoPago' => '2',
                'FechaLimitePago' => '10-06-2026',
            ],
            'Emisor' => [
                'RNCEmisor' => '{{RNC}}',
                'RazonSocialEmisor' => '{{RAZON_SOCIAL}}',
                'DireccionEmisor' => '{{DIRECCION_EMISOR}}',
                'FechaEmision' => '{{FECHA_EMISION}}',
            ],
            'Comprador' => [
                'RNCComprador' => '101023122',
                'RazonSocialComprador' => 'INVERSIONES CARIBE EXPRESS SRL',
            ],
            'Totales' => [
                'MontoGravadoTotal' => 1000,
                'MontoGravadoI1' => 1000,
                'ITBIS1' => 18,
                'TotalITBIS' => 180,
                'MontoTotal' => 1180,
            ],
        ],
        'DetallesItems' => [
            'Item' => [[
                'NumeroLinea' => '1',
                'IndicadorFacturacion' => '1',
                'NombreItem' => 'Producto demo',
                'IndicadorBienoServicio' => '1',
                'CantidadItem' => 1,
                'UnidadMedida' => '43',
                'PrecioUnitarioItem' => 1000,
                'MontoItem' => 1000,
            ]],
        ],
        'FechaHoraFirma' => '',
    ],
];

$response = $client->recepcionJson($payload);
$result = ResultInterpreter::gatewayRecepcion($response);

echo 'Estado : ' . $result->outcome->labelEs() . PHP_EOL;
echo 'TrackId: ' . $result->trackId . PHP_EOL;
echo 'Detalle: ' . $result->summary . PHP_EOL;

$payloadRfce = [
    'RFCE' => [
        'Encabezado' => [
            'Version' => '1.0',
            'IdDoc' => [
                'TipoeCF' => 32,
                'eNCF' => 'E320000000050',
                'TipoIngresos' => '01',
                'TipoPago' => '1',
                'TablaFormasPago' => [
                    'FormaDePago' => [['FormaPago' => '1', 'MontoPago' => 1475.00]],
                ],
            ],
            'Emisor' => [
                'RNCEmisor' => '{{RNC}}',
                'RazonSocialEmisor' => '{{RAZON_SOCIAL}}',
                'FechaEmision' => '{{FECHA_EMISION}}',
            ],
            'Totales' => [
                'MontoGravadoTotal' => 1250.00,
                'MontoGravadoI1' => 1250.00,
                'TotalITBIS' => 225.00,
                'TotalITBIS1' => 225.00,
                'MontoTotal' => 1475.00,
            ],
            'CodigoSeguridadeCF' => '{{CODIGO_SEGURIDAD_RFCE}}',
        ],
        'FechaGeneracion' => '{{FECHA_GENERACION_ISO}}',
    ],
];

$response = $client->recepcionJson($payloadRfce);

use Grodtech\Ecf\JsonToXml;

$built = JsonToXml::documentFromArray($payload);
if ($built['ok']) {
    file_put_contents('preview_E310000000001.xml', $built['xml']);
} else {
    fwrite(STDERR, "JSON inválido: {$built['error']}\n");
}

$xmlFirmado = file_get_contents('comprobante_firmado.xml');
$response = $client->recepcionXml($xmlFirmado);
$result = ResultInterpreter::gatewayRecepcion($response);

$xmlAprobacion = file_get_contents('aprobacion_comercial.xml');
$response = $client->aprobacionComercialXml($xmlAprobacion);
$result = ResultInterpreter::gatewayRecepcion($response);

use Grodtech\Ecf\ResultInterpreter;

$bodyJson = '{"trackId":"abc-123","estado":"Aceptado","codigo":"0","mensajes":[]}';
$consulta = ResultInterpreter::dgiiConsultaFromBody($bodyJson);

echo $consulta->outcome->labelEs() . PHP_EOL;
foreach ($consulta->mensajesTexto as $msg) {
    echo "  · {$msg}" . PHP_EOL;
}

public function __construct(
    string $baseUrl,
    string $apiKey,
    int    $timeoutSeconds        = 120,
    int    $connectTimeoutSeconds = 10,
    bool   $allowInsecureHttp     = false
);

public function recepcionJson(array $document): array;
public function recepcionXml(string $xml): array;
public function aprobacionComercialXml(string $xml): array;

public static function applyPlaceholders(mixed &$node, array $placeholders): void;
public static function documentFromArray(array $data): array;  // ['ok','xml','is_rfce','error'?]
public static function ecfToUnsignedXml(array $ecfRoot): string;
public static function ensureFechaHoraFirmaPlaceholder(array &$data): void;
public static function ensureFechaGeneracionRfce(array &$data): void;

public static function gatewayRecepcion(array $json): GatewayRecepcionResult;
public static function dgiiConsultaFromBody(string $body): DgiiConsultaResult;
public static function dgiiConsultaFromArray(array $json, string $rawBody = ''): DgiiConsultaResult;

StandardPlaceholders::RNC;
StandardPlaceholders::RAZON_SOCIAL;
StandardPlaceholders::NOMBRE_COMERCIAL;
StandardPlaceholders::DIRECCION_EMISOR;
StandardPlaceholders::FECHA_EMISION;
StandardPlaceholders::FECHA_LIMITE_PAGO;
StandardPlaceholders::FECHA_VENC_SEQ;
StandardPlaceholders::NCF_MODIFICADO;
StandardPlaceholders::CODIGO_SEGURIDAD_RFCE;
StandardPlaceholders::FECHA_GENERACION_ISO;

StandardPlaceholders::wrap(StandardPlaceholders::RNC); // '{{RNC}}'

$response = $client->recepcionJson($payload);
$result = ResultInterpreter::gatewayRecepcion($response);

match ($result->outcome) {
    DgiiOutcome::Approved => $this->markApproved($encf, $result->trackId, $result->raw),
    DgiiOutcome::Pending  => $this->markQueuedForRetry($encf, $result->trackId),
    DgiiOutcome::Partial  => $this->markWithObservations($encf, $result->trackId, $result->raw),
    DgiiOutcome::Rejected => $this->markRejected($encf, $result->error, $result->raw),
    DgiiOutcome::Error    => $this->scheduleRetry($encf, $result->http, $result->curlError),
    DgiiOutcome::Unknown  => $this->logForManualReview($encf, $result->raw),
};

use PHPUnit\Framework\TestCase;
use Grodtech\Ecf\ResultInterpreter;
use Grodtech\Ecf\DgiiOutcome;

final class ResultInterpreterTest extends TestCase
{
    public function testApprovedOutcome(): void
    {
        $json = ['ok' => true, 'trackId' => 'abc-123'];
        $result = ResultInterpreter::gatewayRecepcion($json);

        $this->assertSame(DgiiOutcome::Approved, $result->outcome);
        $this->assertSame('abc-123', $result->trackId);
    }

    public function testRejectedOutcome(): void
    {
        $json = ['ok' => false, 'error' => 'eNCF inválido', 'http' => 200];
        $result = ResultInterpreter::gatewayRecepcion($json);

        $this->assertSame(DgiiOutcome::Rejected, $result->outcome);
    }
}
json
{
  "repositories": [
    {
      "type": "path",
      "url": "packages/grodtech-ecf-php"
    }
  ],
  "
bash
composer update grodtech/ecf-php