github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/util/math.go (about)

     1  package util
     2  
     3  import (
     4  	"strconv"
     5  )
     6  
     7  type ModFunc int
     8  
     9  const (
    10  	MOD10 ModFunc = 1 + iota
    11  	MOD11
    12  )
    13  
    14  //mod11 calculate Mod11 DV from string
    15  func mod11(valueSequence string, baseNum ...int) int {
    16  	base := 9
    17  	digit := 0
    18  	sum := 0
    19  	weight := 2
    20  
    21  	var values []int
    22  
    23  	if baseNum != nil {
    24  		base = baseNum[0]
    25  	}
    26  
    27  	for _, r := range valueSequence {
    28  		c := string(r)
    29  		n, _ := strconv.Atoi(c)
    30  		values = append(values, n)
    31  	}
    32  	for i := len(values) - 1; i >= 0; i-- {
    33  		sum += values[i] * weight
    34  
    35  		if weight < base {
    36  			weight = weight + 1
    37  		} else {
    38  			weight = 2
    39  		}
    40  	}
    41  	digit = 11 - (sum % 11)
    42  	return digit
    43  }
    44  
    45  //mod10 calculate Mod10 DV from string
    46  func mod10(valueSequence string) int {
    47  	sum := 0
    48  
    49  	multiplyByTwo := true
    50  
    51  	for i := len(valueSequence) - 1; i >= 0; i-- {
    52  		c := string(valueSequence[i])
    53  
    54  		num, _ := strconv.Atoi(c)
    55  
    56  		if multiplyByTwo {
    57  			num = num * 2
    58  			sum += (num / 10) + (num % 10)
    59  			multiplyByTwo = false
    60  		} else {
    61  			sum += num
    62  			multiplyByTwo = true
    63  		}
    64  	}
    65  
    66  	remainder := sum % 10
    67  
    68  	if remainder == 0 {
    69  		return 0
    70  	}
    71  
    72  	return 10 - remainder
    73  }
    74  
    75  //OurNumberDv calculate DV from OurNumber
    76  func OurNumberDv(valueSequence string, modFunc ModFunc, base ...int) string {
    77  	digit := 0
    78  
    79  	if modFunc == MOD10 {
    80  		digit = mod10(valueSequence)
    81  	} else if modFunc == MOD11 && base != nil {
    82  		digit = mod11(valueSequence, base[0])
    83  	} else if modFunc == MOD11 {
    84  		digit = mod11(valueSequence)
    85  	}
    86  
    87  	if base != nil && digit == 10 {
    88  		return "P"
    89  	} else if digit > 9 {
    90  		digit = 0
    91  	}
    92  	return strconv.Itoa(digit)
    93  }
    94  
    95  //BarcodeDv calculate DV from barcode
    96  func BarcodeDv(valueSequence string) string {
    97  	digit := mod11(valueSequence)
    98  	if digit <= 1 || digit > 9 {
    99  		digit = 1
   100  	}
   101  	return strconv.Itoa(digit)
   102  }