69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package invoice
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
func generateReference() string {
|
|
// 1) Build the 26-digit payload from time + random suffix
|
|
now := time.Now().UTC()
|
|
ts := now.Format("20060102150405") // YYYYMMDDHHMMSS -> 14 chars
|
|
ns := now.Nanosecond() // 0..999999999
|
|
// format nanoseconds as 9 digits, zero padded
|
|
nsStr := fmt.Sprintf("%09d", ns)
|
|
|
|
// 3-digit random suffix (000..999) to reach 26 digits
|
|
randBytes := make([]byte, 2) // we'll read 2 bytes and map to 0..999
|
|
rand.Read(randBytes)
|
|
|
|
// convert to number 0..65535 then mod 1000
|
|
rnum := int(randBytes[0])<<8 | int(randBytes[1])
|
|
rnum = rnum % 1000
|
|
randStr := fmt.Sprintf("%03d", rnum)
|
|
|
|
// compose 26-digit payload: 14 + 9 + 3 = 26
|
|
payload := ts + nsStr + randStr
|
|
|
|
// Safety: ensure payload is 26 digits (should always be true)
|
|
if len(payload) != 26 {
|
|
panic(fmt.Errorf("internal error: payload length %d != 26", len(payload)))
|
|
}
|
|
|
|
// 2) Compute Modulo-10 recursive check digit
|
|
check := mod10RecursiveChecksum(payload)
|
|
|
|
// 3) Build full 27-digit reference
|
|
full := payload + fmt.Sprintf("%d", check)
|
|
|
|
// 4) Format with grouping: 2-5-5-5-5-5
|
|
formatted := fmt.Sprintf("%s %s %s %s %s %s",
|
|
full[0:2],
|
|
full[2:7],
|
|
full[7:12],
|
|
full[12:17],
|
|
full[17:22],
|
|
full[22:27],
|
|
)
|
|
return formatted
|
|
}
|
|
|
|
// mod10RecursiveChecksum computes the Mod10 recursive check digit for a numeric string.
|
|
// Implements the table-based recursive mod10 described in Swiss Annex B / ISR implementations.
|
|
func mod10RecursiveChecksum(digits string) int {
|
|
// table as used in ISR/QR implementations
|
|
arrTable := [10]int{0, 9, 4, 6, 8, 2, 7, 1, 3, 5}
|
|
carry := 0
|
|
for i := 0; i < len(digits); i++ {
|
|
ch := digits[i]
|
|
// assume digits are ASCII '0'..'9'
|
|
n := int(ch - '0')
|
|
// update carry
|
|
idx := (carry + n) % 10
|
|
carry = arrTable[idx]
|
|
}
|
|
// final check digit
|
|
return (10 - carry) % 10
|
|
}
|