gocnab

package module
v0.0.0-...-8805e0f Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2023 License: MIT Imports: 7 Imported by: 0

README

GoDoc license Build Status Go Report Card codebeat badge

toglacier

gocnab

gocnab implements encoding and decoding of CNAB (Centro Nacional de Automação Bancária) data as defined by FEBRABAN.

When marshaling it is possible to inform a struct, that will generate 1 CNAB line, or a slice of struct to generate multiple CNAB lines. On unmarshal a pointer to a struct, a pointer to a slice of struct or a mapper (map[string]interface{} for a full CNAB file) should be used.

The library use struct tags to define the position of the field in the CNAB content [begin,end). It supports the basic attribute types string (uppercase and left align), bool (represented by 1 or 0), int, int8, int16, int32, int64, uint, uint8, uint16, uint23, uint64, float32 and float64 (decimal separator removed). And for custom types it is possible to implement gocnab.Marshaler, gocnab.Unmarshaler, encoding.TextMarshaler and encoding.TextUnmarshaler to make full use of this library.

Install

go get -u github.com/ammeg/gocnab

Usage

For working with only a single line of the CNAB file:

package main

import "github.com/ammeg/gocnab"

type example struct {
	FieldA int     `cnab:"0,20"`
	FieldB string  `cnab:"20,50"`
	FieldC float64 `cnab:"50,60"`
	FieldD uint    `cnab:"60,70"`
	FieldE bool    `cnab:"70,71"`
}

func main() {
	e1 := example{
		FieldA: 123,
		FieldB: "THIS IS A TEST",
		FieldC: 50.30,
		FieldD: 445,
		FieldE: true,
	}

	data, err := gocnab.Marshal400(e1)
	if err != nil {
		println(err)
		return
	}

	var e2 example
	if err = gocnab.Unmarshal(data, &e2); err != nil {
		println(err)
		return
	}

	println(e1 == e2)
}

And for the whole CNAB file:

package main

import "github.com/ammeg/gocnab"

type header struct {
	Identifier string `cnab:"0,1"`
	HeaderA    int    `cnab:"1,5"`
}

type content struct {
	Identifier string  `cnab:"0,1"`
	FieldA     int     `cnab:"1,20"`
	FieldB     string  `cnab:"20,50"`
	FieldC     float64 `cnab:"50,60"`
	FieldD     uint    `cnab:"60,70"`
	FieldE     bool    `cnab:"70,71"`
}

type footer struct {
	Identifier string `cnab:"0,1"`
	FooterA    string `cnab:"5,30"`
}

func main() {
	h1 := header{
		Identifier: "0",
		HeaderA:    2,
	}

	c1 := []content{
		{
			Identifier: "1",
			FieldA:     123,
			FieldB:     "THIS IS A TEXT",
			FieldC:     50.30,
			FieldD:     445,
			FieldE:     true,
		},
		{
			Identifier: "1",
			FieldA:     321,
			FieldB:     "THIS IS ANOTHER TEXT",
			FieldC:     30.50,
			FieldD:     544,
			FieldE:     false,
		},
	}

	f1 := footer{
		Identifier: "2",
		FooterA:    "FINAL TEXT",
	}

	data, err := gocnab.Marshal400(h1, c1, f1)
	if err != nil {
		println(err)
		return
	}

	var h2 header
	var c2 []content
	var f2 footer

	if err = gocnab.Unmarshal(data, map[string]interface{}{
		"0": &h2,
		"1": &c2,
		"2": &f2,
	}); err != nil {
		println(err)
		return
	}

	println(h1 == h2)
	for i := range c1 {
		println(c1[i] == c2[i])
	}
	println(f1 == f2)
}

Documentation

Overview

Package gocnab implements encoding and decoding of CNAB (Centro Nacional de Automação Bancária) as defined by FEBRABAN (Federação Brasileira de Bancos).

Index

Examples

Constants

View Source
const FinalControlCharacter = "\x1A"

