biz/inns/main.go

200 lines
3.2 KiB
Go
Raw Normal View History

2024-03-27 10:51:48 +03:00
package inns
// The package implements the basic
// Russian Federation INN format
// storing it in int64 to keep
// searching and storing as
// quick as possible.
import (
"strings"
"unicode"
"strconv"
"fmt"
"slices"
)
2024-05-31 16:58:28 +03:00
type Type uint8
2024-03-27 10:51:48 +03:00
const (
2024-05-31 16:58:28 +03:00
TypeIncorrect Type = iota
TypeLegal
TypeIndividual
2024-03-27 10:51:48 +03:00
)
2024-05-31 16:58:28 +03:00
2024-03-27 10:51:48 +03:00
func removeSpaces(s string) string {
return strings.Map(func(r rune) rune{
if unicode.IsSpace(r) {
return -1
}
return r
}, s)
}
2024-05-31 16:58:28 +03:00
type INN int64
2024-03-27 10:51:48 +03:00
2024-05-31 16:58:28 +03:00
func NewFromInt64(innRaw int64) (INN, error) {
inn := INN(innRaw)
2024-03-27 10:51:48 +03:00
if !inn.isCorrectLen() {
2024-05-31 16:58:28 +03:00
return -1, ErrIncorrectLen
2024-03-27 10:51:48 +03:00
}
if !inn.isSumCorrect() {
2024-05-31 16:58:28 +03:00
return -1, ErrSumsNotMatch
2024-03-27 10:51:48 +03:00
}
return inn, nil
}
2024-05-31 16:58:28 +03:00
func (inn INN) IsCorrect() bool {
_, err := NewFromInt64(int64(inn))
return err == nil
}
2024-03-27 10:51:48 +03:00
// Convert string with spaces into the INN
// and return error if anything is wrong with it.
2024-05-31 16:58:28 +03:00
func NewFromStr(str string) (INN, error) {
2024-03-27 10:51:48 +03:00
str = removeSpaces(str)
innRaw, err := strconv.ParseInt(str, 10, 64)
if err != nil {
2024-05-31 16:58:28 +03:00
return -1, ErrIncorrectFormat
2024-03-27 10:51:48 +03:00
}
return NewFromInt64(innRaw)
}
2024-05-31 16:58:28 +03:00
func (inn INN) Type() Type {
2024-03-27 10:51:48 +03:00
ln := inn.length()
switch ln {
case 9, 10:
2024-05-31 16:58:28 +03:00
return TypeLegal
2024-03-27 10:51:48 +03:00
case 11, 12:
2024-05-31 16:58:28 +03:00
return TypeIndividual
2024-03-27 10:51:48 +03:00
}
2024-05-31 16:58:28 +03:00
return TypeIncorrect
2024-03-27 10:51:48 +03:00
}
2024-05-31 16:58:28 +03:00
func (inn INN) length() int {
2024-03-27 10:51:48 +03:00
ln := 0
for {
if inn == 0 {
break
}
inn /= 10
ln++
}
if ln == 9 || ln == 11 {
ln++
}
return ln
}
2024-05-31 16:58:28 +03:00
func (inn INN) isCorrectLen() bool {
2024-03-27 10:51:48 +03:00
ln := inn.length()
if ln == 9 || ln == 11 {
ln++
}
return ln == 10 || ln == 12
}
var (
// Koefs for the control sum.
innSum10 = [9]int64{
2, 4, 10, 3, 5, 9, 4, 6, 8,
}
innSum11 = [10]int64{
7, 2, 4, 10, 3, 5, 9, 4, 6, 8,
}
innSum12 = [11]int64{
3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8,
}
)
// Get the integer representation of digits in string INN.
2024-05-31 16:58:28 +03:00
func (inn INN) digits() []int64 {
2024-03-27 10:51:48 +03:00
ln := inn.length()
v := int64(inn)
ret := make([]int64, ln)
for i := 0 ; i<ln ; i++{
ret[i] = v % 10
v /= 10
}
slices.Reverse(ret)
return ret
}
//
2024-05-31 16:58:28 +03:00
func (inn INN) specifiedSum() int64 {
2024-03-27 10:51:48 +03:00
ln := inn.length()
v := int64(inn)
switch ln {
case 10:
return v%10
case 12:
return v%100
default:
return -1
}
}
// Returns the supposed control sum rune. (the last number)
2024-05-31 16:58:28 +03:00
func (inn INN) sum() int64 {
2024-03-27 10:51:48 +03:00
d := inn.digits()
ln := inn.length()
switch ln {
case 10 :
var n10 int64
for i, ni := range d[:9] {
n10 += innSum10[i] * ni
}
n10 = (n10 % 11) % 10
return n10
case 12 :
var n11 int64
for i, ni := range d[:10] {
n11 += innSum11[i] * ni
}
n11 = (n11 % 11) % 10
var n12 int64
for i, ni := range d[:10] {
n12 += innSum12[i] * ni
}
n12 += innSum12[10] * n11
n12 = (n12 % 11) % 10
return n11*10 + n12
}
return -1
}
2024-05-31 16:58:28 +03:00
func (inn INN) isSumCorrect() bool {
2024-03-27 10:51:48 +03:00
return inn.specifiedSum() == inn.sum()
}
2024-05-31 16:58:28 +03:00
func (inn INN) String() string {
2024-03-27 10:51:48 +03:00
return fmt.Sprintf("%d", inn)
}
// Fancy way to print INN with space delimiters.
2024-05-31 16:58:28 +03:00
func (inn INN) Fancy() string {
2024-03-27 10:51:48 +03:00
ln := inn.length()
str := fmt.Sprintf("%d", inn)
// Adding zero depending on length.
if len(str) == 9 || len(str) == 11 {
str = "0"+str
}
switch ln {
case 10 :
return fmt.Sprintf("%s %s %s", str[:4], str[4:9], str[9:])
case 12 :
return fmt.Sprintf("%s %s %s", str[:4], str[4:10], str[10:])
}
// Reaching the point if the length is incorrect.
2024-05-31 16:58:28 +03:00
return "<"+ErrIncorrectLen.Error()+">"
2024-03-27 10:51:48 +03:00
}