cnab

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MPL-2.0 Imports: 10 Imported by: 0

Documentation

Overview

blocks/cnab/block.go

Package cnab provides a declarative CNAB 240 and CNAB 400 file reader block.

CNAB (Centro Nacional de Automação Bancária) is the Brazilian banking file interchange standard. The two variants differ only in line width and record structure:

CNAB 240 — 240 chars/line; Header de Arquivo, Header de Lote,
           Segmentos (A, B, C…), Trailer de Lote, Trailer de Arquivo.

CNAB 400 — 400 chars/line; Header, Detalhe, Trailer.

The block is configured by declaring field layouts that mirror the bank's technical specification document — field names, column positions (1-indexed), and data types. No parsing code needs to be written by the caller.

CNAB 240 example

reader := cnab.New("remessa-itau",
    cnab.WithFormat(cnab.Format240),

    cnab.WithFileHeader(
        cnab.NumericField("banco_codigo",   1,  3).Describe("Código do banco"),
        cnab.NumericField("lote",           4,  7),
        cnab.NumericField("tipo_registro",  8,  8),
        cnab.Field("nome_empresa",         73, 102),
        cnab.DateField("data_geracao",     144, 151),
        cnab.NumericField("sequencia",     158, 163),
    ),

    cnab.WithSegment("A",
        cnab.NumericField("banco_codigo_favorecido", 21, 23),
        cnab.NumericField("agencia",                 24, 28),
        cnab.Field("nome_favorecido",               43, 72),
        cnab.DecimalField("valor",                  120, 134, 2),
        cnab.DateField("data_pagamento",            145, 152),
    ),

    cnab.WithSegment("B",
        cnab.Field("logradouro",  19,  53),
        cnab.Field("cidade",      64,  83),
        cnab.Field("cep",         84,  91),
        cnab.Field("uf",          92,  93),
    ),

    cnab.WithFileTrailer(
        cnab.NumericField("total_lotes",    18, 23),
        cnab.NumericField("total_registros", 24, 29),
    ),
)

CNAB 400 example

reader := cnab.New("retorno-bradesco",
    cnab.WithFormat(cnab.Format400),

    cnab.WithHeader(
        cnab.NumericField("tipo_registro",  1,  1),
        cnab.NumericField("codigo_retorno", 2,  2),
        cnab.Field("nome_banco",           77, 94),
        cnab.DateField("data_geracao",     95, 100, "020106"),
    ),

    cnab.WithDetail(
        cnab.NumericField("tipo_registro",     1,   1),
        cnab.NumericField("codigo_ocorrencia", 109, 110),
        cnab.Field("nome_pagador",            218, 257),
        cnab.DecimalField("valor_titulo",      153, 165, 2),
        cnab.DateField("data_vencimento",      120, 125, "020106"),
        cnab.DateField("data_credito",         296, 301, "020106"),
    ),

    cnab.WithTrailer(
        cnab.NumericField("tipo_registro",      1,  1),
        cnab.NumericField("total_registros",   395, 400),
    ),
)

Parsing

// From a file path
result, err := reader.ParseFile(ctx, "/data/retorno.txt")

// From any io.Reader (uploaded file, S3 object, etc.)
result, err := reader.Parse(ctx, s3Body)

// Navigate results
fmt.Println(result.FileHeader["nome_empresa"])

for _, batch := range result.Batches {
    for _, seg := range batch.Segments {
        if seg.Code == "A" {
            fmt.Println(seg.Data["nome_favorecido"], seg.Data["valor"])
        }
    }
}

for _, detail := range result.Details {
    fmt.Println(detail["nome_pagador"], detail["valor_titulo"])
}

blocks/cnab/options.go

blocks/cnab/parser.go

blocks/cnab/types.go

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Batch

type Batch struct {
	// Header holds the parsed Lote Header (record type 1).
	Header Record
	// Segments is an ordered list of all detail segments in this batch.
	Segments []Segment
	// Trailer holds the parsed Lote Trailer (record type 5).
	Trailer Record
	// LineStart is the 1-indexed line number of the batch header in the file.
	LineStart int
}

Batch groups the header, detail segments and trailer of one CNAB 240 lote.

type Block

type Block struct {
	// contains filtered or unexported fields
}

Block is a CNAB file reader block. It holds the field layouts declared via options and exposes Parse / ParseFile methods that return a fully typed ParseResult.

func New

func New(name string, opts ...Option) *Block

New creates a new CNAB Block.

reader := cnab.New("remessa",
    cnab.WithFormat(cnab.Format240),
    cnab.WithFileHeader( ... ),
    cnab.WithSegment("A", ... ),
    cnab.WithFileTrailer( ... ),
)

func (*Block) Init

func (b *Block) Init(_ context.Context) error