FinalControlCharacter defines the control character of the last registry entry. It should be the hex encoded 1A.

View Source
const LineBreak = "\r\n"

LineBreak defines the control characters at the end of each registry entry. It should be the hex encoded 0D0A except for the last one.

Variables

View Source
var (
	// ErrUnsupportedType raised when trying to marshal something different from a
	// struct or a slice.
	ErrUnsupportedType = errors.New("gocnab: unsupported type")

	// ErrInvalidFieldTagFormat CNAB field tag doesn't follow the expected format.
	ErrInvalidFieldTagFormat = errors.New("invalid field tag format")

	// ErrInvalidFieldTagBeginRange begin range isn't a valid number in the CNAB
	// tag.
	ErrInvalidFieldTagBeginRange = errors.New("invalid begin range in cnab tag")

	// ErrInvalidFieldTagEndRange end range isn't a valid number in the CNAB tag.
	ErrInvalidFieldTagEndRange = errors.New("invalid end range in cnab tag")

	// ErrInvalidFieldTagRange ranges don't have consistency with the desired
	// encoding in the CNAB tag.
	ErrInvalidFieldTagRange = errors.New("invalid range in cnab tag")
)

Functions

func Marshal150

func Marshal150(vs ...interface{}) ([]byte, error)

func Marshal240

func Marshal240(vs ...interface{}) ([]byte, error)

Marshal240 returns the CNAB 240 encoding of vs. The accepted types are struct and slice of struct, where only the exported struct fields with the tag "cnab" are going to be used. Invalid cnab tag ranges will generate errors.

The following struct field types are supported: string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint23, uint64, float32, float64, gocnab.Marshaler and encoding.TextMarshaler. Where string are transformed to uppercase and are left aligned in the CNAB space, booleans are represented as 1 or 0, numbers are right aligned with zeros and float decimal separators are removed.

When only one parameter is given the generated CNAB line will only have break line symbols if the input is a slice of struct. When using multiple parameters the library determinate that you are trying to build the full CNAB file, so it add the breaking lines and the final control symbol.

Example
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	e := struct {
		FieldA int     `cnab:"0,20"`
		FieldB string  `cnab:"20,50"`
		FieldC float64 `cnab:"50,60"`
		FieldD uint    `cnab:"60,70"`
		FieldE bool    `cnab:"70,71"`
	}{
		FieldA: 123,
		FieldB: "This is a text",
		FieldC: 50.30,
		FieldD: 445,
		FieldE: true,
	}

	data, _ := gocnab.Marshal240(e)

	fmt.Println(string(data))
}
Output:

00000000000000000123THIS IS A TEXT                000000503000000004451
Example (FullFile)
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	header := struct {
		Identifier string `cnab:"0,1"`
		HeaderA    int    `cnab:"1,5"`
	}{
		HeaderA: 2,
	}

	content := []struct {
		Identifier string  `cnab:"0,1"`
		FieldA     int     `cnab:"1,20"`
		FieldB     string  `cnab:"20,50"`
		FieldC     float64 `cnab:"50,60"`
		FieldD     uint    `cnab:"60,70"`
		FieldE     bool    `cnab:"70,71"`
	}{
		{
			FieldA: 123,
			FieldB: "This is a text",
			FieldC: 50.30,
			FieldD: 445,
			FieldE: true,
		},
		{
			FieldA: 321,
			FieldB: "This is another text",
			FieldC: 30.50,
			FieldD: 544,
			FieldE: false,
		},
	}

	footer := struct {
		Identifier string `cnab:"0,1"`
		FooterA    string `cnab:"5,30"`
	}{
		FooterA: "Final text",
	}

	data, _ := gocnab.Marshal240(header, content, footer)

	fmt.Println(string(data))
}
Output:

func Marshal400

func Marshal400(vs ...interface{}) ([]byte, error)

