Saltar al contenido principal
Esta guía te acompaña a través de la estructura y lógica utilizada para generar los informes CADOC 4010 y CADOC 4016 en XML.
  Estos informes siguen el estándar COSIF y deben coincidir con la estructura XML definida por BACEN. Puedes adaptar la lógica a tu propio modelo de datos, pero el formato XML debe ser respetado.

¿Qué son CADOC 4010 y 4016?

El 4010 y el 4016 son informes de Balance Analítico utilizados para presentar informes financieros al BACEN (Banco Central de Brasil). Estos incluyen:
  • 4010: Detalla saldos mensuales o trimestrales de todas las cuentas hasta el nivel 3 del balance analítico, siguiendo el COSIF (Estándar de Contabilidad para Instituciones Reguladas por el Banco Central de Brasil).
  • 4016: Proporciona información de balance analítico de forma semestral, específicamente para los meses de junio y diciembre.
Utilizarás Reporter para generar estos informes en XML, usando tus propios datos y aplicando la lógica que se ajusta al esquema COSIF.

Estructura CADOC

Formato base

El informe CADOC debe ser un archivo XML y debe seguir la estructura definida por BACEN:
<?xml version="1.0" encoding="UTF-8"?>
<documento codigoDocumento="4010" cnpj="99999999999999"
dataBase="AAAA-MM" tipoRemessa="I">
<contas>
<conta codigoConta="1000000009" saldo="99.99" />
<conta codigoConta="1100000002" saldo="99.99" />
</contas>
</documento>
Campos obligatorios Estos campos son requeridos y deben incluirse: <?xml version="1.0" encoding="UTF-8"?> Siempre inicia el archivo. Define la versión y la codificación del XML para que el sistema sepa cómo leer el contenido. Etiqueta <documento> Envuelve toda la estructura CADOC e incluye:
  • codigoDocumento: Identifica el tipo de informe:
    • "4010" para informes de balance general (activos, pasivos y patrimonio).
    • "4016" para informes de estado de resultados (ingresos y gastos).
  • cnpj: Identifica la institución financiera.
    • Usa solo los primeros 8 dígitos del CNPJ (solo números, sin puntuación).
  • dataBase: Período de referencia, en el formato "YYYY-MM".
    • Ejemplo: "2025-01" significa enero de 2025.
  • tipoRemessa: Define el tipo de envío:
    • "I" (Inclusión): Primer envío de ese período.
    • "S" (Sustitución): Actualización o corrección de datos previamente aceptados.
Si tu primer envío fue rechazado por errores, aún debes usar "I" en el siguiente intento. Solo usa "S" para reemplazar datos previamente aprobados.
Etiqueta <contas> Agrupa todas las cuentas del período de referencia. Etiqueta <conta>
  • codigoConta: Código de la cuenta, siguiendo el formato COSIF.
  • saldo: Saldo de la cuenta en formato decimal (dos decimales).

Usando Reporter

Cada organización puede adaptar la plantilla a su propio modelo de datos, solo reemplaza los nombres de los campos (como midaz_onboarding.account, midaz_transaction.balance, etc.) para que coincidan con tu estructura. La lógica permanece igual; solo cambian las rutas y nombres de los campos. Aquí tienes un ejemplo funcional que puedes usar como punto de partida:
<documento codigoDocumento="4010"
           cnpj={{ midaz_onboarding.organization.0.legal_document|slice:':8' }}
           dataBase={% date_time "YYYY/MM" %}
           tipoRemessa="I">
  <contas>
    {%- for account in midaz_onboarding.account %}
      {%- with balance = filter(midaz_transaction.balance, "account_id", account.id)[0] %}
        {%- set saldoDia = balance.available %}
        <conta codigoConta="{{ account.id|slice:':10' }}" saldo="{{ saldoDia|floatformat:2 }}"/>
      {% endwith %}
    {% endfor %}
  </contas>
</documento>

Desglose del código

<documento ...>

