Skip to content

Commit f52d730

Browse files
committed
add: okato
1 parent d4d96d6 commit f52d730

File tree

5 files changed

+313
-3
lines changed

5 files changed

+313
-3
lines changed

okato/data.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package okato
2+
3+
var fisrtLevel = map[int]string{
4+
0: "Территория не определена", // Территория находится за пределами России
5+
1: "Алтайский край (г.Барнаул)",
6+
3: "Краснодарский край (г.Краснодар)",
7+
4: "Красноярский край (г.Красноярск)",
8+
5: "Приморский край (г.Владивосток)",
9+
7: "Ставропольский край (г.Ставрополь)",
10+
8: "Хабаровский край (г.Хабаровск)",
11+
10: "Амурская область (г.Благовещенск)",
12+
11: "Архангельская область (г.Архангельск)",
13+
12: "Астраханская область (г.Астрахань)",
14+
14: "Белгородская область (г.Белгород)",
15+
15: "Брянская область (г.Брянск)",
16+
17: "Владимирская область (г.Владимир)",
17+
18: "Волгоградская область (г.Волгоград)",
18+
19: "Вологодская область (г.Вологда)",
19+
20: "Воронежская область (г.Воронеж)",
20+
21: "Донецкая Народная Республика (г.Донецк)",
21+
22: "Нижегородская область (г.Нижний Новгород)",
22+
23: "Запорожская область (г.Мелитополь)",
23+
24: "Ивановская область (г.Иваново)",
24+
25: "Иркутская область (г.Иркутск)",
25+
26: "Республика Ингушетия (г.Назрань)",
26+
27: "Калининградская область (г.Калининград)",
27+
28: "Тверская область (г.Тверь)",
28+
29: "Калужская область (г.Калуга)",
29+
30: "Камчатский край (г.Петропавловск-Камчатский)",
30+
32: "Кемеровская область (г.Кемерово)",
31+
33: "Кировская область (г.Киров)",
32+
34: "Костромская область (г.Кострома)",
33+
35: "Республика Крым (г.Симферополь)",
34+
36: "Самарская область (г.Самара)",
35+
37: "Курганская область (г.Курган)",
36+
38: "Курская область (г.Курск)",
37+
40: "Санкт-Петербург (г.Санкт-Петербург)",
38+
41: "Ленинградская область (г.Санкт-Петербург)",
39+
42: "Липецкая область (г.Липецк)",
40+
43: "Луганская Народная Республика (г.Луганск)",
41+
44: "Магаданская область (г.Магадан)",
42+
45: "Москва (г.Москва)",
43+
46: "Московская область (г.Москва)",
44+
47: "Мурманская область (г.Мурманск)",
45+
49: "Новгородская область (г.Великий Новгород)",
46+
50: "Новосибирская область (г.Новосибирск)",
47+
52: "Омская область (г.Омск)",
48+
53: "Оренбургская область (г.Оренбург)",
49+
54: "Орловская область (г.Орел)",
50+
56: "Пензенская область (г.Пенза)",
51+
57: "Пермский край (г.Пермь)",
52+
58: "Псковская область (г.Псков)",
53+
60: "Ростовская область (г.Ростов-на-Дону)",
54+
61: "Рязанская область (г.Рязань)",
55+
63: "Саратовская область (г.Саратов)",
56+
64: "Сахалинская область (г.Южно-Сахалинск)",
57+
65: "Свердловская область (г.Екатеринбург)",
58+
66: "Смоленская область (г.Смоленск)",
59+
67: "Севастополь (г.Севастополь)",
60+
68: "Тамбовская область (г.Тамбов)",
61+
69: "Томская область (г.Томск)",
62+
70: "Тульская область (г.Тула)",
63+
71: "Тюменская область (г.Тюмень)",
64+
73: "Ульяновская область (г.Ульяновск)",
65+
74: "Херсонская область (г.Херсон)",
66+
75: "Челябинская область (г.Челябинск)",
67+
76: "Читинская область (г.Чита)",
68+
77: "Чукотский АО (г.Анадырь)",
69+
78: "Ярославская область (г.Ярославль)",
70+
79: "Республика Адыгея (г.Майкоп)",
71+
80: "Республика Башкортостан (г.Уфа)",
72+
81: "Республика Бурятия (г.Улан-удэ)",
73+
82: "Республика Дагестан (г.Махачкала)",
74+
83: "Кабардино-балкарская республика (г.Нальчик)",
75+
84: "Республика Алтай (г.Горно-алтайск)",
76+
85: "Республика Калмыкия (г.Элиста)",
77+
86: "Республика Карелия (г.Петрозаводск)",
78+
87: "Республика Коми (г.Сыктывкар)",
79+
88: "Республика Марий эл (г.Йошкар-ола)",
80+
89: "Республика Мордовия (г.Саранск)",
81+
90: "Республика северная Осетия",
82+
91: "Карачаево-черкесская республика (г.Черкесск)",
83+
92: "Республика Татарстан (г.Казань)",
84+
93: "Республика Тыва (г.Кызыл)",
85+
94: "Удмуртская республика (г.Ижевск)",
86+
95: "Республика Хакасия (г.Абакан)",
87+
96: "Чеченская республика (г.Грозный)",
88+
97: "Чувашская республика (г.Чебоксары)",
89+
98: "Республика Саха (Якутия) (г.Якутск)",
90+
99: "Еврейская АО (г.Биробиджан)",
91+
}