Marshal400 returns the CNAB 400 encoding of vs. The accepted types are struct and slice of struct, where only the exported struct fields with the tag "cnab" are going to be used. Invalid cnab tag ranges will generate errors.

The following struct field types are supported: string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint23, uint64, float32, float64, gocnab.Marshaler and encoding.TextMarshaler. Where string are transformed to uppercase and are left aligned in the CNAB space, booleans are represented as 1 or 0, numbers are right aligned with zeros and float decimal separators are removed.

When only one parameter is given the generated CNAB line will only have break line symbols if the input is a slice of struct. When using multiple parameters the library determinate that you are trying to build the full CNAB file, so it add the breaking lines and the final control symbol.

Example
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	e := struct {
		FieldA int     `cnab:"0,20"`
		FieldB string  `cnab:"20,50"`
		FieldC float64 `cnab:"50,60"`
		FieldD uint    `cnab:"60,70"`
		FieldE bool    `cnab:"70,71"`
	}{
		FieldA: 123,
		FieldB: "This is a text",
		FieldC: 50.30,
		FieldD: 445,
		FieldE: true,
	}

	data, _ := gocnab.Marshal400(e)

	fmt.Println(string(data))
}
Output:

00000000000000000123THIS IS A TEXT                000000503000000004451
Example (FullFile)
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	header := struct {
		Identifier string `cnab:"0,1"`
		HeaderA    int    `cnab:"1,5"`
	}{
		HeaderA: 2,
	}

	content := []struct {
		Identifier string  `cnab:"0,1"`
		FieldA     int     `cnab:"1,20"`
		FieldB     string  `cnab:"20,50"`
		FieldC     float64 `cnab:"50,60"`
		FieldD     uint    `cnab:"60,70"`
		FieldE     bool    `cnab:"70,71"`
	}{
		{
			FieldA: 123,
			FieldB: "This is a text",
			FieldC: 50.30,
			FieldD: 445,
			FieldE: true,
		},
		{
			FieldA: 321,
			FieldB: "This is another text",
			FieldC: 30.50,
			FieldD: 544,
			FieldE: false,
		},
	}

	footer := struct {
		Identifier string `cnab:"0,1"`
		FooterA    string `cnab:"5,30"`
	}{
		FooterA: "Final text",
	}

	data, _ := gocnab.Marshal400(header, content, footer)

	fmt.Println(string(data))
}
Output:

func Marshal500

func Marshal500(vs ...interface{}) ([]byte, error)

Marshal500 returns the CNAB 500 encoding of vs. The accepted types are struct and slice of struct, where only the exported struct fields with the tag "cnab" are going to be used. Invalid cnab tag ranges will generate errors.

The following struct field types are supported: string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint23, uint64, float32, float64, gocnab.Marshaler and encoding.TextMarshaler. Where string are transformed to uppercase and are left aligned in the CNAB space, booleans are represented as 1 or 0, numbers are right aligned with zeros and float decimal separators are removed.

When only one parameter is given the generated CNAB line will only have break line symbols if the input is a slice of struct. When using multiple parameters the library determinate that you are trying to build the full CNAB file, so it add the breaking lines and the final control symbol.

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal parses the CNAB-encoded data and stores the result in the value pointed to by v. Accepted types of v are: *struct, *[]struct or map[string]interface{}.

The following struct field types are supported: string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint23, uint64, float32, float64, gocnab.Unmarshaler and encoding.TextUnmarshaler.

When parsing a full CNAB file we recommend using the map type (mapper) to fill different lines into the correct types. Usually the CNAB prefix determinate the type used, so the mapper key will be the prefix, and the mapper value is the pointer to the type that you're filling. For example, if we have a CNAB file where the starter character determinate the type, and for "0" is header, "1" is the content line (can repeat many times) and "2" is the footer, we could have the following code to unmarshal:

header := struct{ A int `cnab:1,10` }{}
content := []struct{ B string `cnab:1,10` }{}
footer := struct{ C bool `cnab:1,2` }{}

