diff options
author | George Abbott <george@gabbott.dev> | 2023-11-03 19:39:48 +0000 |
---|---|---|
committer | George Abbott <george@gabbott.dev> | 2023-11-03 19:39:48 +0000 |
commit | f64b83de5e28a038d47d11c325ebd292adc70ceb (patch) | |
tree | 5b19a4553ae963b5f3f290dac87acac5e174f75f /main.go |
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 188 |
1 files changed, 188 insertions, 0 deletions
@@ -0,0 +1,188 @@ +package main + +import ( + "fmt" + "strconv" + "os" + "time" + // "path/filepath" + xl "anyxcelize" + // "git.gabbott.dev/george/excelize/v2" + st "saggytrousers" + bt "badtudexo" +) + +func usage() { + fmt.Println(`bt-eqpct: check fields calculated from percentages +Usage: + bt-eqpct FILE -b BASE -p PERCENT -r RESULT -t TOLERANCE + -s SHEET -o OUTPUT +As an example, -b can be a price, -p can be discount %, and -r discount value. +Then it is calculated: BASE * (PERCENT ± TOLERANCE), and checked if RESULT is +in this range. This checks the discount amount is always within the tolerance +of what the percentage should be; if out, either the percentage or the value +(either -p or -r) are probably wrong and need correcting in the data. + +The fields -b, -p and -r are required. If they are not passed, they will be +prompted for. The function Locate() is used to find these and is passed the +strings you passed in as params. +`) + os.Exit(0) +} + +func parseArgs(args []string) { + if len(args) < 2 { + usage() + } + + for i := 0; i < len(args); i++ { + arg := args[i] + switch arg { + case "--help", "-h", "help", "helpme": + usage() + + case "-b", "--base": + i++ + base = args[i] + case "-p", "--pct", "--percent", "--percentage": + i++ + percent = args[i] + case "-r", "--result": + i++ + result = args[i] + case "-t", "--tol", "--tolerance": + i++ + t, err := strconv.ParseFloat(args[i], 64) + if err != nil { + fmt.Printf("Tolerance passed with -t could not be parsed into a float64\n") + os.Exit(-1) + } + tol = t + + case "-s", "--sheet": + i++ + sheet = args[i] + + case "--time", "--timings": + timeme = true + case "-o", "--out", "--output": + i++ + out = args[i] + case "-v", "--verbose": + verbose = true + + default: + filename = arg + } + } +} + +// Constants +const ToleranceNotSetValue float64 = 420.69 + +// Globals +var base string +var percent string +var result string +var tol float64 = ToleranceNotSetValue +var timeme bool = false +var verbose bool = false +var out string +var sheet string +var filename string + + +func main() { + args := os.Args + parseArgs(args) + + file, err := xl.OpenFile(filename) + if err != nil { + fmt.Printf("Cannot open file [%s], err [%v].\n", filename, err) + return + } + + /* Ask user to select the sheet */ + sheet = st.SelectSheet(file, sheet) + + /* Try find base, percent, result rows, else prompt for them */ + header := st.GetHeader(file, sheet) + baseIdx := bt.LocateOrAsk(header, base, "Please choose the base: ") + percentIdx := bt.LocateOrAsk(header, percent, "Please choose the percent: ") + resultIdx := bt.LocateOrAsk(header, result, "Please choose the resultant value: ") + if tol == ToleranceNotSetValue { + tol = st.GetFloat64("Please set the tolerance: ") + } + + if verbose { + fmt.Printf("base index: %v\n", baseIdx) + fmt.Printf("percent index: %v\n", percentIdx) + fmt.Printf("result index: %v\n", resultIdx) + } + + /* Now load all rows in. */ + st.Log(verbose, "Loading rows...") + loadStart := time.Now() + rows := st.GetRows(file, sheet) // panics if fails, which is ok + loadTime := time.Since(loadStart) + st.Log(verbose, " done!\n") + + /* Get columns from rows as []float64 for call to EqPct. */ + var wasError bool = false + start := time.Now() + db, err := st.DowncastF64(st.TransmogrifyRows(rows, baseIdx)) + if err != nil { + wasError = true + fmt.Printf("%v\n", err) + } + dp, err := st.DowncastF64(st.TransmogrifyRows(rows, percentIdx)) + if err != nil { + wasError = true + fmt.Printf("%v\n", err) + } + dr, err := st.DowncastF64(st.TransmogrifyRows(rows, resultIdx)) + if err != nil { + wasError = true + fmt.Printf("%v\n", err) + } + st.Log(verbose, "About to call bt.EqPct.\n") + + if len(db) != len(dp) || len(dp) != len(dr) { + st.ErrLog(verbose, + fmt.Sprintf("Length mismatch: db = %v, dp = %v, dr = %v", + len(db), len(dp), len(dr))) + } else { + st.Log(verbose, fmt.Sprintf("Lengths are %v\n", len(db))) + } + + indexes, err := bt.EqPct(db, dp, dr, tol) + if err != nil { + wasError = true + fmt.Printf("There was an error [%v]\n", err) + os.Exit(-1) + } + st.Log(verbose, "bt.EqPct completed successfully.\n") + end := time.Since(start) + // lenMax := len(string(len(db))) + for _, v := range indexes { + st.Log(true, fmt.Sprintf("%7v: %v * %v pct should be %v but found %v.\n", + v, + db[v], + dp[v], + (db[v] * dp[v])/100.00, + dr[v])) + } + if verbose { + fmt.Printf("base index: %v\n", baseIdx) + fmt.Printf("percent index: %v\n", percentIdx) + fmt.Printf("result index: %v\n", resultIdx) + } + + if timeme { + fmt.Printf("Time to load: %v\n", loadTime) + fmt.Printf("Time to process: %v\n", end) + } + if verbose { + fmt.Printf("Was error: %v\n", wasError) + } +} |