100 lines
2.9 KiB
Go

package cmd
import (
"fmt"
"log/slog"
"math"
"slices"
"github.com/fatih/color"
"github.com/rodaine/table"
"github.com/spf13/cobra"
"kryddan.xyz/bookkeep/process"
"kryddan.xyz/bookkeep/vismaparse"
)
func printFaults(faults []process.FaultyOutlay) {
headerFmt := color.New(color.FgGreen, color.Underline).SprintfFunc()
columnFmt := color.New(color.FgYellow).SprintfFunc()
tbl := table.New("Verification", "Description", "Related Verf.", "Error").
WithPadding(2).
WithHeaderFormatter(headerFmt).
WithFirstColumnFormatter(columnFmt)
totalChange := 0
for _, fault := range faults {
localChange := fault.Row.Debet - fault.Row.Kredit
totalChange += localChange
localDecimal := int(math.Max(float64(localChange%100), float64(-localChange%100)))
difference := fmt.Sprintf("%6d.%02d", localChange/100, localDecimal)
description := fault.Row.Description
if len(description) > 80 {
description = description[:76] + "..."
}
if len(fault.ContributingVerifications) == 0 {
tbl.AddRow(fault.Row.Verification, description, "", difference)
} else {
tbl.AddRow(fault.Row.Verification, description, fault.ContributingVerifications, difference)
}
}
totalDecimal := int(math.Max(float64(totalChange%100), float64(-totalChange%100)))
totalChangeString := fmt.Sprintf("%6d.%02d", totalChange/100, totalDecimal)
tbl.AddRow("Total", "", "", totalChangeString)
tbl.Print()
}
func OutlayCmd() *cobra.Command {
unitsFlagName := "unit"
accountNumberFlagName := "account"
cmd := &cobra.Command{
Use: "outlays [file]",
Short: "This command analyses outlays in the provided file",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
filePath := args[0]
units, err := cmd.Flags().GetStringArray(unitsFlagName)
if err != nil {
slog.Error("get --units flag", slog.Any("err", err))
}
accountNumber, err := cmd.Flags().GetInt(accountNumberFlagName)
if err != nil {
slog.Error("get --units flag", slog.Any("err", err))
}
org, err := vismaparse.LoadSheet(filePath)
if err != nil {
slog.Error("load sheet failed", slog.Any("err", err))
return err
}
for _, account := range org.Accounts {
if account.AccountNumber == accountNumber {
change := 0
for unit, perUnitAccount := range process.PerOrgUnit(account) {
if len(units) != 0 && !slices.Contains(units, unit) {
continue
}
faults, ok := process.ValidateOutlays(perUnitAccount)
if ok {
continue
}
fmt.Printf("\n----- Faulty verifications in %s -----\n", unit)
for _, fault := range faults {
change += fault.Row.Debet
change -= fault.Row.Kredit
}
printFaults(faults)
}
}
}
return nil
},
}
cmd.Flags().StringArray(unitsFlagName, []string{""}, "The organizational units to analyse. Omit to include all")
cmd.Flags().Int(accountNumberFlagName, 2820, "The account number which tracks outlays")
return cmd
}