Init implements core.Block. Validates the configuration.

func (*Block) Layout

func (b *Block) Layout() map[string]RecordLayout

Layout returns the configured field definitions for documentation or front-end form generation purposes. The returned map keys are record identifiers:

  • "file_header", "batch_header", "batch_trailer", "file_trailer" (CNAB 240)
  • "segment_A", "segment_B", … (CNAB 240 segments)
  • "header", "detail", "trailer" (CNAB 400)

func (*Block) Name

func (b *Block) Name() string

Name implements core.Block.

func (*Block) Parse

func (b *Block) Parse(_ context.Context, r io.Reader) (*ParseResult, error)

Parse reads CNAB data from r and returns the fully typed ParseResult. The caller is responsible for closing r after Parse returns.

// From an S3 object
obj, _ := assets.GetObject(ctx, "retorno.txt")
defer obj.Close()
result, err := cnabBlock.Parse(ctx, obj)

func (*Block) ParseFile

func (b *Block) ParseFile(ctx context.Context, path string) (*ParseResult, error)

ParseFile opens the file at path and parses it. The file is closed when parsing completes.

result, err := cnabBlock.ParseFile(ctx, "/var/data/remessa.txt")

func (*Block) Shutdown

func (b *Block) Shutdown(_ context.Context) error

Shutdown implements core.Block. No-op — CNAB block holds no open resources.

type FieldDef

type FieldDef struct {
	Name          string
	Start         int // 1-indexed, inclusive
	End           int // 1-indexed, inclusive
	Type          FieldType
	DecimalPlaces int    // Decimal fields only
	DateFormat    string // Date fields only; default "02012006" (DDMMYYYY)
	Description   string // Optional documentation
}

FieldDef describes one field inside a CNAB record.

Positions are 1-indexed to match bank documentation directly. A field spanning columns 1–3 means Start=1, End=3 (3 bytes).

func BoolField

func BoolField(name string, start, end int) FieldDef

BoolField creates a FieldDef with Boolean type.

cnab.BoolField("indicativo_pix", 198, 198)

func DateField

func DateField(name string, start, end int, format ...string) FieldDef

DateField creates a FieldDef with Date type. format follows Go's time.Parse convention; defaults to "02012006" (DDMMYYYY).

cnab.DateField("data_pagamento", 94, 101)            // DDMMYYYY
cnab.DateField("data_vencimento", 94, 101, "020106") // DDMMYY

func DecimalField

func DecimalField(name string, start, end, decimalPlaces int) FieldDef

DecimalField creates a FieldDef with Decimal type and the given decimal places.

cnab.DecimalField("valor", 153, 167, 2)  // 15 digits, 2 decimal places

func Field

func Field(name string, start, end int) FieldDef

Field creates a FieldDef with Alpha type. This is the most common field type.

cnab.Field("nome_empresa", 73, 102)

func NumericField

func NumericField(name string, start, end int) FieldDef

NumericField creates a FieldDef with Numeric type.

cnab.NumericField("numero_documento", 74, 93)

func (FieldDef) Describe

func (f FieldDef) Describe(description string) FieldDef

Describe adds a human-readable description to a FieldDef. Useful for documentation and for rendering forms in the front-end.

cnab.Field("banco_codigo", 1, 3).Describe("Código do banco compensação")

type FieldType

type FieldType int

FieldType determines how raw bytes are converted to a Go value.

const (
	// Alpha is a left-aligned, space-padded string field.
	Alpha FieldType = iota

	// Numeric is a right-aligned, zero-padded integer field.
	Numeric

	// Decimal is a numeric field with an implicit decimal separator.
	// Use WithDecimalPlaces to set how many digits are fractional.
	// E.g. "000001234" with 2 decimal places → 12.34
	Decimal

	// Date parses the field as a date. Default format is DDMMYYYY.
	// Use WithDateFormat to override.
	Date

	// Boolean treats "1" or "S" as true, anything else as false.
	Boolean
)

type Format

type Format int

Format identifies the CNAB line width standard.

const (
	// Format240 is the CNAB 240 standard (FEBRABAN) — 240 characters per line.
	// Structure: FileHeader | BatchHeader | Segments (A, B, C…) | BatchTrailer | FileTrailer
	Format240 Format = 240

	// Format400 is the CNAB 400 standard — 400 characters per line.
	// Structure: FileHeader | Details | FileTrailer
	Format400 Format = 400
)

type Option

type Option func(*blockConfig)

Option configures a CNAB Block.

func WithBatchHeader

func WithBatchHeader(fields ...FieldDef) Option

WithBatchHeader defines the fields for the CNAB 240 lote header (registro tipo 1).

func WithBatchTrailer

func WithBatchTrailer(fields ...FieldDef) Option

