Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b904c597b | |||
| e8cd6e2a91 | |||
| 5fdf2e7cb0 | |||
| 0de4425bff | |||
| bb58bdfaee |
@@ -14,15 +14,45 @@ Ausgabe:
|
||||
|
||||
```text
|
||||
Netto-Zeit 06:01:14
|
||||
+ Minuszeit 01:51:46
|
||||
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
|
||||
`+`.
|
||||
|
||||
```sh
|
||||
goTimecalc --netto 08:56:12 --saldo +01:03:12
|
||||
```
|
||||
|
||||
Ausgabe:
|
||||
|
||||
```text
|
||||
Netto-Zeit 08:56:12
|
||||
Tagesaldo +01:03:12
|
||||
= Sollzeit 07:53:00
|
||||
```
|
||||
|
||||
## Brutto, Pause, Netto und Tages-Saldo
|
||||
|
||||
```sh
|
||||
@@ -47,6 +77,9 @@ Der Tages-Saldo kann positiv oder negativ sein.
|
||||
goTimecalc --start 08:00 --ende 16:30 --pause 00:30 --soll 07:53
|
||||
```
|
||||
|
||||
Bei Start-/Endzeit zaehlt nur Arbeitszeit zwischen `06:00` und `20:00`.
|
||||
Zeit davor oder danach wird aus der Brutto-Zeit herausgerechnet.
|
||||
|
||||
Beispielausgabe:
|
||||
|
||||
```text
|
||||
@@ -65,6 +98,9 @@ Wenn die Endzeit kleiner als die Startzeit ist, wird eine Nachtschicht angenomme
|
||||
goTimecalc --start 22:00 --ende 06:00 --pause 00:30
|
||||
```
|
||||
|
||||
Da diese Zeit komplett ausserhalb `06:00` bis `20:00` liegt, wird sie nicht als
|
||||
Arbeitszeit angerechnet.
|
||||
|
||||
## Webinterface
|
||||
|
||||
Der Webserver startet nur, wenn `--web` angegeben wird:
|
||||
|
||||
@@ -14,6 +14,12 @@ import (
|
||||
|
||||
const appName = "goTimecalc"
|
||||
|
||||
const (
|
||||
workdayStart = 6 * 3600
|
||||
workdayEnd = 20 * 3600
|
||||
daySeconds = 24 * 3600
|
||||
)
|
||||
|
||||
type dayList []dayEntry
|
||||
|
||||
type dayEntry struct {
|
||||
@@ -42,7 +48,7 @@ func run(args []string, out io.Writer) error {
|
||||
return fmt.Errorf("Minuszeit: %w", err)
|
||||
}
|
||||
|
||||
printSollzeit(out, netto, minuszeit)
|
||||
printSollzeitFromSaldo(out, netto, -minuszeit)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -50,10 +56,13 @@ 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")
|
||||
minusInput := flags.String("minus", "", "Minuszeit, z.B. 01:52")
|
||||
saldoInput := flags.String("saldo", "", "Tagesaldo mit Vorzeichen, z.B. -01:52 oder +01:03")
|
||||
bruttoInput := flags.String("brutto", "", "Brutto-Zeit, z.B. 09:26:12")
|
||||
startInput := flags.String("start", "", "Startzeit, z.B. 08:00")
|
||||
endInput := flags.String("ende", "", "Endzeit, z.B. 16:30")
|
||||
@@ -65,6 +74,8 @@ 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")
|
||||
fmt.Fprintln(out, " goTimecalc --day 08:00-16:30,00:30 --day 09:00-17:00 --soll 15:46")
|
||||
@@ -74,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
|
||||
@@ -85,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)
|
||||
}
|
||||
@@ -113,16 +133,40 @@ func run(args []string, out io.Writer) error {
|
||||
return runStartEnd(out, *startInput, *endInput, *pauseInput, *sollInput)
|
||||
}
|
||||
|
||||
if *nettoInput != "" || *minusInput != "" {
|
||||
return runNettoMinus(out, *nettoInput, *minusInput)
|
||||
if *nettoInput != "" || *minusInput != "" || *saldoInput != "" {
|
||||
return runNettoSaldo(out, *nettoInput, *saldoInput, *minusInput)
|
||||
}
|
||||
|
||||
return runInteractive(out)
|
||||
flags.Usage()
|
||||
return nil
|
||||
}
|
||||
|
||||
func runNettoMinus(out io.Writer, nettoInput string, minusInput string) error {
|
||||
if nettoInput == "" || minusInput == "" {
|
||||
return errors.New("--netto und --minus muessen zusammen angegeben werden")
|
||||
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 {
|
||||
if nettoInput == "" {
|
||||
return errors.New("--netto muss angegeben werden")
|
||||
}
|
||||
if saldoInput == "" && minusInput == "" {
|
||||
return errors.New("--saldo mit Vorzeichen angeben, zum Beispiel: --saldo -01:52 oder --saldo +01:03")
|
||||
}
|
||||
if saldoInput != "" && minusInput != "" {
|
||||
return errors.New("bitte entweder --saldo oder --minus angeben, nicht beides")
|
||||
}
|
||||
|
||||
netto, err := parseDuration(nettoInput)
|
||||
@@ -130,12 +174,21 @@ func runNettoMinus(out io.Writer, nettoInput string, minusInput string) error {
|
||||
return fmt.Errorf("Netto-Zeit: %w", err)
|
||||
}
|
||||
|
||||
minuszeit, err := parseDuration(minusInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Minuszeit: %w", err)
|
||||
saldo := 0
|
||||
if saldoInput != "" {
|
||||
saldo, err = parseSignedDuration(saldoInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Tagesaldo: %w", err)
|
||||
}
|
||||
} else {
|
||||
minuszeit, err := parseDuration(minusInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Minuszeit: %w", err)
|
||||
}
|
||||
saldo = -minuszeit
|
||||
}
|
||||
|
||||
printSollzeit(out, netto, minuszeit)
|
||||
printSollzeitFromSaldo(out, netto, saldo)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -197,27 +250,42 @@ 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
|
||||
}
|
||||
|
||||
printSollzeit(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 printSollzeit(out io.Writer, netto int, minuszeit int) {
|
||||
fmt.Fprintf(out, "Netto-Zeit %8s\n", formatDuration(netto))
|
||||
fmt.Fprintf(out, "+ Minuszeit %8s\n", formatDuration(minuszeit))
|
||||
fmt.Fprintf(out, "= Sollzeit %8s\n", formatDuration(netto+minuszeit))
|
||||
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 {
|
||||
@@ -273,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 {
|
||||
@@ -320,6 +372,44 @@ func parseDuration(input string) (int, error) {
|
||||
return hours*3600 + minutes*60 + seconds, nil
|
||||
}
|
||||
|
||||
func parseSignedDuration(input string) (int, error) {
|
||||
input = strings.TrimSpace(input)
|
||||
if input == "" {
|
||||
return 0, errors.New("Zeit fehlt")
|
||||
}
|
||||
|
||||
sign := input[0]
|
||||
if sign != '+' && sign != '-' {
|
||||
return 0, errors.New("Tagesaldo braucht ein Vorzeichen, zum Beispiel -01:52 oder +01:03")
|
||||
}
|
||||
|
||||
value, err := parseDuration(input[1:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if sign == '-' {
|
||||
return -value, nil
|
||||
}
|
||||
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 {
|
||||
@@ -350,9 +440,26 @@ func workDuration(start int, end int, pause int) int {
|
||||
|
||||
func grossDuration(start int, end int) int {
|
||||
if end < start {
|
||||
end += 24 * 3600
|
||||
end += daySeconds
|
||||
}
|
||||
return end - start
|
||||
|
||||
total := 0
|
||||
for dayStart := 0; dayStart <= end; dayStart += daySeconds {
|
||||
windowStart := dayStart + workdayStart
|
||||
windowEnd := dayStart + workdayEnd
|
||||
total += overlapSeconds(start, end, windowStart, windowEnd)
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
func overlapSeconds(start int, end int, windowStart int, windowEnd int) int {
|
||||
from := max(start, windowStart)
|
||||
to := min(end, windowEnd)
|
||||
if to <= from {
|
||||
return 0
|
||||
}
|
||||
return to - from
|
||||
}
|
||||
|
||||
func formatDuration(totalSeconds int) string {
|
||||
@@ -363,6 +470,13 @@ func formatDuration(totalSeconds int) string {
|
||||
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
}
|
||||
|
||||
func formatSignedDuration(totalSeconds int) string {
|
||||
if totalSeconds < 0 {
|
||||
return "-" + formatDuration(-totalSeconds)
|
||||
}
|
||||
return "+" + formatDuration(totalSeconds)
|
||||
}
|
||||
|
||||
func (d *dayList) String() string {
|
||||
return fmt.Sprint([]dayEntry(*d))
|
||||
}
|
||||
|
||||
+115
-6
@@ -11,7 +11,7 @@ func TestOldNettoMinusUsage(t *testing.T) {
|
||||
|
||||
want := strings.Join([]string{
|
||||
"Netto-Zeit 06:01:14",
|
||||
"+ Minuszeit 01:51:46",
|
||||
"Tagesaldo -01:51:46",
|
||||
"= Sollzeit 07:53:00",
|
||||
"",
|
||||
}, "\n")
|
||||
@@ -21,6 +21,33 @@ func TestOldNettoMinusUsage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNettoSaldoUsage(t *testing.T) {
|
||||
output := runCommand(t, "--netto", "08:56:12", "--saldo", "+01:03:12")
|
||||
|
||||
assertContains(t, output, "Netto-Zeit 08:56:12")
|
||||
assertContains(t, output, "Tagesaldo +01:03:12")
|
||||
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")
|
||||
|
||||
@@ -64,12 +91,49 @@ func TestShortDurationInput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOvernightWorkDuration(t *testing.T) {
|
||||
start, err := parseClock("22:00")
|
||||
func TestSignedDurationRequiresSign(t *testing.T) {
|
||||
if _, err := parseSignedDuration("01:03"); err == nil {
|
||||
t.Fatal("expected missing sign error")
|
||||
}
|
||||
|
||||
got, err := parseSignedDuration("-01:03")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
end, err := parseClock("06:00")
|
||||
if got != -3780 {
|
||||
t.Fatalf("want -3780 seconds, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
end, err := parseClock("07:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -78,8 +142,39 @@ func TestOvernightWorkDuration(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if got := workDuration(start, end, pause); got != 27000 {
|
||||
t.Fatalf("want 27000 seconds, got %d", got)
|
||||
if got := workDuration(start, end, pause); got != 5400 {
|
||||
t.Fatalf("want 5400 seconds, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrossDurationOnlyCountsWorkdayWindow(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
start string
|
||||
end string
|
||||
want int
|
||||
}{
|
||||
{name: "full span is capped", start: "05:00", end: "21:00", want: 14 * 3600},
|
||||
{name: "after workday is removed", start: "19:00", end: "22:00", want: 1 * 3600},
|
||||
{name: "overnight counts both workday windows", start: "19:00", end: "07:00", want: 2 * 3600},
|
||||
{name: "outside workday only", start: "22:00", end: "05:00", want: 0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
start, err := parseClock(tt.start)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
end, err := parseClock(tt.end)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if got := grossDuration(start, end); got != tt.want {
|
||||
t.Fatalf("want %d seconds, got %d", tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +198,20 @@ func TestWebRangeCalculation(t *testing.T) {
|
||||
assertLine(t, resp.Lines, "= Tagesaldo", "+00:07:00")
|
||||
}
|
||||
|
||||
func TestWebNettoSaldoCalculation(t *testing.T) {
|
||||
resp, err := calculateWeb(webCalcRequest{
|
||||
Mode: "netto",
|
||||
Netto: "08:56:12",
|
||||
Saldo: "+01:03:12",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertLine(t, resp.Lines, "Tagesaldo", "+01:03:12")
|
||||
assertLine(t, resp.Lines, "= Sollzeit", "07:53:00")
|
||||
}
|
||||
|
||||
func TestWebBruttoCalculation(t *testing.T) {
|
||||
resp, err := calculateWeb(webCalcRequest{
|
||||
Mode: "brutto",
|
||||
|
||||
@@ -12,6 +12,7 @@ type webCalcRequest struct {
|
||||
Mode string `json:"mode"`
|
||||
Netto string `json:"netto"`
|
||||
Minus string `json:"minus"`
|
||||
Saldo string `json:"saldo"`
|
||||
Brutto string `json:"brutto"`
|
||||
Start string `json:"start"`
|
||||
End string `json:"end"`
|
||||
@@ -110,15 +111,33 @@ func calculateWebNetto(req webCalcRequest) (webCalcResponse, error) {
|
||||
if err != nil {
|
||||
return webCalcResponse{}, fmt.Errorf("Netto-Zeit: %w", err)
|
||||
}
|
||||
minus, err := parseDuration(req.Minus)
|
||||
if err != nil {
|
||||
return webCalcResponse{}, fmt.Errorf("Minuszeit: %w", err)
|
||||
|
||||
saldoInput := req.Saldo
|
||||
if strings.TrimSpace(saldoInput) == "" {
|
||||
saldoInput = req.Minus
|
||||
}
|
||||
|
||||
var saldo int
|
||||
if strings.TrimSpace(saldoInput) == "" {
|
||||
return webCalcResponse{}, fmt.Errorf("Tagesaldo fehlt")
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(saldoInput), "+") || strings.HasPrefix(strings.TrimSpace(saldoInput), "-") {
|
||||
saldo, err = parseSignedDuration(saldoInput)
|
||||
if err != nil {
|
||||
return webCalcResponse{}, fmt.Errorf("Tagesaldo: %w", err)
|
||||
}
|
||||
} else {
|
||||
minus, err := parseDuration(saldoInput)
|
||||
if err != nil {
|
||||
return webCalcResponse{}, fmt.Errorf("Minuszeit: %w", err)
|
||||
}
|
||||
saldo = -minus
|
||||
}
|
||||
|
||||
lines := []resultLine{
|
||||
{Label: "Netto-Zeit", Value: formatDuration(netto)},
|
||||
{Label: "+ Minuszeit", Value: formatDuration(minus)},
|
||||
{Label: "= Sollzeit", Value: formatDuration(netto + minus), Kind: "total"},
|
||||
{Label: "Tagesaldo", Value: formatSignedDuration(saldo)},
|
||||
{Label: "= Sollzeit", Value: formatDuration(netto - saldo), Kind: "total"},
|
||||
}
|
||||
|
||||
return webCalcResponse{Lines: lines}, nil
|
||||
@@ -485,7 +504,7 @@ input:focus {
|
||||
<nav class="tabs" aria-label="Rechenmodus">
|
||||
<button class="tab active" data-mode="range" type="button">Start / Ende</button>
|
||||
<button class="tab" data-mode="brutto" type="button">Brutto / Pause</button>
|
||||
<button class="tab" data-mode="netto" type="button">Netto + Minus</button>
|
||||
<button class="tab" data-mode="netto" type="button">Netto / Saldo</button>
|
||||
<button class="tab" data-mode="days" type="button">Mehrere Tage</button>
|
||||
</nav>
|
||||
|
||||
@@ -508,7 +527,7 @@ input:focus {
|
||||
<div id="mode-netto" class="mode">
|
||||
<div class="grid">
|
||||
<label>Netto-Zeit <input id="netto" value="06:01:14" inputmode="numeric"></label>
|
||||
<label>Minuszeit <input id="minus" value="01:51:46" inputmode="numeric"></label>
|
||||
<label>Tagesaldo <input id="saldo" value="-01:51:46" inputmode="numeric"></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -579,7 +598,7 @@ function payload() {
|
||||
return {
|
||||
mode: activeMode,
|
||||
netto: document.querySelector("#netto").value,
|
||||
minus: document.querySelector("#minus").value,
|
||||
saldo: document.querySelector("#saldo").value,
|
||||
brutto: document.querySelector("#brutto").value,
|
||||
start: document.querySelector("#start").value,
|
||||
end: document.querySelector("#end").value,
|
||||
|
||||
Reference in New Issue
Block a user