package bik
import (
"strconv"
ru_doc_code "github.com/sshaplygin/ru-doc-code"
)
// Validate check to valid BIK format
// example valid format is 044525225
func Validate(bik string) (bool, error) {
if len(bik) != 9 {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
bikArr, err := ru_doc_code.StrToArr(bik)
if err != nil {
return false, err
}
if bikArr[0] != 0 || bikArr[1] != 4 {
return false, ru_doc_code.ErrInvalidBIKCountryCode
}
// special code
if bikArr[6] == 0 && bikArr[7] == 1 && bikArr[8] == 2 {
return true, nil
}
latestTriadStr := bik[6:]
code, _ := strconv.Atoi(latestTriadStr)
return code >= 50 && code < 1000, nil
}
package ru_doc_code
import (
"errors"
"fmt"
"path/filepath"
"runtime"
"strings"
)
var (
// ErrInvalidLength invalid input document code length
ErrInvalidLength = errors.New("invalid length")
// ErrInvalidFormattedSNILSLength invalid formatted length of snils
ErrInvalidFormattedSNILSLength = errors.New("invalid formatted snils length")
// ErrRegistrationReasonCode invalid registration reason code
ErrRegistrationReasonCode = errors.New("invalid registration reason code")
// ErrInvalidValue invalid input value
ErrInvalidValue = errors.New("invalid code value")
// ErrInvalidBIKCountryCode invalid bik code country
ErrInvalidBIKCountryCode = errors.New("invalid bik country code")
// ErrNotImplemented not implemented method error
ErrNotImplemented = errors.New("method does not implemented")
)
// CommonError common error wrapped base error
type CommonError struct {
Method string
Err error
}
func (c *CommonError) Error() string {
return fmt.Sprintf("%s: %s", c.Method, c.Err.Error())
}
// GetModuleName get package name in runtime
func GetModuleName() (string, error) {
pc, _, _, ok := runtime.Caller(1)
if !ok {
return "", errors.New("invalid runtime caller")
}
parts := strings.Split(runtime.FuncForPC(pc).Name(), ".")
pl := len(parts)
pathArr := strings.Split(parts[pl-2], string(filepath.Separator))
if len(pathArr) == 0 {
return "", errors.New("invalid path length")
}
pkgName := pathArr[len(pathArr)-1]
return pkgName, nil
}
package ru_doc_code
import (
"crypto/rand"
"math/big"
"strconv"
"strings"
)
func RandomDigits(len int) int64 {
if len <= 0 {
len = 1
}
max, _ := strconv.Atoi(strings.Repeat("9", len))
min, _ := strconv.Atoi("1" + strings.Repeat("0", len-1))
num, _ := rand.Int(rand.Reader, big.NewInt(int64(max-min+1)))
return num.Int64() + int64(min)
}
func StrToArr(str string) ([]int, error) {
numbers := strings.Split(str, "")
arr := make([]int, 0, len(numbers))
for _, number := range numbers {
number, err := strconv.Atoi(number)
if err != nil {
return nil, ErrInvalidValue
}
arr = append(arr, number)
}
return arr, nil
}
package inn
import (
"strconv"
"strings"
ru_doc_code "github.com/sshaplygin/ru-doc-code"
)
const (
lengthLegal = 10
lengthPhysical = 12
)
type INN struct {
Code ru_doc_code.TaxRegionCode
SerialNumber ru_doc_code.SerialNumber
Hash10 uint
Hash11 uint
Hash12 uint
}
// Validate check to valid inn from input string.
// example: input format is 7707083893
func Validate(inn string) (bool, error) {
if len(inn) != lengthLegal && len(inn) != lengthPhysical {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
innArr, err := transformInn(inn)
if err != nil {
return false, err
}
if len(inn) == 10 {
return hash10(innArr) == innArr[len(innArr)-1], nil
}
return hash11(innArr) == innArr[len(innArr)-2] && hash12(innArr) == innArr[len(innArr)-1], nil
}
// GenerateLegal generate legal type inn string value.
func GenerateLegal() string {
inn := strconv.FormatInt(ru_doc_code.RandomDigits(9), 10)
innArr, _ := transformInn(inn)
return inn + strconv.Itoa(hash10(innArr))
}
// GeneratePhysical generate physical type inn string value.
func GeneratePhysical() string {
inn := strconv.FormatInt(ru_doc_code.RandomDigits(10), 10)
innArr, _ := transformInn(inn)
hash1Num := hash11(innArr)
innArr = append(innArr, hash1Num)
return strings.Join([]string{
inn,
strconv.Itoa(hash1Num),
strconv.Itoa(hash12(innArr)),
}, "")
}
func transformInn(inn string) ([]int, error) {
innNumbers := strings.Split(inn, "")
innArr := make([]int, 0, len(inn))
for _, str := range innNumbers {
number, err := strconv.Atoi(str)
if err != nil {
return nil, ru_doc_code.ErrInvalidValue
}
innArr = append(innArr, number)
}
return innArr, nil
}
// Generate generate random type inn string value.
func Generate() string {
if ru_doc_code.RandomDigits(1)%2 == 1 {
return GeneratePhysical()
}
return GenerateLegal()
}
// IsEntrepreneur check inn for Entrepreneur type
func IsEntrepreneur(inn string) bool {
return len(inn) == lengthPhysical
}
// IsCompany check inn for Company type
func IsCompany(inn string) bool {
return len(inn) == lengthLegal
}
func hash10(innArr []int) int {
return ((2*innArr[0] + 4*innArr[1] + 10*innArr[2] + 3*innArr[3] +
5*innArr[4] + 9*innArr[5] + 4*innArr[6] + 6*innArr[7] + 8*innArr[8]) % 11) % 10
}
func hash11(innArr []int) int {
return ((7*innArr[0] + 2*innArr[1] + 4*innArr[2] + 10*innArr[3] + 3*innArr[4] +
5*innArr[5] + 9*innArr[6] + 4*innArr[7] + 6*innArr[8] + 8*innArr[9]) % 11) % 10
}
func hash12(innArr []int) int {
return ((3*innArr[0] + 7*innArr[1] + 2*innArr[2] + 4*innArr[3] +
10*innArr[4] + 3*innArr[5] + 5*innArr[6] + 9*innArr[7] + 4*innArr[8] +
6*innArr[9] + 8*innArr[10]) % 11) % 10
}
package kpp
import ru_doc_code "github.com/sshaplygin/ru-doc-code"
type KPP struct {
Code ru_doc_code.TaxRegionCode
Reason ru_doc_code.ReasonRegistration
SerialNumber ru_doc_code.SerialNumber
}
// Validate check to valid KPP format
// example: input format is 773643301
func Validate(kpp string) (bool, error) {
if len(kpp) != 9 {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
_, err := ru_doc_code.StrToArr(kpp)
if err != nil {
return false, err
}
// todo: validate tax region/office ru_doc_code.TaxRegionCode(kpp[:4])
_, ok := ru_doc_code.SupportedRegistrationReasonSet[ru_doc_code.RegistrationReasonCode(kpp[4:6])]
if !ok {
return false, ru_doc_code.ErrRegistrationReasonCode
}
return true, nil
}
package ogrn
import (
"strconv"
ru_doc_code "github.com/sshaplygin/ru-doc-code"
)
// Validate check to valid OGRN format
// example: input format is 1027700132195
func Validate(ogrn string) (bool, error) {
if len(ogrn) != 13 {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
ogrnArr, err := ru_doc_code.StrToArr(ogrn)
if err != nil {
return false, err
}
code, _ := strconv.Atoi(ogrn[:12])
return ogrnArr[len(ogrn)-1] == code%11%10, nil
}
package ogrnip
import (
"strconv"
ru_doc_code "github.com/sshaplygin/ru-doc-code"
)
// Validate check to valid OGRNIP format
// example: input format is 304500116000157
func Validate(ogrnip string) (bool, error) {
if len(ogrnip) != 15 {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
ogrnipArr, err := ru_doc_code.StrToArr(ogrnip)
if err != nil {
return false, err
}
if ogrnipArr[0] != 3 && ogrnipArr[0] != 4 {
return false, ru_doc_code.ErrInvalidValue
}
code, _ := strconv.Atoi(ogrnip[:len(ogrnip)-1])
return ogrnipArr[len(ogrnip)-1] == code%13%10, nil
}
package okato
import ru_doc_code "github.com/sshaplygin/ru-doc-code"
// Validate check to valid OKATO format
// example: input format is 17205000000
func Validate() (bool, error) {
return false, ru_doc_code.ErrNotImplemented
}
package oktmo
import ru_doc_code "github.com/sshaplygin/ru-doc-code"
// Validate check to valid OKTMO format
// example: input format is 17605101
func Validate() (bool, error) {
return false, ru_doc_code.ErrNotImplemented
}
package snils
import (
"strconv"
"strings"
ru_doc_code "github.com/sshaplygin/ru-doc-code"
)
// Validate check to valid SNILS format
// example: input format is 112-233-445 95
func Validate(snils string) (bool, error) {
if len(snils) != 14 {
name, err := ru_doc_code.GetModuleName()
if err != nil {
return false, err
}
return false, &ru_doc_code.CommonError{
Method: name,
Err: ru_doc_code.ErrInvalidLength,
}
}
fSnils := strings.ReplaceAll(snils, "-", "")
fSnils = strings.ReplaceAll(fSnils, " ", "")
if len(fSnils) != 11 {
return false, ru_doc_code.ErrInvalidFormattedSNILSLength
}
snilsArr, err := ru_doc_code.StrToArr(fSnils)
if err != nil {
return false, err
}
hashSum := 0
hashLen := len(fSnils) - 2
code, _ := strconv.Atoi(fSnils[hashLen:])
for i, v := range snilsArr[:hashLen] {
hashSum += v * (hashLen - i)
}
return hashSum%101 == code, nil
}
// Generate generate random
func Generate() string {
return ""
}