cnab.Unmarshal(data, map[string]interface{}{
  "0": &header,
  "1": &content,
  "2": &footer,
})
Example
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	var e struct {
		FieldA int     `cnab:"0,20"`
		FieldB string  `cnab:"20,50"`
		FieldC float64 `cnab:"50,60"`
		FieldD uint    `cnab:"60,70"`
		FieldE bool    `cnab:"70,71"`
	}

	data := []byte("00000000000000000123THIS IS A TEXT                000000503000000004451")
	if err := gocnab.Unmarshal(data, &e); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("%v\n", e)
}
Output:

{123 THIS IS A TEXT 50.3 445 true}
Example (FullFile)
package main

import (
	"fmt"

	"github.com/ammeg/gocnab"
)

func main() {
	header := struct {
		Identifier int `cnab:"0,1"`
		HeaderA    int `cnab:"1,5"`
	}{}

	content := []struct {
		Identifier int     `cnab:"0,1"`
		FieldA     int     `cnab:"1,20"`
		FieldB     string  `cnab:"20,50"`
		FieldC     float64 `cnab:"50,60"`
		FieldD     uint    `cnab:"60,70"`
		FieldE     bool    `cnab:"70,71"`
	}{}

	footer := struct {
		Identifier int    `cnab:"0,1"`
		FooterA    string `cnab:"5,30"`
	}{}

	data := []byte("00005" + gocnab.LineBreak +
		"10000000000000000123THIS IS A TEXT 1              000000503000000004451" + gocnab.LineBreak +
		"10000000000000000321THIS IS A TEXT 2              000000305000000005440" + gocnab.LineBreak +
		"2    THIS IS THE FOOTER            " + gocnab.FinalControlCharacter)

	err := gocnab.Unmarshal(data, map[string]interface{}{
		"0": &header,
		"1": &content,
		"2": &footer,
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("%v\n%v\n%v\n", header, content, footer)
}
Output:

{0 5}
[{1 123 THIS IS A TEXT 1 50.3 445 true} {1 321 THIS IS A TEXT 2 30.5 544 false}]
{2 THIS IS THE FOOTER}

Types

type FieldError

type FieldError struct {
	Field string
	Err   error
}

FieldError problem detected in a field tag containing CNAB options or when marshalling the field itself.

func (FieldError) Error

func (f FieldError) Error() string

Error return a human readable representation of the field error.

type MarshalOptionFunc

type MarshalOptionFunc func(*MarshalOptions)

MarshalOptionFunc helper type alias to handle options.

func WithFinalControlCharacter

func WithFinalControlCharacter(enabled bool) MarshalOptionFunc

WithFinalControlCharacter allows to enable or disable the final control character. The first version of this library was designed to build valid CNAB files for Bradesco bank, and one of Bradesco's requirements was to contain the final control hexadecimal character 1A. But as this library started being used by other integrations, the final control character became an issue, as it doesn't comply with other specifications. By default, the final control character is added to keep backward compatibility.

type MarshalOptions

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

MarshalOptions contains available options when marshaling. The properties can be modified using auxiliary functions directly into the marshal calls.

Example:

Marshal240(myCNABType, gocnab.WithFinalControlCharacter(false))

type Marshaler

type Marshaler interface {
	MarshalCNAB() ([]byte, error)
}

Marshaler is the interface implemented by types that can marshal themselves into valid string representation.

type UnmarshalFieldError

type UnmarshalFieldError struct {
	Field string
	Data  []byte
	Err   error
}

UnmarshalFieldError stores the error that occurred while decoding the CNAB data into a field.

func (UnmarshalFieldError) Error

func (u UnmarshalFieldError) Error() string

Error return a human readable representation of the unmarshal error.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalCNAB([]byte) error
}

Unmarshaler is the interface implemented by types that can unmarshal a string representation description of themselves. UnmarshalCNAB must copy the CNAB data if it wishes to retain the data after returning.

Jump to

Keyboard shortcuts

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