Skip to content

Commit 4d3f023

Browse files
committed
ref: move logic to packages
1 parent c33c04c commit 4d3f023

File tree

17 files changed

+873
-575
lines changed

17 files changed

+873
-575
lines changed

README.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# ru-doc-codes
22
[![GoDoc](https://godoc.org/github.com/mrfoe7/ru-doc-code?status.svg)](https://godoc.org/github.com/mrfoe7/ru-doc-code) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mrfoe7/ru-doc-code/blob/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/mrfoe7/ru-doc-code)](https://goreportcard.com/report/github.com/mrfoe7/ru-doc-code)
33

4-
It is validator about official codes of documents from Russia in Go
4+
It is validator about official of code documents from Russia in Go
55

66
## Usage
77

@@ -11,26 +11,29 @@ It is validator about official codes of documents from Russia in Go
1111

1212
```go
1313

14-
isValid, err := ru-doc-code.IsSNILSValid("112-233-445 95")
14+
import (
15+
"log"
16+
17+
"github.com/mrfoe7/ru-doc-codes/inn"
18+
)
19+
20+
...
21+
22+
isValid, err := inn.Validate("526317984689")
1523
if err != nil {
1624
log.Fatal(err)
1725
}
1826
if isValid {
19-
log.Println("SNILS is valid")
27+
log.Println("INN is valid")
2028
}
2129

2230
```
2331

2432
## Documentation
2533

26-
- Check to valid INN - [ИНН](https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0)
27-
28-
- Check to valid SNILS - [СНИЛС](http://www.consultant.ru/document/cons_doc_LAW_124607/68ac3b2d1745f9cc7d4332b63c2818ca5d5d20d0/)
29-
30-
- Check to valid OGRN - [ОГРН](https://ru.wikipedia.org/wiki/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D0%BE%D0%B9_%D0%B3%D0%BE%D1%81%D1%83%D0%B4%D0%B0%D1%80%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80)
31-
32-
- Check to valid OGRNIP - [ОГРНИП](http://www.temabiz.com/terminy/chto-takoe-ogrnip.html)
33-
34-
- Check to valid BIK - [БИК](https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D0%BD%D0%BA%D0%BE%D0%B2%D1%81%D0%BA%D0%B8%D0%B9_%D0%B8%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4)
35-
36-
- Check to valid KPP - [КПП](https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0#%D0%9A%D0%BE%D0%B4_%D0%BF%D1%80%D0%B8%D1%87%D0%B8%D0%BD%D1%8B_%D0%BF%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B8_%D0%BD%D0%B0_%D1%83%D1%87%D1%91%D1%82_(%D0%9A%D0%9F%D0%9F)
34+
- Info about INN - [ИНН](https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%89%D0%B8%D0%BA%D0%B0)
35+
- Info about SNILS - [СНИЛС](http://www.consultant.ru/document/cons_doc_LAW_124607/68ac3b2d1745f9cc7d4332b63c2818ca5d5d20d0/)
36+
- Info about OGRN - [ОГРН](https://ru.wikipedia.org/wiki/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D0%BE%D0%B9_%D0%B3%D0%BE%D1%81%D1%83%D0%B4%D0%B0%D1%80%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80)
37+
- Info about OGRNIP - [ОГРНИП](http://www.temabiz.com/terminy/chto-takoe-ogrnip.html)
38+
- Info about BIK - [БИК](https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D0%BD%D0%BA%D0%BE%D0%B2%D1%81%D0%BA%D0%B8%D0%B9_%D0%B8%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4)
39+
- Info about KPP - [КПП](https://dic.academic.ru/dic.nsf/ruwiki/239834)

bik/bik.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package bik
2+
3+
import (
4+
"strconv"
5+
6+
ru_doc_code "github.com/mrfoe7/go-codes-validator"
7+
)
8+
9+
// Validate check to valid BIK format
10+
// example valid format is 044525225
11+
func Validate(bik string) (bool, error) {
12+
if len(bik) != 9 {
13+
return false, ru_doc_code.ErrInvalidBIKLength
14+
}
15+
16+
bikArr, err := ru_doc_code.StrToArr(bik)
17+
if err != nil {
18+
return false, err
19+
}
20+
21+
if bikArr[0] != 0 || bikArr[1] != 4 {
22+
return false, ru_doc_code.ErrInvalidBIKCountryCode
23+
}
24+
25+
// special code
26+
if bikArr[6] == 0 && bikArr[7] == 1 && bikArr[8] == 2 {
27+
return true, nil
28+
}
29+
30+
latestTriadStr := bik[6:]
31+
code, _ := strconv.Atoi(latestTriadStr)
32+
33+
return code >= 50 && code < 1000, nil
34+
}

bik/bik_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package bik
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
9+
ru_doc_code "github.com/mrfoe7/go-codes-validator"
10+
)
11+
12+
func TestValidate(t *testing.T) {
13+
t.Parallel()
14+
15+
t.Run("invalid bik length", func(t *testing.T) {
16+
testCases := []ru_doc_code.TestCodeCase{
17+
{
18+
Code: "1234567888776",
19+
Error: ru_doc_code.ErrInvalidBIKLength,
20+
IsValid: false,
21+
},
22+
{
23+
Code: "044525",
24+
Error: ru_doc_code.ErrInvalidBIKLength,
25+
IsValid: false,
26+
},
27+
{
28+
Code: "044525225",
29+
Error: nil,
30+
IsValid: true,
31+
},
32+
{
33+
Code: "044525012",
34+
Error: nil,
35+
IsValid: true,
36+
},
37+
}
38+
for _, test := range testCases {
39+
isValid, err := Validate(test.Code)
40+
assert.Equal(t, test.IsValid, isValid, test.Code)
41+
assert.Equal(t, true, errors.Is(test.Error, err), test.Code)
42+
}
43+
})
44+
45+
t.Run("invalid bik value", func(t *testing.T) {
46+
testCases := []ru_doc_code.TestCodeCase{
47+
{
48+
Code: "0445?5226",
49+
Error: ru_doc_code.ErrInvalidValue,
50+
IsValid: false,
51+
},
52+
{
53+
Code: "054525225",
54+
Error: ru_doc_code.ErrInvalidBIKCountryCode,
55+
IsValid: false,
56+
},
57+
{
58+
Code: "104525225",
59+
Error: ru_doc_code.ErrInvalidBIKCountryCode,
60+
IsValid: false,
61+
},
62+
{
63+
Code: "044#55#25",
64+
Error: ru_doc_code.ErrInvalidValue,
65+
IsValid: false,
66+
},
67+
{
68+
Code: "044525225",
69+
Error: nil,
70+
IsValid: true,
71+
},
72+
{
73+
Code: "044525012",
74+
Error: nil,
75+
IsValid: true,
76+
},
77+
}
78+
for _, test := range testCases {
79+
isValid, err := Validate(test.Code)
80+
assert.Equal(t, test.IsValid, isValid, test.Code, test.IsValid)
81+
assert.Equal(t, true, errors.Is(test.Error, err), test.Code)
82+
}
83+
})
84+
}

helpers.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ru_doc_code
2+
3+
import (
4+
"crypto/rand"
5+
"math/big"
6+
"strconv"
7+
"strings"
8+
)
9+
10+
func RandomDigits(len int) int64 {
11+
if len <= 0 {
12+
len = 1
13+
}
14+
max, _ := strconv.Atoi(strings.Repeat("9", len))
15+
min, _ := strconv.Atoi("1" + strings.Repeat("0", len-1))
16+
17+
num, _ := rand.Int(rand.Reader, big.NewInt(int64(max-min+1)))
18+
return num.Int64() + int64(min)
19+
}
20+
21+
func StrToArr(str string) ([]int, error) {
22+
numbers := strings.Split(str, "")
23+
arr := make([]int, 0, len(numbers))
24+
for _, number := range numbers {
25+
number, err := strconv.Atoi(number)
26+
if err != nil {
27+
return []int{}, ErrInvalidValue
28+
}
29+
arr = append(arr, number)
30+
}
31+
return arr, nil
32+
}

inn/inn.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package inn
2+
3+
import (
4+
"strconv"
5+
"strings"
6+
7+
ru_doc_code "github.com/mrfoe7/go-codes-validator"
8+
)
9+
10+
const (
11+
lengthLegal = 10
12+
lengthPhysical = 12
13+
)
14+
15+
// Validate check to valid inn from input string.
16+
// example: input format is 7707083893
17+
func Validate(inn string) (bool, error) {
18+
if len(inn) != lengthLegal && len(inn) != lengthPhysical {
19+
return false, ru_doc_code.ErrInvalidINNLength
20+
}
21+
22+
innArr, err := transformInn(inn)
23+
if err != nil {
24+
return false, err
25+
}
26+
if len(inn) == 10 {
27+
return hash10(innArr) == innArr[len(innArr)-1], nil
28+
}
29+
30+
return hash11(innArr) == innArr[len(innArr)-2] && hash12(innArr) == innArr[len(innArr)-1], nil
31+
}
32+
33+
// GenerateLegal generate legal type inn string value.
34+
func GenerateLegal() string {
35+
inn := strconv.FormatInt(ru_doc_code.RandomDigits(9), 10)
36+
innArr, _ := transformInn(inn)
37+
38+
return inn + strconv.Itoa(hash10(innArr))
39+
}
40+
41+
// GeneratePhysical generate physical type inn string value.
42+
func GeneratePhysical() string {
43+
inn := strconv.FormatInt(ru_doc_code.RandomDigits(10), 10)
44+
innArr, _ := transformInn(inn)
45+
46+
hash1Num := hash11(innArr)
47+
innArr = append(innArr, hash1Num)
48+
49+
return strings.Join([]string{
50+
inn,
51+
strconv.Itoa(hash1Num),
52+
strconv.Itoa(hash12(innArr)),
53+
}, "")
54+
}
55+
56+
func transformInn(inn string) ([]int, error) {
57+
innNumbers := strings.Split(inn, "")
58+
innArr := make([]int, 0, len(inn))
59+
60+
for _, str := range innNumbers {
61+
number, err := strconv.Atoi(str)
62+
if err != nil {
63+
return nil, ru_doc_code.ErrInvalidValue
64+
}
65+
innArr = append(innArr, number)
66+
}
67+
68+
return innArr, nil
69+
}
70+
71+
// Generate generate random type inn string value.
72+
func Generate() string {
73+
if ru_doc_code.RandomDigits(1)%2 == 1 {
74+
return GeneratePhysical()
75+
}
76+
77+
return GenerateLegal()
78+
}
79+
80+
// IsEntrepreneur check inn for Entrepreneur type
81+
func IsEntrepreneur(inn string) bool {
82+
return len(inn) == lengthPhysical
83+
}
84+
85+
// IsCompany check inn for Company type
86+
func IsCompany(inn string) bool {
87+
return len(inn) == lengthLegal
88+
}
89+
90+
func hash10(innArr []int) int {
91+
return ((2*innArr[0] + 4*innArr[1] + 10*innArr[2] + 3*innArr[3] +
92+
5*innArr[4] + 9*innArr[5] + 4*innArr[6] + 6*innArr[7] + 8*innArr[8]) % 11) % 10
93+
}
94+
95+
func hash11(innArr []int) int {
96+
return ((7*innArr[0] + 2*innArr[1] + 4*innArr[2] + 10*innArr[3] + 3*innArr[4] +
97+
5*innArr[5] + 9*innArr[6] + 4*innArr[7] + 6*innArr[8] + 8*innArr[9]) % 11) % 10
98+
}
99+
100+
func hash12(innArr []int) int {
101+
return ((3*innArr[0] + 7*innArr[1] + 2*innArr[2] + 4*innArr[3] +
102+
10*innArr[4] + 3*innArr[5] + 5*innArr[6] + 9*innArr[7] + 4*innArr[8] +
103+
6*innArr[9] + 8*innArr[10]) % 11) % 10
104+
}

0 commit comments

Comments
 (0)