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 }