<documento codigoDocumento="4010"
          cnpj={{ midaz_onboarding.organization.0.legal_document|slice:':8' }}
          dataBase={% date_time "YYYY/MM" %}
          tipoRemessa="I">
Define el documento principal y los metadatos requeridos. codigoDocumento="4010" Indica al BACEN qué informe estás enviando; ya sea 4010 o 4016. cnpj={{ midaz_onboarding.organization.0.legal_document|slice:':8' }} Obtiene los primeros 8 dígitos del CNPJ de la organización.
  • midaz_onboarding.organization.0.legal_document: Obtiene el CNPJ de la primera organización en la lista.
  • slice:':8': Lo recorta a los primeros 8 dígitos.
dataBase={% date_time "YYYY/MM" %} Define dinámicamente el período de referencia.
  • {% date_time "YYYY/MM" %}: Imprime el año y mes actual en el momento de la generación.
tipoRemessa="I" Indica si es un envío inicial (I) o una corrección (S).

Información de cuentas

    {%- for account in midaz_onboarding.account %}
      {%- with balance = filter(midaz_transaction.balance, "account_id", account.id)[0] %}
        {%- set saldoDia = balance.available %}
{% for account in midaz_onboarding.account %} Itera sobre todas las cuentas asociadas a la lista midaz_onboarding.account.
  • En cada iteración, crea un nuevo contexto donde account se refiere a un elemento específico de esa lista.
{% with balance = filter(midaz_transaction.balance, "account_id", account.id)[0] %} Dentro del bucle:
  • Filtra midaz_transaction.balance por account_id para que coincida con el ID de la cuenta actual.
  • [0]: Obtiene el primer saldo coincidente (suponiendo que solo haya uno por cuenta).
  • Lo guarda como una variable temporal balance.
{%- set saldoDia = balance.available %}
  • Obtiene el saldo y lo almacena como saldoDia.

Generando cada etiqueta <conta />

<conta codigoConta="{{ account.id|slice:':10' }}" saldo="{{ saldoDia|floatformat:2 }}"/>
Crea un elemento <conta> por cada cuenta, con dos atributos:
  • codigoConta="{{ account.id|slice:':10' }}": Usa los primeros 10 caracteres del ID de la cuenta; útil si el ID completo es demasiado largo o si la integración requiere una longitud fija.
  • saldo="{{ saldoDia|floatformat:2 }}": Da formato al saldo con exactamente dos decimales.
Aplica siempre el escalado antes de renderizar valores numéricos para garantizar la precisión. Usa floatformat:2 para forzar dos decimales.

Cierre de la plantilla

  </contas>
</documento>
Finaliza la lista de cuentas y la estructura del documento.

Ejemplo renderizado

Así podría verse el XML final después de generarse:
<?xml version="1.0" encoding="UTF-8"?>
<documento codigoDocumento="4010" cnpj= "99999999999999" dataBase="2025/06" tipoRemessa="I" >
    <contas>
        <conta codigoConta="0196d9758" saldo= "-2500000.00" />
        <conta codigoConta="0196d9720" saldo= "499950.00" />
        <conta codigoConta="0196d9761" saldo= "500050.00" />
        <conta codigoConta="0196d9779" saldo= "500000.00" />
        <conta codigoConta="0196d9797" saldo= "500000.00" />
        <conta codigoConta="0196d9725" saldo= "500000.00" />
        <conta codigoConta="019784537" saldo= "0" />
        <conta codigoConta="019784572" saldo= "0" />
        <conta codigoConta="019784580" saldo= "0" />
        <conta codigoConta="019784535" saldo= "0" />
        <conta codigoConta="019784586" saldo= "0" />
    </contas>
</documento>

Personalizando la plantilla

Puedes ajustar los nombres de los campos (como midaz_onboarding.account) para que coincidan con tu propio modelo de datos. Solo asegúrate de preservar la estructura XML, ya que eso es lo que garantiza que el BACEN acepte tu archivo.
Siempre valida el XML generado contra el esquema del BACEN antes de enviarlo. La estructura por sí sola no es suficiente: los datos deben reflejar el libro mayor real de tu institución.
I