=head1 list_stunden_summe

C<list_stunden_summe( [Person] [Kunde] [Prompt] [Flag] )>

Listet alle Stunden einer Person / eines Kunden in einem
bestimmten Zeitraum auf, summiert über einen Tag.

Flags:

=over 4

=item 1

berechnete Zeit setzen

=item 2

nur die Stundenliste, kein Drumherum

=back

=cut

use utf8;
use warnings; no warnings "redefine";
use strict;

use Loader qw(
	edit_kunden edit_personen
	line_printer
	select_date
  );
use Dbase::Globals qw(mpersinfo no_crlf stunden_bereich content
	test_flag);
use Dbase::Help qw(isodate DoFn Do isotime DoN DoTime);
use Fehler qw(warnung);

#my $artHotline = DoFn("select id from stunden_art where name ='Hotline'");
my $artUrlaub = DoFn("select id from stunden_art where name ='Urlaub'");
my $artPause = DoFn("select id from stunden_art where name ='Pause'");

my @pausen = ([9,45],[6,30]); # nach x Stunden Arbeit braucht es y Minuten Pause

sub lss_zeit($) {
	my($z) = @_;
	return "  --:--" if $z == 0;
	my $res = sprintf " %3d:%02d",abs($z)/3600,(abs($z)%3600)/60;
	$res =~ s/^ /-/ if $z < 0;
	$res;
}


