X-Git-Url: https://git.infodrom.org/?p=infodrom.org%2Fservice.infodrom.org;a=blobdiff_plain;f=src%2FInfoCon%2Fbuch%2Finfocon;h=c10413b7a5fb262a77af79b92d00570aa6e322be;hp=a1c68194cf3a8932e6334c0c5d644dca2e185448;hb=65cb3d52b45296e9a5f6a5d06fdb5d7f4d99d749;hpb=48093e30a8c602ac5c51e94753ec9afbeecfe3e4;ds=sidebyside diff --git a/src/InfoCon/buch/infocon b/src/InfoCon/buch/infocon index a1c6819..c10413b 100755 --- a/src/InfoCon/buch/infocon +++ b/src/InfoCon/buch/infocon @@ -1,7 +1,7 @@ #! /usr/bin/perl # infocon - Administration tool for InfoCon -# Copyright (c) 1998-2003,2005-8 Martin Schulze +# Copyright (c) 1998-2003,2005-8,10,11,12,14,15,16 Martin Schulze # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,12 +17,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. -# $Id$ - use strict; use warnings; use DBI; +use Scalar::Util qw/reftype/; use Term::ReadLine; use Getopt::Long; @@ -40,6 +39,7 @@ my $term = undef; my $opt_all = 0; my $opt_verbose = 0; my $opt_year = 0; +my $opt_date = undef; my $opt_direction = undef; sub sdate @@ -87,15 +87,48 @@ sub date_to_string return sprintf("%4d%02d%02d", $year,$mon,$day); } +sub valid_isodate +{ + my $date = shift; + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + return sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday) unless defined $date; + + if ($date =~ /^(\d+)\.(\d+)\.?$/) { + if ($mon == 0 && $2 > 9) { + $date = sprintf('%04d-%02d-%02d', $year+1900-1, $2, $1); + } else { + $date = sprintf('%04d-%02d-%02d', $year+1900, $2, $1); + } + } elsif ($date =~ /^(\d+)\.(\d+)\.(\d+)?$/) { + if (length $3 == 2) { + $date = sprintf('20%02d-%02d-%02d', $3, $2, $1); + } else { + $date = sprintf('%04d-%02d-%02d', $3, $2, $1); + } + } elsif ($date !~ /^(\d+)-(\d+)-(\d+)$/) { + return undef; + } + return $date; +} + sub pay_invoice { my $nr = shift; my $pay = shift; - my $value = $pay==1?1:0; my $query; my $sth; - $query = "UPDATE sales SET paid=$value WHERE nr = $nr"; + if ($pay) { + my $date = valid_isodate $opt_date; + + die "Invalid date\n" unless defined $date; + + $query = sprintf("UPDATE sales SET paid=1,billing_date=%s WHERE nr = %d", + defined $date ? $dbh->quote($date) : 'now()', $nr); + } else { + $query = sprintf("UPDATE sales SET paid=0,billing_date=NULL WHERE nr = %d", $nr); + } $sth = $dbh->do($query); } @@ -131,11 +164,13 @@ sub sales_list } if ($opt_year) { - if ($where) { - $where .= " AND date ~* '$opt_year'"; - } else { - $where .= "date ~* '$opt_year'"; - } + $where .= " AND " if $where; + $where .= sprintf("year = %d", $opt_year); + } + + if (defined $data{category} && length $data{category}) { + $where .= " AND " if $where; + $where .= sprintf("category = %s", $dbh->quote($data{category})); } if ($opt_direction) { @@ -152,54 +187,40 @@ sub sales_list } } + if ($where !~ /visible/) { + $where .= " AND " if $where; + $where .= "visible = 1"; + } + $query = "SELECT nr,date,description,price FROM $table"; $query .= " WHERE $where" if ($where); $query .= " ORDER by date,nr"; + $sth = $dbh->prepare($query); if ($sth && (my $rc = $sth->execute) > 0) { - print " Nr. Datum Bezeichnung Betrag\n"; - print "------------------------------------------------------------------\n"; + print " Nr. Datum Bezeichnung Betrag\n"; + print "----------------------------------------------------------------------------\n"; while (@row = $sth->fetchrow_array) { - $descr = substr($row[2],0,40); - printf "%4d %8s %-40s %9.2f\n", $row[0], sdate($row[1]), $descr, $row[3]; + $descr = substr($row[2],0,50); + printf "%4d %8s %-50s %9.2f\n", $row[0], sdate($row[1]), $descr, $row[3]; if ($row[3] < 0.0) { $sum_neg -= $row[3]; } else { $sum_pos += $row[3]; } } - print "-----------------------------------------------------------------\n" + print "---------------------------------------------------------------------------\n" if ($sum_neg > 0 || $sum_pos > 0) ; - printf " Zahlungseingänge %9.2f\n", $sum_pos + printf " Zahlungseingänge %9.2f\n", $sum_pos if ($sum_pos > 0); - printf " Zahlungsausgänge %9.2f\n", -$sum_neg + printf " Zahlungsausgänge %9.2f\n", -$sum_neg if ($sum_neg > 0); - print "==================================================================\n"; - printf " Summe %9.2f\n\n", $sum_pos - $sum_neg; + print "============================================================================\n"; + printf " Summe %9.2f\n\n", $sum_pos - $sum_neg; } $data{'done'} = 1; } -sub get_descriptions -{ - my $query; - my @row; - my $sth; - my @arr = (); - my ($date_sec,$date_min,$date_hour,$date_mday,$date_mon,$date_year,$date_wday,$date_isdst) - = localtime; - - $query = sprintf("SELECT DISTINCT description FROM %s WHERE date LIKE '%d%%' ORDER by description", - $table, $date_year+1900); - $sth = $dbh->prepare($query); - if ($sth && (my $rc = $sth->execute) > 0) { - while (@row = $sth->fetchrow_array) { - push(@arr, $row[0]) if ($row[0]); - } - } - return @arr; -} - sub get_categories { my $query; @@ -219,30 +240,166 @@ sub get_categories sub list_categories { + my $field = shift; + my $answers = shift; + @categories = get_categories unless @categories; printf "%s\n", join (", ",@categories); - exit; + exit unless $field; +} + +sub validate_date +{ + my $ans = shift; + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + return sprintf("%d.%d.%d", $mday, $mon+1, $year+1900) unless length $ans; + + my @arr = split(/\./, $ans); + + return sprintf("%d.%d.%d", $ans, $mon+1, $year+1900) if scalar @arr == 1; + return sprintf("%d.%d.%d", $arr[0], $arr[1], $year+1900) if scalar @arr == 2; + return sprintf("%d.%d.%d", $arr[0], $arr[1], + length $arr[2] > 2 ? $arr[2] : $arr[2] + 2000); +} + +my $answers; +sub calculate_price +{ + my $ans = shift; + + if (!defined $answers->{tax_assigned} || !length $answers->{tax_assigned}) { + $answers->{tax_assigned} = $ans - ($ans / ((100+$answers->{tax_percent})/100)); + } + + if ($answers->{einaus} =~ /[ei]/i) { + $answers->{tax_assigned} *= -1 if $answers->{tax_assigned} < 0; + $ans *= -1 if $ans < 0; + } else { + $answers->{tax_assigned} *= -1 if $answers->{tax_assigned} > 0; + $ans *= -1 if $ans > 0; + } + + return $ans; +} + +sub complete_category +{ + my ($text, $line, $start) = @_; + + return () unless exists $answers->{category} && length $answers->{category}; + + my $sql = sprintf("SELECT DISTINCT description FROM %s WHERE category = '%s' AND description LIKE '%s%%' ORDER BY description", + $table, + $answers->{category}, + $line); + my $sth = $dbh->prepare($sql); + $sth->execute; + my @complete; + while (my $row = $sth->fetchrow_hashref) { + $row->{description} = substr $row->{description}, $start if $start; + push @complete, $row->{description}; + } + + return @complete; +} + +sub complete_categoryname +{ + my ($text, $line, $start) = @_; + + return () unless length $line; + + my $sql = sprintf("SELECT DISTINCT category FROM %s WHERE category LIKE '%s%%' ORDER BY category", + $table, + $line); + my $sth = $dbh->prepare($sql); + $sth->execute; + my @complete; + while (my $row = $sth->fetchrow_hashref) { + $row->{category} = substr $row->{category}, $start if $start; + push @complete, $row->{category}; + } + + return @complete; +} + +sub default_year +{ + my $answers = shift; + + my @arr = split(/\./, $answers->{date}); + return $arr[2]; } sub read_input { - my $prompt = shift; - my $default = shift; + my $name = shift; + my $info = shift; + my $default; my $ans; + if (exists $info->{default}) { + if ($info->{default} eq 'last') { + $default = $answers->{$name} if $answers->{$name}; + } elsif (reftype $info->{default} && reftype $info->{default} eq 'CODE') { + $default = $info->{default}($answers); + } elsif ($info->{type} && $info->{type} eq 'boolean') { + if ($info->{default}) { + $default = 'J'; + } else { + $default = 'N'; + } + } else { + $default = $info->{default}; + } + } + + if ($info->{complete}) { + $term->{completion_function} = $info->{complete}; + } else { + $term->{completion_function} = undef; + } + if ($default) { - $ans = $term->readline ($prompt . " [" . $default . "]: "); + $ans = $term->readline ($info->{title} . " [" . $default . "]: "); } else { - $ans = $term->readline ($prompt . ": "); + $ans = $term->readline ($info->{title} . ": "); } - if (length ($ans) == 0) { + + exit unless defined $ans; + + if (!length $ans && defined $default) { $ans = $default; } elsif ($ans eq ".") { $ans = ''; } - $ans =~ s/ *$// if $ans; + + return read_input($name, $info) unless length $ans || exists $info->{empty}; + + if ($ans eq '?' && exists $info->{lookup}) { + $info->{lookup}($name, $answers); + return read_input($name, $info); + } + + if (exists $info->{type} && $info->{type} eq 'boolean') { + if ($ans =~ /[JY1]/i) { + $ans = 1; + } else { + $ans = 0; + } + } elsif (exists $info->{validate} && reftype $info->{validate} eq 'CODE') { + $ans = $info->{validate}($ans); + } else { + $ans =~ s/ *$// if $ans; + } + + if (!exists $info->{type} || $info->{type} ne 'boolean') { + $term->addhistory($ans); + } + return $ans; } @@ -270,90 +427,103 @@ sub get_next_nr sub buchung_input { - my @fieldname = ('Datum','Category','Description','Ein/Aus','Tax percent','Tax assigned','Price','Paid'); - my @input = (); my $weiter = 'y'; - my $i; my $ans; - my $query; my ($date_sec,$date_min,$date_hour,$date_mday,$date_mon,$date_year,$date_wday,$date_isdst) = localtime; + my $fields = { + 'date' => { + 'title' => 'Datum', + 'validate' => \&validate_date, + 'default' => 'last'}, + 'pdf' => { + 'title' => 'PDF', + 'type' => 'boolean', + 'default' => 0}, + 'year' => { + 'title' => 'Jahr', + 'default' => \&default_year}, + 'category' => { + 'title' => 'Kategorie', + 'lookup' => \&list_categories, + 'default' => 'last', + 'complete' => \&complete_categoryname}, + 'description' => { + 'title' => 'Beschreibung', + 'default' => 'last', + 'complete' => \&complete_category}, + 'einaus' => { + 'title' => 'Ein/Aus', + 'default' => 'a', + 'save' => 0}, + 'tax_percent' => { + 'title' => 'Steuersatz', + 'default' => '19'}, + 'tax_assigned' => { + 'title' => 'Umsatzsteuer', + 'empty' => 1}, + 'price' => { + 'title' => 'Betrag', + 'validate' => \&calculate_price}, + 'paid' => { + 'title' => 'bezahlt', + 'type' => 'boolean', + 'default' => 0}, + 'billing_date' => { + 'title' => 'wann', + 'type' => 'date', + 'validate' => \&validate_date}, + 'weiter' => { + 'title' => 'Weiter', + 'type' => 'boolean', + 'default' => 1, + 'save' => 0}, + }; + my @fields = ('date','year','pdf','category','description','einaus','tax_percent','tax_assigned','price','paid','weiter'); + @categories = get_categories unless @categories; - my @descriptions = get_descriptions; $term = new Term::ReadLine '' unless $term; - $term->addhistory($_) foreach (@categories); - $term->addhistory($_) foreach (@descriptions); - - my $attribs = $term->Attribs; - - my $sth = $dbh->prepare ("INSERT INTO $table VALUES (?,?,?,?,?,?,?,?,?)"); + my $sth = $dbh->prepare ("INSERT INTO $table (nr,date,pdf,year,category,description,tax_percent,tax_assigned,price,billing_date,paid) " . + "VALUES (?,?,?,?,?,?,?,?,?,?,?)"); print "Buchungseingabe\n\n"; while ($weiter =~ /[JjYy1]/) { - $i=0;while ($i <= $#fieldname) { - if ($fieldname[$i] eq "Category") { - $attribs->{completion_entry_function} = $attribs->{list_completion_function}; - $attribs->{completion_word} = \@categories; - } elsif ($fieldname[$i] eq "Description") { - $attribs->{completion_entry_function} = $attribs->{list_completion_function}; - $attribs->{completion_word} = \@descriptions; - } elsif ($fieldname[$i] eq "Tax assigned") { - if ($input[$i-1] == 0) { - $input[$i++] = 0; - next; - } - } else { - $attribs->{completion_word} = undef; + foreach my $f (@fields) { + if ($f eq 'tax_assigned' && $answers->{'tax_percent'} == 0) { + $answers->{$f} = 0; + next; } - $ans = read_input($fieldname[$i],$input[$i]); - if ($fieldname[$i] eq "Category" && $ans eq "?") { - printf " %s\n", join (", ",@categories); - } elsif ($fieldname[$i] eq "Datum") { - if ($ans =~ /^\d+\.\d+.\d+$/) { - $input[$i] = $ans; - $i++; - } elsif ($ans =~ /^\d+\.\d+.$/) { - $ans .= $date_year + 1900; - $input[$i] = $ans; - $i++; - } elsif ($ans =~ /^\d+\.$/) { - $ans .= sprintf ("%d.%d", $date_mon + 1, $date_year + 1900); - $input[$i] = $ans; - $i++; - } - } elsif ($fieldname[$i] eq "Paid") { - if ($ans =~ /[1jJyY]/) { - $input[$i] = 1; + $ans = read_input($f, $fields->{$f}); + $answers->{$f} = $ans; + + if ($f eq 'paid') { + if ($answers->{paid}) { + $fields->{'billing_date'}{'default'} = $answers->{'date'}; + $ans = read_input('billing_date', $fields->{'billing_date'}); + $answers->{billing_date} = $ans; } else { - $input[$i] = 0; + $answers->{billing_date} = undef; } - $i++; - } else { - $input[$i] = $ans; - $i++; - } - } - if (!$input[5]) { # USt selbst berechnen - if ($input[4] != 0) { - $input[5] = $input[6] - ($input[6] / ((100+$input[4])/100)); } } - if ($input[3] =~ /[EeIi\+]/) { - $input[5] *= -1 if ($input[5] < 0); - $input[6] *= -1 if ($input[6] < 0); - } else { - $input[5] *= -1 if ($input[5] > 0); - $input[6] *= -1 if ($input[6] > 0); - } - - $sth->execute (get_next_nr(), date_to_string($input[0]), $input[1], $input[2], $input[4], - $input[5], $input[6], 1, $input[7]); - $weiter = read_input("Weiter",'j'); - $input[5] = 0.0; + $sth->execute(get_next_nr(), + date_to_string($answers->{date}), + $answers->{pdf}, + $answers->{year}, + $answers->{category}, + $answers->{description}, + $answers->{tax_percent}, + $answers->{tax_assigned}, + $answers->{price}, + defined $answers->{billing_date} ? date_to_string($answers->{billing_date}) : undef, + $answers->{paid}); + + $weiter = $answers->{weiter}; + $answers->{tax_assigned} = 0.0; } exit; @@ -370,8 +540,6 @@ sub buchung_hidden sub buchung_unpaid { - $table = "sales_dm"; - sales_list("paid = 0"); $table = "sales"; sales_list("paid = 0"); exit; @@ -384,6 +552,7 @@ sub usage print " --buchung-input|-bi\n"; print " --buchung-unpaid\n"; print " --buchung-hidden\n"; + print " --date [yyyy-mm-dd|dd.mm.] (for --pay)\n"; print " --pay | --unpay \n"; print " --hide | --unhide \n"; print " --list-categories|-lc\n"; @@ -403,6 +572,11 @@ sub usage 'unpay' => undef, 'hide' => undef, 'unhide' => undef, + 'mailto' => undef, + 'buchung-input' => undef, + 'buchung-unpaid' => undef, + 'buchung-hidden' => undef, + 'list-categories' => undef, ); my %options = ( 'buchung-category|bc:s' => \$data{category}, @@ -411,7 +585,9 @@ my %options = ( 'hide=s' => \$data{hide}, 'unhide=s' => \$data{unhide}, 'year=i' => \$opt_year, - 'direction=s' => \$opt_direction, + 'date=s' => \$opt_date, + 'direction|d=s' => \$opt_direction, + 'mailto:s' => \$data{mailto}, 'all' => \$opt_all, 'verbose' => \$opt_verbose, 'help' => \&usage, @@ -419,9 +595,10 @@ my %options = ( 'buchung-input|bi' => \&buchung_input, 'buchung-unpaid|bu' => \&buchung_unpaid, 'buchung-hidden|bh' => \&buchung_hidden, - 'list-categories|lc' => \&list_categories, + 'list-categories|lc' => \$data{'list-categories'}, ); +my $cmdln = 'infocon ' . join (' ', @ARGV); GetOptions(%options); if ($opt_year != 0 && $opt_year < 2002) { @@ -432,21 +609,32 @@ if (defined $opt_direction) { usage unless $opt_direction =~ /^(in|out)$/i; } -if (defined $data{category}) { - if (length($data{category})) { - sales_list("category = '".$data{category}."'"); - } else { - sales_list; +if (defined $data{mailto}) { + if (open(STDOUT, "| /usr/sbin/sendmail -t")) { + print "From: Joey Schulze \n"; + printf "To: %s\n", length($data{mailto})?$data{mailto}:'Joey Schulze '; + printf "Subject: %s\n", $cmdln; + print "MIME-Version: 1.0\n"; + print "Content-type: text/plain; charset=iso-8859-1\n"; + print "Content-Disposition: inline\n"; + print "Content-Transfer-Encoding: 8bit\n"; + print "\n"; } +} + +if (defined $data{category}) { + sales_list; exit; +} elsif (defined $data{'list-categories'}) { + list_categories; } elsif (defined $data{pay}) { - pay_invoce($data{pay}, 1); + pay_invoice($data{pay}, 1); } elsif (defined $data{unpay}) { - pay_invoce($data{unpay}, 0); + pay_invoice($data{unpay}, 0); } elsif (defined $data{hide}) { - hide_invoce($data{hide}, 1); + hide_invoice($data{hide}, 1); } elsif (defined $data{unhide}) { - hide_invoce($data{unhide}, 0); + hide_invoice($data{unhide}, 0); +} else { + usage; } - -usage;