Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b904c597b | |||
| e8cd6e2a91 | |||
| 5fdf2e7cb0 |
@@ -18,11 +18,24 @@ Tagesaldo -01:51:46
|
||||
= Sollzeit 07:53:00
|
||||
```
|
||||
|
||||
Ohne Argumente fragt das Programm die Zeiten interaktiv im Terminal ab. Dabei
|
||||
wird kein Webserver gestartet.
|
||||
Ohne Argumente zeigt das Programm nur die Hilfe an. Berechnet wird erst, wenn
|
||||
passende Werte uebergeben werden. Beim Tages-Saldo bitte `+` oder `-` angeben;
|
||||
eine Eingabe ohne Vorzeichen wird aus Kompatibilitaet als Minuszeit behandelt.
|
||||
|
||||
Kurze Zeiten wie `6:01` oder `01:52` sind ebenfalls erlaubt.
|
||||
|
||||
## Werte abfragen
|
||||
|
||||
```sh
|
||||
goTimecalc -a
|
||||
```
|
||||
|
||||
Oder ausgeschrieben:
|
||||
|
||||
```sh
|
||||
goTimecalc --ask
|
||||
```
|
||||
|
||||
## Netto-Zeit und Tages-Saldo
|
||||
|
||||
Der Tages-Saldo wird mit Vorzeichen angegeben: Minuszeit mit `-`, Pluszeit mit
|
||||
|
||||
@@ -56,6 +56,8 @@ func run(args []string, out io.Writer) error {
|
||||
flags.SetOutput(out)
|
||||
|
||||
var days dayList
|
||||
askInput := flags.Bool("a", false, "Werte interaktiv abfragen")
|
||||
flags.BoolVar(askInput, "ask", false, "Werte interaktiv abfragen")
|
||||
webInput := flags.Bool("web", false, "Optionales Webinterface lokal starten")
|
||||
addrInput := flags.String("addr", "127.0.0.1:8080", "Adresse fuer das Webinterface")
|
||||
nettoInput := flags.String("netto", "", "Netto-Zeit, z.B. 06:01 oder 06:01:14")
|
||||
@@ -72,6 +74,7 @@ func run(args []string, out io.Writer) error {
|
||||
flags.Usage = func() {
|
||||
fmt.Fprintln(out, "Nutzung:")
|
||||
fmt.Fprintln(out, " goTimecalc 06:01:14 01:51:46")
|
||||
fmt.Fprintln(out, " goTimecalc -a")
|
||||
fmt.Fprintln(out, " goTimecalc --netto 08:56:12 --saldo +01:03:12")
|
||||
fmt.Fprintln(out, " goTimecalc --brutto 09:26:12 --pause 00:30 --soll 07:53")
|
||||
fmt.Fprintln(out, " goTimecalc --start 08:00 --ende 16:30 --pause 00:30 --soll 07:53")
|
||||
@@ -82,6 +85,11 @@ func run(args []string, out io.Writer) error {
|
||||
flags.PrintDefaults()
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
flags.Usage()
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
if errors.Is(err, flag.ErrHelp) {
|
||||
return nil
|
||||
@@ -93,6 +101,10 @@ func run(args []string, out io.Writer) error {
|
||||
return errors.New("unbekannte Argumente. Hilfe mit: goTimecalc --help")
|
||||
}
|
||||
|
||||
if *askInput {
|
||||
return runAsk(os.Stdin, out)
|
||||
}
|
||||
|
||||
if *webInput {
|
||||
return startWebServer(*addrInput, out)
|
||||
}
|
||||
@@ -125,7 +137,25 @@ func run(args []string, out io.Writer) error {
|
||||
return runNettoSaldo(out, *nettoInput, *saldoInput, *minusInput)
|
||||
}
|
||||
|
||||
return runInteractive(out)
|
||||
flags.Usage()
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAsk(input io.Reader, out io.Writer) error {
|
||||
reader := bufio.NewReader(input)
|
||||
|
||||
netto, err := promptDuration(reader, out, "Netto-Zeit: ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
saldo, err := promptSaldo(reader, out, "Tagesaldo (+/-): ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printSollzeitFromSaldo(out, netto, saldo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runNettoSaldo(out io.Writer, nettoInput string, saldoInput string, minusInput string) error {
|
||||
@@ -220,29 +250,44 @@ func runDays(out io.Writer, days dayList, sollInput string) error {
|
||||
return printBalance(out, total, sollInput)
|
||||
}
|
||||
|
||||
func runInteractive(out io.Writer) error {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
netto, err := promptDuration(reader, "Netto-Zeit: ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minuszeit, err := promptDuration(reader, "Minuszeit: ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printSollzeitFromSaldo(out, netto, -minuszeit)
|
||||
return nil
|
||||
}
|
||||
|
||||
func printSollzeitFromSaldo(out io.Writer, netto int, saldo int) {
|
||||
fmt.Fprintf(out, "Netto-Zeit %8s\n", formatDuration(netto))
|
||||
fmt.Fprintf(out, "Tagesaldo %s\n", formatSignedDuration(saldo))
|
||||
fmt.Fprintf(out, "= Sollzeit %8s\n", formatDuration(netto-saldo))
|
||||
}
|
||||
|
||||
func promptDuration(reader *bufio.Reader, out io.Writer, label string) (int, error) {
|
||||
fmt.Fprint(out, label)
|
||||
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value, err := parseDuration(strings.TrimSpace(input))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s%w", strings.TrimSuffix(label, ": "), err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func promptSaldo(reader *bufio.Reader, out io.Writer, label string) (int, error) {
|
||||
fmt.Fprint(out, label)
|
||||
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value, err := parseSaldoInput(strings.TrimSpace(input))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s%w", strings.TrimSuffix(label, ": "), err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func printBruttoNetto(out io.Writer, brutto int, pause int, sollInput string) error {
|
||||
netto := brutto - pause
|
||||
if netto < 0 {
|
||||
@@ -296,22 +341,6 @@ func wantedSoll(input string) (int, bool, error) {
|
||||
return value, true, nil
|
||||
}
|
||||
|
||||
func promptDuration(reader *bufio.Reader, label string) (int, error) {
|
||||
fmt.Print(label)
|
||||
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value, err := parseDuration(strings.TrimSpace(input))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s%w", strings.TrimSuffix(label, ": "), err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func parseDuration(input string) (int, error) {
|
||||
parts := strings.Split(strings.TrimSpace(input), ":")
|
||||
if len(parts) < 2 || len(parts) > 3 {
|
||||
@@ -364,6 +393,23 @@ func parseSignedDuration(input string) (int, error) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func parseSaldoInput(input string) (int, error) {
|
||||
input = strings.TrimSpace(input)
|
||||
if input == "" {
|
||||
return 0, errors.New("Zeit fehlt")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(input, "+") || strings.HasPrefix(input, "-") {
|
||||
return parseSignedDuration(input)
|
||||
}
|
||||
|
||||
value, err := parseDuration(input)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return -value, nil
|
||||
}
|
||||
|
||||
func parseClock(input string) (int, error) {
|
||||
value, err := parseDuration(input)
|
||||
if err != nil {
|
||||
|
||||
@@ -29,6 +29,25 @@ func TestNettoSaldoUsage(t *testing.T) {
|
||||
assertContains(t, output, "= Sollzeit 07:53:00")
|
||||
}
|
||||
|
||||
func TestNoArgumentsShowsHelp(t *testing.T) {
|
||||
output := runCommand(t)
|
||||
|
||||
assertContains(t, output, "Nutzung:")
|
||||
assertContains(t, output, "goTimecalc -a")
|
||||
assertContains(t, output, "goTimecalc --netto 08:56:12 --saldo +01:03:12")
|
||||
}
|
||||
|
||||
func TestAskMode(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
if err := runAsk(strings.NewReader("08:05:25\n+00:12:25\n"), &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertContains(t, out.String(), "Netto-Zeit: Tagesaldo (+/-):")
|
||||
assertContains(t, out.String(), "Tagesaldo +00:12:25")
|
||||
assertContains(t, out.String(), "= Sollzeit 07:53:00")
|
||||
}
|
||||
|
||||
func TestStartEndWithPauseAndSoll(t *testing.T) {
|
||||
output := runCommand(t, "--start", "08:00", "--ende", "16:30", "--pause", "00:30", "--soll", "07:53")
|
||||
|
||||
@@ -86,6 +105,29 @@ func TestSignedDurationRequiresSign(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaldoInputAcceptsSignsAndLegacyMinus(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want int
|
||||
}{
|
||||
{input: "+00:12:25", want: 745},
|
||||
{input: "-00:12:25", want: -745},
|
||||
{input: "00:12:25", want: -745},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
got, err := parseSaldoInput(tt.input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Fatalf("want %d seconds, got %d", tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOvernightWorkDuration(t *testing.T) {
|
||||
start, err := parseClock("19:00")
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user