sub list_stunden_summe(;$$$$$$) {
	my($pid,$kid,$kn,$flag,$beginn,$ende) = @_;
	my $ssum=0;
	my $sum=0;
	$flag=0 unless defined $flag;

	unless(defined $pid) {
		$pid = edit_personen(1,1+4,"Stundenliste:");
		return undef unless defined $pid;
	}
	$pid = undef if $pid eq "-";

	if($flag & 1) {
		$kid = undef;
	} else {
		unless(defined $kid) {
			$kid = edit_kunden(1+4,"Stundenliste:");
			return undef unless defined $kid;
		}
		$kid = undef if $kid eq "-";
	}

	unless(defined $beginn) {
		$beginn = select_date(4,"Monat",undef,"-", "dieser Monat");
		return undef unless defined $beginn;
	}
	$beginn = select_date(4|2048,undef,DoTime) if $beginn eq "-";
	if(not defined $ende or $ende eq "-") {
		$ende = select_date(16|2048,undef,$beginn); ## Erster im nächsten Monat
	}
	my $mon; my $moni;
	# my $mon6m;
	{
		my($j,$m,$t) = isodate($beginn);
		$mon = $j*100+$m;
		$moni = sprintf("%04d-%02d",$j,$m);

		# $m -= 6; $m += 12,$j-- if $m < 1;
		# $mon6m = sprintf("%04d-%02d",$j,$m);
	}
	my $urlaub=0;
	my $tag = ""; my $pers = 0;
	my($voll,$paus,$spaus,$mehr,$smehr,$beg,$end,%typ,$ohnepause,$autopause,@autopause);

	line_printer;

	my $endmonat = sub {
		return if $flag & 2;
		printf $Db::pr_fh <<END,lss_zeit($ssum);
       ---------
       %s h
END
		return if $kid; ### TODO: Kundenabrechnung

		my($ep,$letzter) = DoFn("select abschluss,letzter from perso where person = $pers");

		if($letzter) {
			$letzter += 100-12 if (++$letzter % 100) == 13;
		} else {
			$letzter = $mon;
		}
		my($soll,$dueberlim) = DoFn("select soll,ueberstundenlimit from persomonat where monat = $mon and person = $pers");
		$soll = DoFn("select soll from persomonat where monat = $mon and person is NULL") unless defined $soll;

		$urlaub *= 24/8;
		my $auszahl = DoFn("select auszahl from persomonat where monat = $mon and person = $pers")||0;
		my($rdurlaub,$durlaub,$dueber,$dueberlim_default,$dmon) = DoFn("select resturlaub,urlaub,ueberstunde,ueberstundenlimit,letzter from perso where person = $pers");
		my $sdiff = $ssum-($soll||0);
		my $duebe = $dueber;
		my $uneu = $duebe+$sdiff-$auszahl;
		$dueberlim = $dueberlim_default unless defined $dueberlim;

		my $problem;
		if(not defined $soll) {
			$problem = "...keine Sollzeit bekannt.";
		} elsif(not defined $ep or $ep < $end) {
			$problem = "...noch nicht abgeschlossen";
			$problem .= " (".isodate($ep).")" if $ep;
		} elsif ($ende > DoTime) {
			$problem = "...Monat ist noch nicht zu Ende...\n";
		} elsif ($letzter != $mon) {
			$problem = sprintf("...nächster Monat: %d-%02d",int($letzter/100),$letzter%100);
		} else {
			if($ENV{"DB_DEBUG"} && $soll) { ## DISABLED
				printf $Db::pr_fh <<END,lss_zeit($soll),lss_zeit($sdiff);
SOLL   %s h
----------------
       %s h
END
	   		}
			if($ENV{"DB_DEBUG"}) { ## DISABLED
				if($duebe != $dueber) {
					printf $Db::pr_fh <<END,lss_zeit($duebe),lss_zeit($dueber);
Uestd  %s h Limit (Übertrag: %s h)
END
				} else {
					printf $Db::pr_fh <<END,lss_zeit($duebe);
Uestd  %s h Übertrag
END
				}
				printf $Db::pr_fh <<END,lss_zeit($auszahl),lss_zeit($uneu);
Ausz.  %s h
----------------
       %s h Überstunden, Ende $moni

END
			}
			printf $Db::pr_fh <<END,($rdurlaub+$durlaub)/3600/24,$urlaub/3600/24 if $urlaub;
                Resturlaub: %5.1f Tage
                  Genommen: %5.1f Tage
END
			if($rdurlaub > $urlaub) {
				$rdurlaub -= $urlaub;
				$urlaub = 0;
			} else {
				if($rdurlaub > 0) {
					$urlaub -= $rdurlaub;
					$rdurlaub = 0;
				}
				$durlaub -= $urlaub;
			}
			printf $Db::pr_fh <<END,($rdurlaub+$durlaub)/3600/24;
Verbleibender Gesamturlaub: %5.1f Tage
END
			print $Db::pr_fh 'automatisch eingetragene Pausenzeiten:', lss_zeit($autopause), ' h (', join(', ', @autopause), ")\n"
			  if @autopause;

			if($flag & 1) {
				Do "update perso set resturlaub=$rdurlaub,urlaub=$durlaub,letzter=$mon where person = $pers";
				Do "update perso set ueberstunde=$uneu where person = $pers" if $soll;
				my $mid = add_persomonat($pers,$mon);
				Do "update persomonat set ist=$ssum, urlaub=$urlaub, diff=diff+$sdiff where id=$mid";
				print $Db::pr_fh "Update gespeichert.\n";
			} else {
				print $Db::pr_fh "Summe NICHT gespeichert.\n";
			}
			return;
		}
		if($ENV{DB_DEBUG}) {
			$problem="wird abgerechnet" if $flag &1 and not defined $problem;
			printf $Db::pr_fh <<END,lss_zeit($soll),lss_zeit($sdiff),lss_zeit($dueber),(defined $dueberlim?" (Limit: ".lss_zeit($dueberlim)." h)":""), lss_zeit($auszahl),lss_zeit($uneu),$problem,($durlaub+$rdurlaub)/3600/24,$urlaub/3600/24;
SOLL   %s h
----------------
       %s h
Uestd  %s h aktueller Übertrag%s
Ausz.  %s h
----------------
       %s h Überstunden (%s)
      aktueller Resturlaub: %5.1f Tage
     Diesen Monat genommen: %5.1f Tage
END
		} else {
			printf $Db::pr_fh <<END, $urlaub/3600/24;

              Summe genommener Urlaub: %5.1f Tage
END
			print <<END if $flag&1 and defined $problem;
             nicht abgeschlossen weil: $problem
END
		}
		print $Db::pr_fh 'automatisch eingetragene Pausenzeiten:', lss_zeit($autopause), ' h (', join(', ', @autopause), ")\n"
		  if @autopause;
	};
	my $endtag = sub {
		if($tag ne "") {
			my(undef,$bbm,$bbt,$bh,$bm)=isotime($beg);
			my(undef,undef,undef,$eh,$em)=isotime($end);

			# Berechne vorgeschriebene Pause, wenn nicht Urlaub/krank
			my $tm = $voll+$paus-$ohnepause;
			foreach my $p(@pausen) {
				my $pzeit = $p->[0]*60*60; # Arbeitsstunden
				my $ppaus = $p->[1]*60; # min. Minuten
				next if $tm < $pzeit;
				if($tm < $ppaus+$pzeit) { # nicht voller Abzug
					$ppaus=$tm-$pzeit;
				}
				if($paus < $ppaus) { # zu wenig!
					my $pmehr = $ppaus-$paus;
					# print STDERR "APause $paus $ppaus $pmehr\n";
					$voll -= $pmehr;
					$paus += $pmehr;
					$ssum -= $pmehr;
					$autopause += $pmehr;
					push @autopause, sprintf "%02d-%02d: %.f", $bbm, $bbt, $pmehr/60;
				}
			}
			printf $Db::pr_fh "%02d-%02d  %s h   %02d:%02d - %02d:%02d  ",$bbm,$bbt,lss_zeit($voll+$spaus+$mehr),$bh,$bm,$eh,$em;

			if($paus) {
				printf $Db::pr_fh "./. %3d",$paus/60;
				if($spaus) {
					printf $Db::pr_fh " (%3.2f)",$spaus/$paus;
				}
			} else {
				print $Db::pr_fh "       ";
			}
			print $Db::pr_fh " ".join("+",keys %typ) if %typ;
			printf $Db::pr_fh " + %3d",$mehr/60 if $mehr;
			print $Db::pr_fh "\n";
		}
	};
	my $startmonat = sub {
		return if $flag & 2;
		printf $Db::pr_fh <<END,mpersinfo($pers,1),$moni;
*** Zeiterfassung: %s, %s

END
	};
	my $starttag = sub { %typ = (); };

	my $special;
	my $tagstunden; my $ts_pid = 0;
	my $res = stunden_bereich($pid,$kid,$beginn,$ende,1|2, sub {
		my($sid,$sbeg,$sdau,$person,$kunde,$faktor,$txt,$ticket,$art,$artflg,$artname) = @_;
#		{ no warnings "uninitialized";
#		  print STDERR "$sid,$sbeg,$sdau,$person,$kunde,$faktor,$txt,$ticket,$art,$artflg\n";
#		}

		my $t = isodate($sbeg);

		## Datenbanken mit identischen Abfragen zu bombardieren ist unproduktiv
		if($ts_pid != $person) {
			$tagstunden = DoFn("select tagstunden from perso where person = $person");
			$ts_pid = $person;

			if(defined $tagstunden) {
				$tagstunden /= 1000;
			} else {
				$tagstunden = 8;
			}
		}

		{
			my $new_special = test_flag("stunden_art","keine_arbeit",$artflg);
			if ( ($special || $new_special) && ($art != $artPause) || $t ne $tag || $end < $sbeg ) {
				&$endtag() if $tag;

				if($pers ne $person) {
					if($pers) {
						&$endmonat();
						print $Db::pr_fh "";
					}
					$pers = $person;
					&$startmonat();
				}

				$tag = $t; $beg = $sbeg; $end = $sbeg+$sdau;
				$mehr=0; $voll=0; $paus=0; $spaus=0; $smehr=0;
				$ohnepause=0;
				&$starttag();
			}
			$special = $new_special if $art != $artPause;
			$typ{$artname}++ if $art != $artPause;
		}
		$end = $sbeg+$sdau if $end < $sbeg+$sdau;
		if($art == $artUrlaub) {
			$faktor = 100;
			$urlaub += $sdau;
			$sdau *= $tagstunden/8;
			$voll += $sdau;
			$ohnepause += $sdau;
		} elsif(test_flag("stunden_art","keine_arbeit",$artflg)
				and $art != $artPause) {
			$faktor = 100;
			$sdau *= $tagstunden/8;
			$voll += $sdau;
			$ohnepause += $sdau;
		} elsif($faktor == 100) {
			$voll += $sdau;
		} elsif($faktor > 100) {
			$smehr += $sdau*$faktor/100;
			$voll += $sdau;
			$mehr += $sdau*($faktor-100)/100;
		} else {
			$spaus += $sdau*$faktor/100;
			#print STDERR "Pause $paus + $sdau, $faktor\n";
			$paus += $sdau;
		}
		$ssum += $faktor*$sdau/100;
		$sum += $sdau;
	});
	&$endtag() if $tag;
	&$endmonat() if $pers;

	$res;
}

1;
