> ## Documentation Index
> Fetch the complete documentation index at: https://docs.suot.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# MDF-e: emissão e encerramento com o SUOT Fiscal SDK

> Gerencie Manifestos Eletrônicos de Documentos Fiscais com o SUOT Fiscal SDK: emissão, encerramento e inclusão de condutor tipados.

O **MDF-e (Manifesto Eletrônico de Documentos Fiscais)** agrupa CT-e e NF-e em uma única declaração de carga por viagem no transporte rodoviário, sendo exigido pela SEFAZ para operações interestaduais e de cabotagem. O SUOT Fiscal SDK expõe Commands e Handlers tipados para cada operação do ciclo de vida do MDF-e — emissão, encerramento, inclusão de condutor e cancelamento —, sempre retornando um `Result` estruturado ou lançando `InfrastructureException` em caso de falha técnica. Da ordem ao resultado.

## Operações disponíveis

<CardGroup cols={2}>
  <Card title="Emissão" icon="file-circle-plus">
    Cria e transmite um novo MDF-e à SEFAZ. Retorna `EmitirMDFeResult` com chave, protocolo e XML autorizado.
  </Card>

  <Card title="Encerramento" icon="flag-checkered">
    Encerra um MDF-e autorizado ao final da viagem. Obrigatório antes de emitir um novo manifesto para o mesmo veículo na mesma UF.
  </Card>

  <Card title="Inclusão de condutor" icon="id-card">
    Adiciona um condutor a um MDF-e já autorizado sem a necessidade de cancelamento e reemissão.
  </Card>

  <Card title="Cancelamento" icon="ban">
    Cancela um MDF-e autorizado dentro do prazo legal. <br /><br /> **Em desenvolvimento** — disponível em breve.
  </Card>
</CardGroup>

## Construindo um MDF-e

Use `MDFeBuilder` com o padrão **Step Builder** para compor o `EmitirMDFeCommand`. Cada etapa da construção retorna a próxima interface obrigatória, impedindo estados inválidos antes mesmo da execução.

```php theme={null}
<?php

use Suot\Fiscal\MDFe\Builder\MDFeBuilder;
use Suot\Fiscal\MDFe\Command\EmitirMDFeCommand;
use Suot\Fiscal\MDFe\Enum\ModalTransporte;
use Suot\Fiscal\MDFe\Enum\TipoEmitente;
use Suot\Fiscal\ValueObjects\Cnpj;
use Suot\Fiscal\ValueObjects\ChaveCTe;
use Suot\Fiscal\ValueObjects\Municipio;
use Suot\Fiscal\ValueObjects\Uf;
use Suot\Fiscal\ValueObjects\Placa;
use Suot\Fiscal\ValueObjects\Rntrc;
use Suot\Fiscal\ValueObjects\Peso;

$command = MDFeBuilder::novo()
    ->comModal(ModalTransporte::Rodoviario)
    ->comTipoEmitente(TipoEmitente::TransportadorCargaPropria)
    ->comDataEmissao(new DateTimeImmutable('2025-06-15'))
    ->comEmitente(
        cnpj: Cnpj::from('12.345.678/0001-99'),
        razaoSocial: 'Transportadora Exemplo Ltda',
        uf: Uf::SP,
    )
    ->comVeiculo(
        placa: Placa::from('ABC1D23'),
        rntrc: Rntrc::from('12345678'),
        uf: Uf::SP,
    )
    ->comCondutor(
        nome: 'João da Silva',
        cpf: \Suot\Fiscal\ValueObjects\Cpf::from('123.456.789-09'),
    )
    ->comPercurso(
        ufInicio: Uf::SP,
        ufFim: Uf::RJ,
    )
    ->adicionarMunicipioCarga(
        municipio: Municipio::from(codigoIbge: '3550308'), // São Paulo - SP
        documentos: [
            ChaveCTe::from('35250612345678000199570010000010011234567890'),
            ChaveCTe::from('35250612345678000199570010000010021234567891'),
        ],
    )
    ->comCargaTotal(
        pesoTotal: Peso::bruto(quilos: 8_500.00),
        quantidadeDocumentos: 2,
    )
    ->build(); // retorna EmitirMDFeCommand (imutável)
```

