2023-12-07 11:34:00 -05:00
package main
2023-12-07 16:54:12 -05:00
import (
"bufio"
"fmt"
"os"
2023-12-08 19:41:08 -05:00
"regexp"
2023-12-07 16:54:12 -05:00
"strconv"
"strings"
2023-12-08 13:22:19 -05:00
"github.com/pterm/pterm"
2023-12-09 11:43:09 -05:00
"github.com/schollz/progressbar/v3"
2023-12-07 16:54:12 -05:00
)
2023-12-07 11:34:00 -05:00
func main ( ) {
2023-12-08 20:00:21 -05:00
// Set Welcome Header
2023-12-08 19:05:29 -05:00
pterm . DefaultHeader . WithBackgroundStyle ( pterm . NewStyle ( pterm . BgCyan ) ) . WithTextStyle ( pterm . NewStyle ( pterm . FgCyan ) ) . Println ( "Welcome to Checkdigit Calculator" )
2023-12-08 13:07:47 -05:00
2023-12-08 20:00:21 -05:00
// Check what directory the commandline is on when the program is launched.
2023-12-07 16:54:12 -05:00
directory , err := os . Getwd ( )
Error ( err )
2023-12-08 20:00:21 -05:00
// Get name of file to be processed.
2023-12-09 11:51:31 -05:00
args := os . Args [ 1 : ]
var input string
if len ( args ) > 0 {
input = args [ 0 ]
} else {
pterm . Printf ( pterm . Cyan ( "What is the name of the file in this directory?: " ) )
reader := bufio . NewReader ( os . Stdin )
input , err = reader . ReadString ( '\n' )
Error ( err )
}
2023-12-07 16:54:12 -05:00
2023-12-08 20:00:21 -05:00
// Create upcs array and push all upc strings into it
2023-12-07 16:54:12 -05:00
input = strings . TrimSpace ( input )
file , err := os . Open ( input )
Error ( err )
var upcs [ ] string
scanner := bufio . NewScanner ( file )
for scanner . Scan ( ) {
upcs = append ( upcs , scanner . Text ( ) )
}
err = file . Close ( )
Error ( err )
if scanner . Err ( ) != nil {
fmt . Println ( scanner . Err ( ) )
}
2023-12-08 20:00:21 -05:00
// Create gtins array that will eventually be returned
2023-12-07 16:54:12 -05:00
var gtins [ ] string
2023-12-08 20:00:21 -05:00
// Using regex compile so the program stays fast
2023-12-08 19:41:08 -05:00
regex , err := regexp . Compile ( "[^0-9]" )
Error ( err )
2023-12-09 11:43:09 -05:00
checkBar := progressbar . NewOptions ( len ( upcs ) ,
progressbar . OptionEnableColorCodes ( true ) ,
progressbar . OptionSetDescription ( "[cyan][1/2][reset] Calculating Check Digits..." ) ,
progressbar . OptionSetTheme ( progressbar . Theme {
Saucer : "[green]=[reset]" ,
SaucerHead : "[green]>[reset]" ,
SaucerPadding : " " ,
BarStart : "[" ,
BarEnd : "]" ,
} ) )
2023-12-07 16:54:12 -05:00
for _ , upc := range upcs {
upcLength := len ( upc )
// Check Digit Formula
// Take all the digits in odd positions, add them and multiply by three
// Take all the digits in even positions (except for the last one) and add to the number you got above
// Divide that number by 10 and take the remainder
// If the remainder is not 0, subtract it from 10
2023-12-08 10:46:19 -05:00
//
// 12/8/2023: New git updates from https://www.gs1.org/services/how-calculate-check-digit-manually
2023-12-07 16:54:12 -05:00
oddNumber := 0
evenNumber := 0
var remainder int
2023-12-08 19:41:08 -05:00
checkForNonNumber := regex . MatchString ( upc )
if checkForNonNumber {
gtins = append ( gtins , upc )
continue
}
2023-12-08 10:46:19 -05:00
if upcLength < 8 {
gtins = append ( gtins , "Cannot process upcs less than 8 digits" )
2023-12-08 09:54:35 -05:00
continue
}
2023-12-08 10:46:19 -05:00
if upcLength > 17 {
gtins = append ( gtins , "Invalid barcode" )
continue
2023-12-08 09:54:35 -05:00
}
2023-12-08 10:46:19 -05:00
if upcLength % 2 == 0 {
for i , num := range upc {
if i % 2 != 0 {
convertedOddNumber , err := strconv . Atoi ( string ( num ) )
Error ( err )
convertedOddNumber = convertedOddNumber * 3
oddNumber += convertedOddNumber
} else {
if upcLength - 1 > i {
convertedEvenNumber , err := strconv . Atoi ( string ( num ) )
Error ( err )
evenNumber += convertedEvenNumber
}
}
}
} else {
for i , num := range upc {
if i % 2 == 0 {
convertedOddNumber , err := strconv . Atoi ( string ( num ) )
2023-12-07 16:54:12 -05:00
Error ( err )
2023-12-08 10:46:19 -05:00
convertedOddNumber = convertedOddNumber * 3
oddNumber += convertedOddNumber
} else {
if upcLength - 1 > i {
convertedEvenNumber , err := strconv . Atoi ( string ( num ) )
Error ( err )
evenNumber += convertedEvenNumber
}
2023-12-07 16:54:12 -05:00
}
}
}
remainder = ( oddNumber + evenNumber ) % 10
if remainder != 0 {
remainder = 10 - remainder
}
remainderString := strconv . Itoa ( remainder )
gtins = append ( gtins , upc + remainderString )
2023-12-09 11:43:09 -05:00
checkBar . Add ( 1 )
2023-12-07 16:54:12 -05:00
}
2023-12-09 11:43:09 -05:00
answerBar := progressbar . NewOptions ( len ( gtins ) ,
progressbar . OptionEnableColorCodes ( true ) ,
progressbar . OptionSetDescription ( "[cyan][2/2][reset] Writing answers into file..." ) ,
progressbar . OptionClearOnFinish ( ) ,
progressbar . OptionSetTheme ( progressbar . Theme {
Saucer : "[green]=[reset]" ,
SaucerHead : "[green]>[reset]" ,
SaucerPadding : " " ,
BarStart : "[" ,
BarEnd : "]" ,
} ) )
2023-12-08 20:00:21 -05:00
// Check if answer.txt already exists and if so, delete it
2023-12-07 16:54:12 -05:00
if _ , err := os . Stat ( directory + "/answer.txt" ) ; err == nil {
e := os . Remove ( directory + "/answer.txt" )
Error ( e )
}
2023-12-08 20:00:21 -05:00
// Create new answer.txt
2023-12-07 16:54:12 -05:00
answerFile , err := os . Create ( directory + "/answer.txt" )
Error ( err )
defer answerFile . Close ( )
2023-12-08 20:00:21 -05:00
// Fill the answers.txt file
2023-12-07 16:54:12 -05:00
for _ , gtin := range gtins {
_ , err := answerFile . WriteString ( gtin + "\n" )
Error ( err )
2023-12-09 11:43:09 -05:00
answerBar . Add ( 1 )
2023-12-07 16:54:12 -05:00
}
2023-12-08 13:07:47 -05:00
2023-12-08 20:00:21 -05:00
// Print Success message and exit
2023-12-08 19:07:53 -05:00
pterm . Printf ( "\n" )
2023-12-08 19:05:29 -05:00
pterm . Success . Println ( "The answer.txt file has been successfully generated with check digits." )
2023-12-08 20:00:21 -05:00
os . Exit ( 0 )
2023-12-07 11:34:00 -05:00
}