WithBatchTrailer defines the fields for the CNAB 240 lote trailer (registro tipo 5).

func WithDateLocation

func WithDateLocation(loc *time.Location) Option

WithDateLocation sets the time.Location used when parsing Date fields. Defaults to time.UTC.

func WithDetail

func WithDetail(fields ...FieldDef) Option

WithDetail defines the fields for CNAB 400 detail records. Detail records are identified by record type "1" in column 1.

cnab.WithDetail(
    cnab.NumericField("tipo_registro",      1,   1),
    cnab.Field("nome_pagador",             218, 257),
    cnab.DecimalField("valor_titulo",       153, 165, 2),
    cnab.DateField("data_vencimento",       120, 125, "020106"),
    cnab.NumericField("codigo_ocorrencia",  109, 110),
)

func WithFileHeader

func WithFileHeader(fields ...FieldDef) Option

WithFileHeader defines the fields for the CNAB 240 file header (registro tipo 0).

cnab.WithFileHeader(
    cnab.NumericField("banco_codigo",    1,  3).Describe("Código do banco"),
    cnab.NumericField("lote",            4,  7).Describe("Lote de serviço"),
    cnab.NumericField("tipo_registro",   8,  8).Describe("Tipo de registro"),
    cnab.Field("nome_empresa",          73, 102).Describe("Nome da empresa"),
    cnab.DateField("data_geracao",      144, 151).Describe("Data de geração"),
)

func WithFileTrailer

func WithFileTrailer(fields ...FieldDef) Option

WithFileTrailer defines the fields for the CNAB 240 file trailer (registro tipo 9).

func WithFormat

func WithFormat(f Format) Option

WithFormat sets the CNAB line width. Required. Use Format240 for FEBRABAN CNAB 240 or Format400 for CNAB 400.

func WithHeader

func WithHeader(fields ...FieldDef) Option

WithHeader defines the fields for the CNAB 400 file header. The header record is identified by record type "0" in column 1.

cnab.WithHeader(
    cnab.NumericField("tipo_registro", 1, 1),
    cnab.NumericField("codigo_retorno", 2, 2),
    cnab.Field("nome_banco", 77, 94),
    cnab.DateField("data_geracao", 95, 100, "020106"), // DDMMYY
)

func WithSegment

func WithSegment(code string, fields ...FieldDef) Option

WithSegment defines the fields for a CNAB 240 detalhe segment identified by its code letter (A, B, C, J, O, N, …). The segment code is read from column 14 of each detail line.

cnab.WithSegment("A",
    cnab.NumericField("banco_codigo_favorecido", 21, 23),
    cnab.NumericField("agencia",                 24, 28),
    cnab.Field("nome_favorecido",               43, 72),
    cnab.DecimalField("valor",                  120, 134, 2),
)

func WithSkipUnknownSegments

func WithSkipUnknownSegments() Option

WithSkipUnknownSegments instructs the parser to silently ignore CNAB 240 segments whose code is not registered via WithSegment, instead of recording a ParseError. Useful when you only care about a subset of segments.

func WithTrailer

func WithTrailer(fields ...FieldDef) Option

WithTrailer defines the fields for the CNAB 400 file trailer. The trailer record is identified by record type "9" in column 1.

type ParseError

type ParseError struct {
	Line    int
	Message string
}

ParseError describes a non-fatal error on a specific line.

type ParseResult

type ParseResult struct {
	// Format is the detected (or configured) CNAB format.
	Format Format
	// FileHeader holds the parsed file header record (record type 0 for CNAB 240).
	FileHeader Record
	// Batches holds the parsed batches (CNAB 240 only).
	Batches []Batch
	// Details holds the parsed detail records (CNAB 400 only).
	Details []Record
	// FileTrailer holds the parsed file trailer record (record type 9).
	FileTrailer Record
	// TotalLines is the number of lines read from the file.
	TotalLines int
	// ParseErrors contains non-fatal per-line errors encountered during parsing.
	ParseErrors []ParseError
}

ParseResult is the top-level result of parsing a CNAB file.

type Record

type Record map[string]any

Record is a single parsed CNAB record: a map of field name → Go value. Values are typed according to their FieldDef:

  • Alpha → string
  • Numeric → int64
  • Decimal → float64
  • Date → time.Time
  • Boolean → bool

type RecordLayout

type RecordLayout struct {
	Fields []FieldDef
}

RecordLayout holds the field definitions for one record type.

type Segment

type Segment struct {
	// Code is the segment code letter (A, B, C, J, O, …).
	Code string
	// Data holds the parsed fields of this segment.
	Data Record
	// Line is the 1-indexed line number in the file.
	Line int
}

Segment is a single CNAB 240 detalhe record (record type 3).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL