-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
flavioltonon
committed
Apr 6, 2019
1 parent
f6583ec
commit ca6965b
Showing
2 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package brazil | ||
|
||
import ( | ||
"math/rand" | ||
"regexp" | ||
"strconv" | ||
"time" | ||
) | ||
|
||
// CNPJ struct | ||
type cnpj struct { | ||
number cnpjNumber | ||
valid bool | ||
} | ||
|
||
func (c cnpj) Number(mask bool) string { | ||
if c.valid && mask { | ||
return string(c.number[:2]) + | ||
"." + | ||
string(c.number[2:5]) + | ||
"." + | ||
string(c.number[5:8]) + | ||
"/" + | ||
string(c.number[8:12]) + | ||
"-" + | ||
string(c.number[12:]) | ||
} | ||
return string(c.number) | ||
} | ||
|
||
func ParseCNPJ(number string) (cnpj, error) { | ||
number = regexp.MustCompile(`[^0-9]`).ReplaceAllString(number, "") | ||
|
||
if len(number) != 14 { | ||
return cnpj{}, errIncorrectLenghtCNPJNumber | ||
} | ||
|
||
cnpjNumber := cnpjNumber(number) | ||
|
||
if !cnpjNumber.hasValidFirstDigit() { | ||
return cnpj{}, errInvalidCNPJFirstDigit | ||
} | ||
|
||
if !cnpjNumber.hasValidSecondDigit() { | ||
return cnpj{}, errInvalidCNPJSecondDigit | ||
} | ||
|
||
return cnpj{ | ||
number: cnpjNumber, | ||
valid: true, | ||
}, nil | ||
} | ||
|
||
func RandomCNPJNumber(mask bool) string { | ||
var multipliers = []int{6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2} | ||
|
||
source := rand.NewSource(time.Now().UnixNano()) | ||
r := rand.New(source) | ||
cnpjNumber := int(r.Int63n(899999999999) + 100000000000) | ||
cnpjString := strconv.Itoa(cnpjNumber) | ||
|
||
// Calculate first digit | ||
sum := 0 | ||
for i := 0; i < 12; i++ { | ||
number, _ := strconv.Atoi(string(cnpjString[i])) | ||
sum += number * multipliers[i+1] | ||
} | ||
firstDigit := 0 | ||
if sum%11 >= 2 { | ||
firstDigit = 11 - sum%11 | ||
} | ||
|
||
// Calculate second digit | ||
sum = 0 | ||
for i := 0; i < 12; i++ { | ||
number, _ := strconv.Atoi(string(cnpjString[i])) | ||
sum += number * multipliers[i] | ||
} | ||
sum += firstDigit * multipliers[12] | ||
secondDigit := 0 | ||
if sum%11 >= 2 { | ||
secondDigit = 11 - sum%11 | ||
} | ||
|
||
if mask { | ||
return cnpjString[:2] + "." + cnpjString[2:5] + "." + cnpjString[5:8] + "/" + cnpjString[8:12] + "-" + strconv.Itoa(firstDigit) + strconv.Itoa(secondDigit) | ||
} | ||
return cnpjString + strconv.Itoa(firstDigit) + strconv.Itoa(secondDigit) | ||
} | ||
|
||
type cnpjNumber string | ||
|
||
func (c cnpjNumber) hasValidFirstDigit() bool { | ||
var ( | ||
multipliers = []int{5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2} | ||
sum int | ||
) | ||
|
||
for i := 0; i < 12; i++ { | ||
cnpjDigit, _ := strconv.Atoi(string(c[i])) | ||
sum += cnpjDigit * multipliers[i] | ||
} | ||
if sum%11 < 2 { | ||
return string(c[12]) == strconv.Itoa(0) | ||
} | ||
|
||
return string(c[12]) == strconv.Itoa(11-sum%11) | ||
} | ||
|
||
func (c cnpjNumber) hasValidSecondDigit() bool { | ||
var ( | ||
multipliers = []int{6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2} | ||
sum int | ||
) | ||
|
||
for i := 0; i < 13; i++ { | ||
cnpjDigit, _ := strconv.Atoi(string(c[i])) | ||
sum += cnpjDigit * multipliers[i] | ||
} | ||
|
||
if sum%11 < 2 { | ||
return string(c[13]) == strconv.Itoa(0) | ||
} | ||
return string(c[13]) == strconv.Itoa(11-sum%11) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package brazil_test | ||
|
||
import ( | ||
"testing" | ||
|
||
. "flavioltonon/go-brazil" | ||
|
||
. "github.com/smartystreets/goconvey/convey" | ||
) | ||
|
||
func TestParseCNPJ(t *testing.T) { | ||
Convey("Given a string named s", t, func() { | ||
var s string | ||
|
||
Convey("If s is empty", func() { | ||
s = "" | ||
|
||
Convey("And the function ParseCNPJ is called using it as an argument", func() { | ||
cnpj, err := ParseCNPJ(s) | ||
|
||
Convey("It should return an error", func() { | ||
So(err, ShouldNotEqual, nil) | ||
|
||
Convey("And the CNPJ struct number should be empty", func() { | ||
So(cnpj.Number(false), ShouldEqual, "") | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
Convey("If s is a CNPJ number with an invalid first digit", func() { | ||
s = "11222333000171" | ||
|
||
Convey("And the function ParseCNPJ is called using it as an argument", func() { | ||
cnpj, err := ParseCNPJ(s) | ||
|
||
Convey("It should return an error", func() { | ||
So(err, ShouldNotEqual, nil) | ||
|
||
Convey("And the CNPJ struct number should be empty", func() { | ||
So(cnpj.Number(false), ShouldEqual, "") | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
Convey("If s is a CNPJ number with an invalid second digit", func() { | ||
s = "11222333000182" | ||
|
||
Convey("And the function ParseCNPJ is called using it as an argument", func() { | ||
cnpj, err := ParseCNPJ(s) | ||
|
||
Convey("It should return an error", func() { | ||
So(err, ShouldNotEqual, nil) | ||
|
||
Convey("And the CNPJ struct number should be empty", func() { | ||
So(cnpj.Number(false), ShouldEqual, "") | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
Convey("If s is a valid CNPJ number", func() { | ||
s = "11222333000181" | ||
|
||
Convey("And the function ParseCNPJ is called using it as an argument", func() { | ||
cnpj, err := ParseCNPJ(s) | ||
|
||
Convey("It should not return an error", func() { | ||
So(err, ShouldEqual, nil) | ||
|
||
Convey("And the CNPJ struct number should exist", func() { | ||
So(cnpj.Number(false), ShouldEqual, "11222333000181") | ||
So(cnpj.Number(true), ShouldEqual, "11.222.333/0001-81") | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
} | ||
|
||
func TestRandomCNPJNumber(t *testing.T) { | ||
Convey("Given the function RandomCNPJNumber", t, func() { | ||
Convey("If its mask argument equals true", func() { | ||
number := RandomCNPJNumber(true) | ||
|
||
Convey("It should return a valid CNPJ number", func() { | ||
cnpj, err := ParseCNPJ(number) | ||
|
||
So(err, ShouldEqual, nil) | ||
So(cnpj.Number(false), ShouldNotEqual, "") | ||
So(cnpj.Number(true), ShouldNotEqual, "") | ||
}) | ||
}) | ||
|
||
Convey("If its mask argument equals false", func() { | ||
number := RandomCNPJNumber(false) | ||
|
||
Convey("It should return a valid CNPJ number", func() { | ||
cnpj, err := ParseCNPJ(number) | ||
|
||
So(err, ShouldEqual, nil) | ||
So(cnpj.Number(false), ShouldNotEqual, "") | ||
So(cnpj.Number(true), ShouldNotEqual, "") | ||
}) | ||
}) | ||
}) | ||
} |