Skip to content

Commit

Permalink
Add initial Brazil NFSe addon
Browse files Browse the repository at this point in the history
  • Loading branch information
cavalle committed Oct 25, 2024
1 parent 834477c commit 5a9ade0
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to GOBL will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). See also the [GOBL versions](https://docs.gobl.org/overview/versions) documentation site for more details.

## [Unreleased]

### Added

- `br-nfse-v1`: added initial Brazil NFS-e addon

## [v0.203.0]

### Added
Expand Down
1 change: 1 addition & 0 deletions addons/addons.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package addons

import (
// Import all the addons to ensure they're ready to use.
_ "github.com/invopop/gobl/addons/br/nfse"
_ "github.com/invopop/gobl/addons/co/dian"
_ "github.com/invopop/gobl/addons/es/facturae"
_ "github.com/invopop/gobl/addons/es/tbai"
Expand Down
27 changes: 27 additions & 0 deletions addons/br/nfse/extensions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nfse

import (
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/i18n"
"github.com/invopop/gobl/pkg/here"
)

const (
ExtKeyService = "br-nfse-service"

Check failure on line 10 in addons/br/nfse/extensions.go

View workflow job for this annotation

GitHub Actions / golangci-lint

exported: exported const ExtKeyService should have comment (or a comment on this block) or be unexported (revive)
)

var extensions = []*cbc.KeyDefinition{
{
Key: ExtKeyService,
Name: i18n.String{
i18n.EN: "Service Code",
i18n.PT: "Código Item Lista Serviço",
},
Desc: i18n.String{
i18n.EN: here.Doc(`
The service code as defined by the municipality. Typically, one of the codes listed
in the Lei Complementar 116/2003, but municipalities can make their own changes.
`),
},
},
}
21 changes: 21 additions & 0 deletions addons/br/nfse/item.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package nfse

import (
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/tax"
"github.com/invopop/validation"
)

func validateItem(value any) error {
item, _ := value.(*org.Item)
if item == nil {
return nil
}

Check warning on line 13 in addons/br/nfse/item.go

View check run for this annotation

Codecov / codecov/patch

addons/br/nfse/item.go#L12-L13

Added lines #L12 - L13 were not covered by tests

return validation.ValidateStruct(item,
validation.Field(&item.Ext,
tax.ExtensionsRequires(ExtKeyService),
validation.Skip,
),
)
}
62 changes: 62 additions & 0 deletions addons/br/nfse/item_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package nfse_test

import (
"testing"

"github.com/invopop/gobl/addons/br/nfse"
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/tax"
"github.com/stretchr/testify/assert"
)

func TestItemValidation(t *testing.T) {
tests := []struct {
name string
item *org.Item
err string
}{
{
name: "valid item",
item: &org.Item{
Ext: tax.Extensions{
nfse.ExtKeyService: "12345678",
},
},
},
{
name: "missing extensions",
item: &org.Item{},
err: "ext: (br-nfse-service: required.)",
},
{
name: "empty extensions",
item: &org.Item{
Ext: tax.Extensions{},
},
err: "ext: (br-nfse-service: required.)",
},
{
name: "missing extension",
item: &org.Item{
Ext: tax.Extensions{
"random": "12345678",
},
},
err: "ext: (br-nfse-service: required.).",
},
}

addon := tax.AddonForKey(nfse.V1)
for _, ts := range tests {
t.Run(ts.name, func(t *testing.T) {
err := addon.Validator(ts.item)
if ts.err == "" {
assert.NoError(t, err)
} else {
if assert.Error(t, err) {
assert.Contains(t, err.Error(), ts.err)
}
}
})
}
}
18 changes: 18 additions & 0 deletions addons/br/nfse/line.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nfse

import (
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/regimes/br"
"github.com/invopop/validation"
)

func validateLine(value any) error {
line, _ := value.(*bill.Line)
if line == nil {
return nil
}

Check warning on line 13 in addons/br/nfse/line.go

View check run for this annotation

Codecov / codecov/patch

addons/br/nfse/line.go#L12-L13

Added lines #L12 - L13 were not covered by tests

return validation.Validate(line,
bill.RequireLineTaxCategory(br.TaxCategoryISS),
)
}
67 changes: 67 additions & 0 deletions addons/br/nfse/line_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package nfse_test

import (
"testing"

"github.com/invopop/gobl/addons/br/nfse"
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/regimes/br"
"github.com/invopop/gobl/tax"
"github.com/stretchr/testify/assert"
)

func TestLineValidation(t *testing.T) {
tests := []struct {
name string
line *bill.Line
err string
}{
{
name: "valid line",
line: &bill.Line{
Taxes: tax.Set{
{
Category: br.TaxCategoryISS,
},
},
},
},
{
name: "missing taxes",
line: &bill.Line{},
err: "taxes: missing category ISS.",
},
{
name: "empty taxes",
line: &bill.Line{
Taxes: tax.Set{},
},
err: "taxes: missing category ISS.",
},
{
name: "missing ISS tax",
line: &bill.Line{
Taxes: tax.Set{
{
Category: br.TaxCategoryPIS,
},
},
},
err: "taxes: missing category ISS.",
},
}

addon := tax.AddonForKey(nfse.V1)
for _, ts := range tests {
t.Run(ts.name, func(t *testing.T) {
err := addon.Validator(ts.line)
if ts.err == "" {
assert.NoError(t, err)
} else {
if assert.Error(t, err) {
assert.Contains(t, err.Error(), ts.err)
}
}
})
}
}
41 changes: 41 additions & 0 deletions addons/br/nfse/nfse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Package NFS-e handles extensions and validation rules to issue NFS-e in

Check failure on line 1 in addons/br/nfse/nfse.go

View workflow job for this annotation

GitHub Actions / golangci-lint

package-comments: package comment should be of the form "Package nfse ..." (revive)
// Brazil.
package nfse

import (
"github.com/invopop/gobl/bill"
"github.com/invopop/gobl/cbc"
"github.com/invopop/gobl/i18n"
"github.com/invopop/gobl/org"
"github.com/invopop/gobl/tax"
)

const (
// V1 identifies the NFS-e addon version
V1 cbc.Key = "br-nfse-v1"
)

func init() {
tax.RegisterAddonDef(newAddon())
}

func newAddon() *tax.AddonDef {
return &tax.AddonDef{
Key: V1,
Name: i18n.String{
i18n.EN: "Brazil NFS-e 1.X",
},
Extensions: extensions,
Validator: validate,
}
}

func validate(doc any) error {
switch obj := doc.(type) {
case *bill.Line:
return validateLine(obj)
case *org.Item:
return validateItem(obj)
}
return nil

Check warning on line 40 in addons/br/nfse/nfse.go

View check run for this annotation

Codecov / codecov/patch

addons/br/nfse/nfse.go#L40

Added line #L40 was not covered by tests
}

0 comments on commit 5a9ade0

Please sign in to comment.