okato/errors.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package okato
2+
3+
import "errors"
4+
5+
var (
6+
// ErrNilOKATO try call methods for nil okato struct
7+
ErrNilOKATO = errors.New("nil okato struct")
8+
9+
// ErrInvalidCode invalid okato code
10+
ErrInvalidCode = errors.New("invalid okato code")
11+
12+
// ErrFirstLevelCode
13+
ErrFirstLevelCode = errors.New("")
14+
15+
// ErrSecondLevelCode
16+
ErrSecondLevelCode = errors.New("")
17+
18+
// ErrThirdLevelCode
19+
ErrThirdLevelCode = errors.New("")
20+
21+
// ErrFourthLevelCode
22+
ErrFourthLevelCode = errors.New("")
23+
)

okato/models.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package okato
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"unicode"
7+
8+
"github.com/sshaplygin/docs-code/models"
9+
"github.com/sshaplygin/docs-code/utils"
10+
)
11+
12+
const packageName = "okato"
13+
14+
const (
15+
minTerritoryCodeLength = 0
16+
maxTerritoryCodeLength = 99
17+
)
18+
19+
const (
20+
minSecondLevelCodeLength = 0
21+
maxSecondLevelCodeLength = 999
22+
)
23+
24+
const (
25+
minThirdLevelCodeLength = 0
26+
maxThirdLevelCodeLength = 999
27+
)
28+
29+
const (
30+
minForuthLevelCodeLength = 0
31+
maxForuthLevelCodeLength = 999
32+
)
33+
34+
// Структура кодового обозначения в блоке идентификации: XX XXX XXX XXX, где
35+
36+
// 1, 2 знаки — объекты первого уровня классификации (субъекты Российской Федерации);
37+
// 3, 4, 5 знаки — объекты второго уровня классификации;
38+
// 6, 7, 8 знаки — объекты третьего уровня классификации;
39+
// КЧ — контрольное число.
40+
41+
const codeLength = 11
42+
43+
type OKATOStruct struct {
44+
firstLevel StateCode
45+
secondLevel SecondLevelCode
46+
thirdLevel ThirdLevelCode
47+
fourthLevel FourthLevelCode
48+
}
49+
50+
func NewOKATO(okato string) (*OKATOStruct, error) {
51+
okatoArr := make([]int, 0, codeLength)
52+
var (
53+
val int
54+
err error
55+
)
56+
57+
for _, code := range okato {
58+
if code == rune(' ') {
59+
continue
60+
}
61+
62+
if !unicode.IsDigit(code) {
63+
return nil, ErrInvalidCode
64+
}
65+
66+
val, err = strconv.Atoi(string(code))
67+
if err != nil {
68+
return nil, fmt.Errorf("parse raw %s : %w", packageName, err)
69+
}
70+
71+
okatoArr = append(okatoArr, val)
72+
}
73+
74+
if len(okato) != codeLength {
75+
return nil, &models.CommonError{
76+
Method: packageName,
77+
Err: models.ErrInvalidLength,
78+
}
79+
}
80+
81+
return &OKATOStruct{
82+
firstLevel: StateCode(utils.SliceToInt(okatoArr[0:2])),
83+
secondLevel: SecondLevelCode(utils.SliceToInt(okatoArr[2:5])),
84+
thirdLevel: ThirdLevelCode(utils.SliceToInt(okatoArr[5:8])),
85+
fourthLevel: FourthLevelCode(utils.SliceToInt(okatoArr[8:])),
86+
}, nil
87+
}
88+
89+
func (ost *OKATOStruct) IsValid() (bool, error) {
90+
if ost == nil {
91+
return false, ErrNilOKATO
92+
}
93+
94+
if !ost.firstLevel.IsValid() {
95+
return false, ErrFirstLevelCode
96+
}
97+
98+
if !ost.secondLevel.IsValid() {
99+
return false, ErrSecondLevelCode
100+
}
101+
102+
if !ost.thirdLevel.IsValid() {
103+
return false, ErrThirdLevelCode
104+
}
105+
106+
if !ost.fourthLevel.IsValid() {
107+
return false, ErrFourthLevelCode
108+
}
109+
110+
return true, nil
111+
}
112+
113+
func (ost *OKATOStruct) IsExist() (bool, error) {
114+
panic("not implemented!")
115+
}
116+
117+
// Алейского сельсовета Алейского района Алтайского края - 01 201 802 000
118+
119+
type StateCode int
120+
121+
func (s StateCode) IsValid() bool {
122+
return s >= minTerritoryCodeLength && s <= maxTerritoryCodeLength
123+
}
124+
125+
func (s StateCode) String() string {
126+
region, ok := fisrtLevel[int(s)]
127+
if !ok {
128+
return fisrtLevel[0]
129+
}
130+
131+
return region
132+
}
133+
134+
func GenerateStateCode() StateCode {
135+
panic("not implemented")
136+
}
137+
138+
func (cc StateCode) ToString() string {
139+
panic("not implemented")
140+
}
141+
142+
func (s StateCode) GetName() string {
143+
panic("not implemented")
144+
}
145+
146+
func (s StateCode) GetCenter() string {
147+
panic("not implemented")
148+
}
149+
150+
type SecondLevelCode int
151+
152+
func (s SecondLevelCode) IsValid() bool {
153+
return s >= minSecondLevelCodeLength && s <= maxSecondLevelCodeLength
154+
}
155+
156+
type ThirdLevelCode int
157+
158+
func (s ThirdLevelCode) IsValid() bool {
159+
return s >= minThirdLevelCodeLength && s <= maxThirdLevelCodeLength
160+
}
161+
162+
type FourthLevelCode int
163+
164+
func (s FourthLevelCode) IsValid() bool {
165+
return s >= minForuthLevelCodeLength && s <= maxForuthLevelCodeLength
166+
}