<Note>
  As chaves de CT-e informadas em `adicionarMunicipioCarga()` devem corresponder a documentos já autorizados pela SEFAZ. O SDK valida o formato das chaves (44 dígitos com dígito verificador correto) no momento da construção, mas a validação de existência é feita pelo fisco no momento da transmissão.
</Note>

## Executando e inspecionando o Result

```php theme={null}
<?php

use Suot\Fiscal\MDFe\Handler\EmitirMDFeHandler;
use Suot\Fiscal\MDFe\Result\EmitirMDFeResult;
use Suot\Fiscal\Exception\InfrastructureException;

// $handler é injetado via DI (Laravel Bridge) ou instanciado manualmente
/** @var EmitirMDFeHandler $handler */

try {
    $result = $handler->handle($command);
} catch (InfrastructureException $e) {
    // Falha técnica: conexão, certificado, webservice indisponível.
    logger()->critical('Falha ao transmitir MDF-e', [
        'mensagem' => $e->getMessage(),
    ]);
    throw $e;
}

if ($result->isSuccess()) {
    $chave       = $result->getChave();        // ChaveMDFe (44 dígitos)
    $protocolo   = $result->getProtocolo();    // Protocolo de autorização
    $xmlAutorizado = $result->getXmlAutorizado();

    logger()->info('MDF-e autorizado', [
        'chave'     => (string) $chave,
        'protocolo' => (string) $protocolo,
    ]);
} else {
    $rejeicao = $result->getRejeicao();

    logger()->warning('MDF-e rejeitado pela SEFAZ', [
        'codigo'    => $rejeicao->getCodigo(),
        'descricao' => $rejeicao->getDescricao(),
    ]);
}
```

## Encerramento

O encerramento deve ser realizado ao término de cada viagem. Use `EncerrarMDFeCommand` com a chave e protocolo do manifesto autorizado, além do município e UF de encerramento.

```php theme={null}
<?php

use Suot\Fiscal\MDFe\Command\EncerrarMDFeCommand;
use Suot\Fiscal\MDFe\Handler\EncerrarMDFeHandler;
use Suot\Fiscal\ValueObjects\ChaveMDFe;
use Suot\Fiscal\ValueObjects\Protocolo;
use Suot\Fiscal\ValueObjects\Municipio;
use Suot\Fiscal\ValueObjects\Uf;

$encerramento = new EncerrarMDFeCommand(
    chave: ChaveMDFe::from('35250612345678000199580010000005011234567890'),
    protocolo: Protocolo::from('135250000012345'),
    dataEncerramento: new DateTimeImmutable('2025-06-15'),
    municipioEncerramento: Municipio::from(codigoIbge: '3304557'), // Rio de Janeiro - RJ
    ufEncerramento: Uf::RJ,
);

/** @var EncerrarMDFeHandler $handler */
$resultado = $handler->handle($encerramento);

if ($resultado->isSuccess()) {
    logger()->info('MDF-e encerrado com sucesso', [
        'protocolo_encerramento' => (string) $resultado->getProtocolo(),
    ]);
}
```

<Warning>
  Um MDF-e deve ser **encerrado** antes que um novo manifesto seja emitido para o mesmo veículo (placa) com cargas na mesma UF de início de percurso. A SEFAZ rejeita novos MDF-e enquanto o anterior permanecer aberto — código de rejeição 677.
</Warning>

## Próximos passos

<CardGroup cols={2}>
  <Card title="Resultados" icon="circle-check" href="/fiscal/resultados">
    Anatomia do padrão Result: todos os campos, status e metadados retornados nas operações de MDF-e.
  </Card>

  <Card title="Rejeições" icon="circle-xmark" href="/fiscal/rejeicoes">
    Códigos de rejeição da SEFAZ para MDF-e e estratégias de tratamento.
  </Card>
</CardGroup>
