diff --git a/BENCHMARKS.md b/BENCHMARKS.md new file mode 100644 index 0000000..396e6b9 --- /dev/null +++ b/BENCHMARKS.md @@ -0,0 +1,54 @@ +# Benchmarks + +## BIK + +goos: darwin +goarch: arm64 +pkg: github.com/sshaplygin/docs-code/bik +BenchmarkValidateCorrect-10 8064954 140.7 ns/op 256 B/op 3 allocs/op +BenchmarkGenerate-10 615589 1972 ns/op 240 B/op 18 allocs/op +PASS +ok github.com/sshaplygin/docs-code/bik 2.635s + +## INN + +goos: darwin +goarch: arm64 +pkg: github.com/sshaplygin/docs-code/inn +BenchmarkValidateCorrectLegal-10 2719714 443.8 ns/op 616 B/op 23 allocs/op +BenchmarkValidateCorrectPhysical-10 2076355 576.6 ns/op 936 B/op 30 allocs/op +BenchmarkGenerate-10 394204 3133 ns/op 875 B/op 42 allocs/op +BenchmarkGenerateLegal-10 354616 3213 ns/op 801 B/op 41 allocs/op +BenchmarkGeneratePhysical-10 492985 2419 ns/op 974 B/op 41 allocs/op +PASS +ok github.com/sshaplygin/docs-code/inn 7.215s + +## KPP + +goos: darwin +goarch: arm64 +pkg: github.com/sshaplygin/docs-code/kpp +BenchmarkValidateCorrect-10 5280958 218.9 ns/op 216 B/op 8 allocs/op +BenchmarkGenerate-10 484114 2434 ns/op 385 B/op 22 allocs/op +PASS +ok github.com/sshaplygin/docs-code/kpp 2.810s + +## OGRN + +goos: darwin +goarch: arm64 +pkg: github.com/sshaplygin/docs-code/ogrn +BenchmarkValidateCorrect-10 2583738 457.3 ns/op 728 B/op 18 allocs/op +BenchmarkGenerate-10 294908 3938 ns/op 841 B/op 45 allocs/op +PASS +ok github.com/sshaplygin/docs-code/ogrn 3.074s + +## OGRNIP + +goos: darwin +goarch: arm64 +pkg: github.com/sshaplygin/docs-code/ogrnip +BenchmarkValidateCorrect-10 1991065 580.4 ns/op 1008 B/op 24 allocs/op +BenchmarkGenerate-10 403179 3100 ns/op 1010 B/op 46 allocs/op +PASS +ok github.com/sshaplygin/docs-code/ogrnip 3.411s diff --git a/bik/bik_test.go b/bik/bik_test.go index d289d41..e16dce5 100644 --- a/bik/bik_test.go +++ b/bik/bik_test.go @@ -102,11 +102,13 @@ func TestValidate(t *testing.T) { } func Test_Generate(t *testing.T) { - bik := Generate() - isValid, err := Validate(bik) - require.NoError(t, err, fmt.Sprintf("invalid bik value: %s", bik)) + for i := 0; i < 10; i++ { + bik := Generate() + isValid, err := Validate(bik) + require.NoError(t, err, fmt.Sprintf("invalid bik value: %s", bik)) - assert.True(t, isValid) + assert.True(t, isValid) + } } func Test_Exists(t *testing.T) { diff --git a/fts/fts.go b/fts/fts.go index 7320b99..6843060 100644 --- a/fts/fts.go +++ b/fts/fts.go @@ -53,19 +53,8 @@ func (trc *TaxRegionCode) Ints() []int { res := make([]int, subjectCodeLength+regionTaxServiceNumberLength) - nums := utils.CodeToInts(int(trc.subjectCode)) - idx := subjectCodeLength - 1 - for i := len(nums) - 1; i >= 0; i-- { - res[idx] = nums[i] - idx-- - } - - nums = utils.CodeToInts(int(trc.serviceNumber)) - idx = len(res) - 1 - for i := len(nums) - 1; i >= 0; i-- { - res[idx] = nums[i] - idx-- - } + utils.FillSlice(utils.CodeToInts(int(trc.subjectCode)), res, subjectCodeLength-1) + utils.FillSlice(utils.CodeToInts(int(trc.serviceNumber)), res, len(res)-1) return res } @@ -154,6 +143,12 @@ func (csc ConstitutionRegionCode) GetName() string { return codeName } +func (csc ConstitutionRegionCode) Ints() []int { + res := make([]int, subjectCodeLength) + utils.FillSlice(utils.CodeToInts(int(csc)), res, len(res)-1) + return res +} + func GenerateConstitutionSubjectCode() ConstitutionRegionCode { return regionsCodes[utils.Random(0, len(regionsCodes)-1)] } diff --git a/generate.go b/generate.go index 9f1c0fc..e5f6345 100644 --- a/generate.go +++ b/generate.go @@ -4,6 +4,8 @@ import ( "github.com/sshaplygin/docs-code/bik" "github.com/sshaplygin/docs-code/inn" "github.com/sshaplygin/docs-code/kpp" + "github.com/sshaplygin/docs-code/ogrn" + "github.com/sshaplygin/docs-code/ogrnip" ) type GenerateFunc func() string @@ -17,6 +19,10 @@ func Generate(docType DocType) string { callFunc = inn.Generate case KPP: callFunc = kpp.Generate + case OGRN: + callFunc = ogrn.Generate + case OGRNIP: + callFunc = ogrnip.Generate } if callFunc == nil { diff --git a/inn/models.go b/inn/models.go index a346384..33bff18 100644 --- a/inn/models.go +++ b/inn/models.go @@ -44,12 +44,12 @@ const ( ) type SerialNumber struct { - val int - size int + val int + len int } func (sn SerialNumber) String() string { - return utils.StrCode(sn.val, sn.size) + return utils.StrCode(sn.val, sn.len) } func (sn *SerialNumber) Ints() []int { @@ -57,14 +57,8 @@ func (sn *SerialNumber) Ints() []int { return nil } - res := make([]int, sn.size) - nums := utils.CodeToInts(sn.val) - - idx := len(res) - 1 - for i := len(nums) - 1; i >= 0; i-- { - res[idx] = nums[i] - idx-- - } + res := make([]int, sn.len) + utils.FillSlice(utils.CodeToInts(sn.val), res, len(res)-1) return res } @@ -72,14 +66,14 @@ func (sn *SerialNumber) Ints() []int { func GenerateSerailNumber(innType INNType) SerialNumber { if innType == Physical { return SerialNumber{ - val: int(utils.RandomDigits(physicalSerialNumberLength)), - size: physicalSerialNumberLength, + val: int(utils.RandomDigits(physicalSerialNumberLength)), + len: physicalSerialNumberLength, } } return SerialNumber{ - val: int(utils.RandomDigits(legalSerialNumberLength)), - size: legalSerialNumberLength, + val: int(utils.RandomDigits(legalSerialNumberLength)), + len: legalSerialNumberLength, } } @@ -111,7 +105,6 @@ func GenerateCheckSums(innType INNType, nums []int) CheckSums { nums = append(nums, f(nums)) } - fmt.Println(nums[len(nums)+shiftIdx:]) return nums[len(nums)+shiftIdx:] } @@ -148,10 +141,10 @@ func ParseINN(inn string) (*INNStruct, error) { } t := Physical - snSize := physicalSerialNumberLength + snlen := physicalSerialNumberLength parseIdx := len(inn) - 2 if len(inn) == legalLength { - snSize = legalSerialNumberLength + snlen = legalSerialNumberLength t = Legal parseIdx = len(inn) - 1 const foreignLegalStartWith = "9909" @@ -173,8 +166,8 @@ func ParseINN(inn string) (*INNStruct, error) { return &INNStruct{ taxRegionCode: taxRegionCode, serialNumber: SerialNumber{ - val: utils.SliceToInt(serialNumberArr), - size: snSize, + val: utils.SliceToInt(serialNumberArr), + len: snlen, }, checkSums: checkSums, t: t, diff --git a/kpp/errors.go b/kpp/errors.go index 3ca21ec..d0f4605 100644 --- a/kpp/errors.go +++ b/kpp/errors.go @@ -12,6 +12,6 @@ var ( // ErrInvalidReasonCode invalid reason code ErrInvalidReasonCode = errors.New("invalid reason code") - // ErrInvalidSerialNumber invalid serial number - ErrInvalidSerialNumber = errors.New("invalid serial number") + // ErrInvalidSerialNumbers invalid serial number + ErrInvalidSerialNumbers = errors.New("invalid serial number") ) diff --git a/kpp/kpp_test.go b/kpp/kpp_test.go index 683af47..819dce7 100644 --- a/kpp/kpp_test.go +++ b/kpp/kpp_test.go @@ -130,11 +130,13 @@ func TestValidate(t *testing.T) { } func Test_Generate(t *testing.T) { - kpp := Generate() - isValid, err := Validate(kpp) - require.NoError(t, err, fmt.Sprintf("invalid kpp value: %s", kpp)) + for i := 0; i < 10; i++ { + kpp := Generate() + isValid, err := Validate(kpp) + require.NoError(t, err, fmt.Sprintf("invalid kpp value: %s", kpp)) - assert.True(t, isValid) + assert.True(t, isValid) + } } func BenchmarkValidateCorrect(b *testing.B) { diff --git a/kpp/models.go b/kpp/models.go index 2794a88..3599376 100644 --- a/kpp/models.go +++ b/kpp/models.go @@ -116,7 +116,7 @@ func (kpp *KPPStruct) IsValid() (bool, error) { } if !kpp.serialNumber.IsValid() { - return false, fmt.Errorf(validateErrorTmpl, ErrInvalidSerialNumber, kpp.serialNumber) + return false, fmt.Errorf(validateErrorTmpl, ErrInvalidSerialNumbers, kpp.serialNumber) } return true, nil diff --git a/ogrn/errors.go b/ogrn/errors.go new file mode 100644 index 0000000..c27b775 --- /dev/null +++ b/ogrn/errors.go @@ -0,0 +1,20 @@ +package ogrn + +import "errors" + +var ( + // ErrNilOGRN try call methods for nil ogrn struct + ErrNilOGRN = errors.New("nil ogrn struct") + + // ErrInvalidCodeType invalid code type + ErrInvalidCodeType = errors.New("invalid code type") + + // ErrInvalidYearsNumbers invalid years number code + ErrInvalidYearsNumbers = errors.New("invalid years number code") + + // ErrInvalidRegion invalid region code + ErrInvalidRegion = errors.New("invalid region code") + + // ErrInvalidSerialNumbers invalid serial numbers + ErrInvalidSerialNumbers = errors.New("invalid serial numbers") +) diff --git a/ogrn/models.go b/ogrn/models.go index 904020c..e5635da 100644 --- a/ogrn/models.go +++ b/ogrn/models.go @@ -1,3 +1,306 @@ package ogrn +import ( + "fmt" + "strings" + "time" + + "github.com/sshaplygin/docs-code/fts" + "github.com/sshaplygin/docs-code/models" + "github.com/sshaplygin/docs-code/utils" +) + const packageName = "ogrn" + +const validateErrorTmpl = "%w: %s" + +const ( + codeTypeLength = 1 +) + +const ( + yearsNumbersLength = 2 +) + +const ( + checkSumLength = 1 +) + +type CodeType int + +func (ct CodeType) String() string { + return utils.StrCode(int(ct), codeTypeLength) +} + +func (ct CodeType) IsValid() bool { + _, ok := supportedCodes[ct] + return ok +} + +type OGRNType uint + +const ( + Physical OGRNType = iota + Legal + Government +) + +var supportedCodes = map[CodeType]OGRNType{ + 1: Legal, + 5: Legal, + 2: Government, + 4: Government, + 6: Government, + 7: Government, + 8: Government, + 9: Government, + 3: Physical, +} + +type YearsNumbers int + +func (yn YearsNumbers) String() string { + return utils.StrCode(int(yn), yearsNumbersLength) +} + +func (yn YearsNumbers) Ints() []int { + res := make([]int, yearsNumbersLength) + utils.FillSlice(utils.CodeToInts(int(yn)), res, yearsNumbersLength-1) + return res +} + +func (yn YearsNumbers) IsValid() bool { + // 19xx: [91, 99] || 20xx: [00, now.Year%100] + return yn >= 0 && yn <= YearsNumbers(time.Now().Year()%100) || yn >= 91 && yn <= 99 +} + +type serialNumbers struct { + val int + len int +} + +func (sn serialNumbers) IsValid() bool { + maxL := 0 + for i := 0; i < sn.len; i++ { + maxL = maxL*10 + 9 + } + return sn.val >= 0 && sn.val <= maxL +} + +func (sn serialNumbers) String() string { + return utils.StrCode(sn.val, sn.len) +} + +func (sn serialNumbers) Ints() []int { + res := make([]int, sn.len) + utils.FillSlice(utils.CodeToInts(int(sn.val)), res, sn.len-1) + return res +} + +type checkSum int + +func (cs checkSum) String() string { + return utils.StrCode(int(cs), checkSumLength) +} + +type OGRNStruct struct { + code CodeType + yearsNumbers YearsNumbers + region fts.ConstitutionRegionCode + serialNumbers serialNumbers + checkSum checkSum +} + +func GenerateCodeType(ogrnType OGRNType) CodeType { + var c CodeType = 3 + if ogrnType == Legal { + c = 1 + if utils.RandomDigits(1)%2 == 0 { + c = 5 + } + } + return c +} + +func GenerateYearsNumbers() YearsNumbers { + // 19xx: [91, 99] || 20xx: [00, now.Year%100] + min, max := 91, 99 + if utils.RandomDigits(1)%2 == 0 { + min, max = 00, time.Now().Year()%100 + } + return YearsNumbers(utils.Random(min, max)) +} + +func GenerateSerialNumbers(ogrnType OGRNType) serialNumbers { + n := legalCodeLength + if ogrnType == Physical { + n = physicalCodeLength + } + + return serialNumbers{ + val: int(utils.RandomDigits(n)), + len: n, + } +} + +func NewOGRN(ogrnType OGRNType) *OGRNStruct { + ogrnData := &OGRNStruct{ + code: GenerateCodeType(ogrnType), + yearsNumbers: GenerateYearsNumbers(), + region: fts.GenerateConstitutionSubjectCode(), + serialNumbers: GenerateSerialNumbers(ogrnType), + } + + ogrnData.checkSum = ogrnData.calculateCheckSum() + + return ogrnData +} + +const ( + legalLength = 13 + physicalLength = 15 +) + +const ( + legalCodeLength = 7 + physicalCodeLength = 9 +) + +func ParseOGRN(requiredType OGRNType, ogrn string) (*OGRNStruct, error) { + if requiredType != Physical && len(ogrn) != legalLength { + return nil, &models.CommonError{ + Method: packageName, + Err: models.ErrInvalidLength, + } + } + + if requiredType == Physical && len(ogrn) != physicalLength { + fmt.Println(requiredType, len(ogrn)) + return nil, &models.CommonError{ + Method: packageName, + Err: models.ErrInvalidLength, + } + } + + ogrnArr, err := utils.StrToArr(ogrn) + if err != nil { + return nil, fmt.Errorf("parse raw %s: %w", packageName, err) + } + + code := CodeType(utils.SliceToInt(ogrnArr[:1])) + expectedCode, ok := supportedCodes[code] + if !ok || expectedCode != requiredType { + return nil, ErrInvalidCodeType + } + + l := legalCodeLength + if requiredType == Physical { + l = physicalCodeLength + } + + return &OGRNStruct{ + code: code, + yearsNumbers: YearsNumbers(utils.SliceToInt(ogrnArr[1:3])), + region: fts.ConstitutionRegionCode(utils.SliceToInt(ogrnArr[3:5])), + serialNumbers: serialNumbers{ + val: utils.SliceToInt(ogrnArr[5 : len(ogrnArr)-1]), + len: l, + }, + checkSum: checkSum(utils.SliceToInt(ogrnArr[len(ogrnArr)-1:])), + }, nil +} + +func (o *OGRNStruct) String() string { + codeLength := legalLength + + expectedCode := supportedCodes[o.code] + if expectedCode == Physical { + codeLength = physicalLength + } + + var res strings.Builder + res.Grow(codeLength) + + res.WriteString(o.code.String()) + res.WriteString(o.yearsNumbers.String()) + res.WriteString(o.region.String()) + res.WriteString(o.serialNumbers.String()) + res.WriteString(o.checkSum.String()) + + return res.String() +} + +func (o *OGRNStruct) IsValid() (bool, error) { + if o == nil { + return false, ErrNilOGRN + } + + if !o.code.IsValid() { + return false, fmt.Errorf(validateErrorTmpl, ErrInvalidCodeType, o.code) + } + + if !o.yearsNumbers.IsValid() { + return false, fmt.Errorf(validateErrorTmpl, ErrInvalidYearsNumbers, o.yearsNumbers) + } + + if !o.region.IsValid() { + return false, fmt.Errorf(validateErrorTmpl, ErrInvalidRegion, o.region) + } + + if !o.serialNumbers.IsValid() { + return false, fmt.Errorf(validateErrorTmpl, ErrInvalidSerialNumbers, o.serialNumbers) + } + + return o.calculateCheckSum() == o.checkSum, nil +} + +func (o *OGRNStruct) IsLegal() bool { + t, ok := supportedCodes[o.code] + if !ok { + // by default OGRN for legal + return true + } + + return t == Legal +} + +func (o *OGRNStruct) IsPhysical() bool { + t, ok := supportedCodes[o.code] + if !ok { + // by default OGRN for legal + return false + } + + return t == Physical +} + +func (o *OGRNStruct) makeSliceInts() []int { + n := legalLength + if o.IsPhysical() { + n = physicalLength + } + res := make([]int, n-1) + res[0] = int(o.code) + + utils.FillSlice(o.yearsNumbers.Ints(), res, 2) + utils.FillSlice(o.region.Ints(), res, 4) + utils.FillSlice(o.serialNumbers.Ints(), res, n-2) + + return res +} + +func (o *OGRNStruct) calculateCheckSum() checkSum { + const ( + legalDelim = 11 + physicalDelim = 13 + ) + + delim := legalDelim + if o.IsPhysical() { + delim = physicalDelim + } + + code := utils.SliceToInt(o.makeSliceInts()) + + return checkSum(code % delim % 10) +} diff --git a/ogrn/ogrn.go b/ogrn/ogrn.go index c6c0f22..b1a2493 100644 --- a/ogrn/ogrn.go +++ b/ogrn/ogrn.go @@ -1,31 +1,20 @@ package ogrn import ( - "strconv" - - "github.com/sshaplygin/docs-code/models" - "github.com/sshaplygin/docs-code/utils" + "fmt" ) // Validate check to valid OGRN format // example: input format is 1027700132195 func Validate(ogrn string) (bool, error) { - if len(ogrn) != 13 { - return false, &models.CommonError{ - Method: packageName, - Err: models.ErrInvalidLength, - } - } - - ogrnArr, err := utils.StrToArr(ogrn) + ogrnData, err := ParseOGRN(Legal, ogrn) if err != nil { - return false, err + return false, fmt.Errorf("parse %s model: %w", packageName, err) } - code, _ := strconv.Atoi(ogrn[:12]) - return ogrnArr[len(ogrn)-1] == code%11%10, nil + return ogrnData.IsValid() } func Generate() string { - panic("not implemented!") + return NewOGRN(Legal).String() } diff --git a/ogrn/ogrn_test.go b/ogrn/ogrn_test.go index a834133..a369538 100644 --- a/ogrn/ogrn_test.go +++ b/ogrn/ogrn_test.go @@ -1,7 +1,6 @@ package ogrn import ( - "errors" "fmt" "testing" @@ -24,23 +23,19 @@ func TestValidate(t *testing.T) { testCases := []testCase{ { Code: "1027700132195", - Error: nil, IsValid: true, }, { Code: "1027739244741", - Error: nil, IsValid: true, }, { - Code: "102773924", - Error: models.ErrInvalidLength, - IsValid: false, + Code: "102773924", + Error: models.ErrInvalidLength, }, { - Code: "10277392447411231", - Error: models.ErrInvalidLength, - IsValid: false, + Code: "10277392447411231", + Error: models.ErrInvalidLength, }, } for i, tc := range testCases { @@ -65,41 +60,57 @@ func TestValidate(t *testing.T) { testCases := []testCase{ { - Code: "102773??44741", - Error: models.ErrInvalidValue, - IsValid: false, + Code: "102773??44741", + Error: models.ErrInvalidValue, }, { - Code: "1027739244742", - Error: nil, - IsValid: false, + Code: "1027739244742", }, { - Code: "10@7739244%42", - Error: models.ErrInvalidValue, - IsValid: false, + Code: "10@7739244%42", + Error: models.ErrInvalidValue, }, { Code: "1027700132195", - Error: nil, IsValid: true, }, { Code: "1027739244741", - Error: nil, IsValid: true, }, } - for _, test := range testCases { - isValid, err := Validate(test.Code) - assert.Equal(t, test.IsValid, isValid, test.Code, test.IsValid) - assert.Equal(t, true, errors.Is(test.Error, err), test.Code) + + for i, tc := range testCases { + tc := tc + + isValid, err := Validate(tc.Code) + assert.Equal(t, tc.IsValid, isValid, tc.Code) + if err != nil { + assert.ErrorAs(t, err, &tc.Error, fmt.Sprintf("invalid test case %d: input: %s", i, tc.Code)) + } else { + assert.Empty(t, err, fmt.Sprintf("invalid test case %d: input: %s", i, tc.Code)) + } } }) } func Test_Generate(t *testing.T) { - require.Panics(t, func() { + for i := 0; i < 10; i++ { + ogrn := Generate() + isValid, err := Validate(ogrn) + require.NoError(t, err, fmt.Sprintf("invalid ogrn value: %s", ogrn)) + + assert.True(t, isValid) + } +} + +func BenchmarkValidateCorrect(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = Validate("1027700132195") + } +} +func BenchmarkGenerate(b *testing.B) { + for i := 0; i < b.N; i++ { Generate() - }) + } } diff --git a/ogrnip/ogrnip.go b/ogrnip/ogrnip.go index 435dccc..7cb260f 100644 --- a/ogrnip/ogrnip.go +++ b/ogrnip/ogrnip.go @@ -1,35 +1,22 @@ package ogrnip import ( - "strconv" + "fmt" - "github.com/sshaplygin/docs-code/models" - "github.com/sshaplygin/docs-code/utils" + "github.com/sshaplygin/docs-code/ogrn" ) // Validate check to valid OGRNIP format // example: input format is 304500116000157 func Validate(ogrnip string) (bool, error) { - if len(ogrnip) != 15 { - return false, &models.CommonError{ - Method: packageName, - Err: models.ErrInvalidLength, - } - } - - ogrnipArr, err := utils.StrToArr(ogrnip) + ogrnData, err := ogrn.ParseOGRN(ogrn.Physical, ogrnip) if err != nil { - return false, err - } - - if ogrnipArr[0] != 3 && ogrnipArr[0] != 4 { - return false, models.ErrInvalidValue + return false, fmt.Errorf("parse %s model: %w", packageName, err) } - code, _ := strconv.Atoi(ogrnip[:len(ogrnip)-1]) - return ogrnipArr[len(ogrnip)-1] == code%13%10, nil + return ogrnData.IsValid() } func Generate() string { - panic("not implemented!") + return ogrn.NewOGRN(ogrn.Physical).String() } diff --git a/ogrnip/ogrnip_test.go b/ogrnip/ogrnip_test.go index d879bd1..ca4b3b6 100644 --- a/ogrnip/ogrnip_test.go +++ b/ogrnip/ogrnip_test.go @@ -104,7 +104,22 @@ func TestValidate(t *testing.T) { } func Test_Generate(t *testing.T) { - require.Panics(t, func() { + for i := 0; i < 10; i++ { + ogrnip := Generate() + isValid, err := Validate(ogrnip) + require.NoError(t, err, fmt.Sprintf("invalid ogrnip value: %s", ogrnip)) + + assert.True(t, isValid) + } +} + +func BenchmarkValidateCorrect(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = Validate("304500116000157") + } +} +func BenchmarkGenerate(b *testing.B) { + for i := 0; i < b.N; i++ { Generate() - }) + } } diff --git a/types.go b/types.go index 26ccfac..4075b3f 100644 --- a/types.go +++ b/types.go @@ -6,4 +6,6 @@ const ( BIK DocType = iota INN KPP + OGRN + OGRNIP ) diff --git a/utils/helpers.go b/utils/helpers.go index 04ac1a6..cef0a99 100644 --- a/utils/helpers.go +++ b/utils/helpers.go @@ -31,8 +31,7 @@ func Random(min, max int) int { randomNumber, err := rand.Int(rand.Reader, big.NewInt(int64(max-min+1))) if err != nil { - fmt.Println("Error generating random number:", err) - return 0 + panic(fmt.Errorf("generate random number: %w", err)) } return int(randomNumber.Int64()) + min @@ -82,7 +81,7 @@ func StrCode(val, length int) string { n := length if len(code) > length { - panic("invalid int code length") + panic(fmt.Sprintf("invalid int code length: %d, %d", len(code), length)) } str.Grow(n) @@ -94,3 +93,11 @@ func StrCode(val, length int) string { return str.String() } + +func FillSlice(from, to []int, fromIdx int) { + idx := fromIdx + for i := len(from) - 1; i >= 0; i-- { + to[idx] = from[i] + idx-- + } +} diff --git a/validate.go b/validate.go index 0c96826..ccde492 100644 --- a/validate.go +++ b/validate.go @@ -4,6 +4,8 @@ import ( "github.com/sshaplygin/docs-code/bik" "github.com/sshaplygin/docs-code/inn" "github.com/sshaplygin/docs-code/kpp" + "github.com/sshaplygin/docs-code/ogrn" + "github.com/sshaplygin/docs-code/ogrnip" ) type ValidateFunc func(code string) (bool, error) @@ -17,6 +19,10 @@ func Validate(docType DocType, code string) (bool, error) { callFunc = inn.Validate case KPP: callFunc = kpp.Validate + case OGRN: + callFunc = ogrn.Validate + case OGRNIP: + callFunc = ogrnip.Validate } if callFunc == nil {