okato/okato.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,38 @@
11
package okato
22

3+
import (
4+
"fmt"
5+
)
6+
37
// Validate check to valid OKATO format
4-
// example: input format is 17205000000
8+
// example: input format is 17 205 000 000
59
func Validate(okato string) (bool, error) {
6-
panic("not implemented!")
10+
okatoData, err := NewOKATO(okato)
11+
if err != nil {
12+
return false, fmt.Errorf("create %s model: %w", packageName, err)
13+
}
14+
15+
return okatoData.IsValid()
16+
}
17+
18+
// IsExist check to valid OKATO format and check to used code.
19+
// Example valid format is 01 201 802 003 - Алтайский край/Районы Алтайского края/Алейский район/Сельсоветы Алейского р-на/п Мамонтовский
20+
func IsExist(bik string) (bool, error) {
21+
okatoData, err := NewOKATO(bik)
22+
if err != nil {
23+
return false, fmt.Errorf("create %s model: %w", packageName, err)
24+
}
25+
26+
isValid, err := okatoData.IsValid()
27+
if err != nil {
28+
return false, fmt.Errorf("check valid %s model: %w", packageName, err)
29+
}
30+
31+
if !isValid {
32+
return false, fmt.Errorf("invalid %s model", packageName)
33+
}
34+
35+
return okatoData.IsExist()
736
}
837

938
func Generate() string {

okato/okato_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88

99
func Test_Validete(t *testing.T) {
1010
require.Panics(t, func() {
11-
Validate("")
11+
_, err := Validate("")
12+
require.NoError(t, err)
1213
})
1314
}
1415

0 commit comments

Comments
 (0)