diff options
-rw-r--r-- | go.mod | 27 | ||||
-rw-r--r-- | go.sum | 63 | ||||
-rw-r--r-- | main.go | 188 |
3 files changed, 278 insertions, 0 deletions
@@ -0,0 +1,27 @@ +module bt-eqpct + +go 1.19 + +require ( + anyxcelize v0.0.0-00010101000000-000000000000 + badtudexo v0.0.0-00010101000000-000000000000 + saggytrousers v0.0.0-00010101000000-000000000000 +) + +require ( + git.gabbott.dev/george/excelize/v2 v2.99.1 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/richardlehane/mscfb v1.0.4 // indirect + github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect + github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/net v0.5.0 // indirect + golang.org/x/text v0.6.0 // indirect +) + +replace saggytrousers => ../saggytrousers + +replace anyxcelize => ../../anyxcelize + +replace badtudexo => ../badtudexo @@ -0,0 +1,63 @@ +git.gabbott.dev/george/excelize/v2 v2.99.1 h1:pencpuy3D+7TgEV+BraIj5SUSkcErop3Pes05CDp71M= +git.gabbott.dev/george/excelize/v2 v2.99.1/go.mod h1:JqW30EL316o52Ya+R3++QL7oW13PBwAqYVbSprqTVz4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= +github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= +github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c= +github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -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) + } +} |