From d1ebdf433634b0eeb21bda7dfef30a746eb6dabd Mon Sep 17 00:00:00 2001 From: Joey Schulze Date: Mon, 7 Nov 2011 16:11:09 +0000 Subject: [PATCH] Improve readline capabilities New field definition structure for input queries Use hash instead of array for storage Implement completion function for Readline Thus enable tab completion for some input lines Tidy up a little bit --- src/InfoCon/buch/infocon | 300 +++++++++++++++++++++++++-------------- 1 file changed, 196 insertions(+), 104 deletions(-) diff --git a/src/InfoCon/buch/infocon b/src/InfoCon/buch/infocon index 6060874..d1c7592 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,10 Martin Schulze +# Copyright (c) 1998-2003,2005-8,10,11 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 @@ -23,6 +23,7 @@ use strict; use warnings; use DBI; +use Scalar::Util qw/reftype/; use Term::ReadLine; use Getopt::Long; @@ -183,20 +184,14 @@ sub sales_list $data{'done'} = 1; } -sub get_descriptions +sub get_categories { - my $category = shift; 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 year = %d ", - $table, $date_year+1900); - $query .= sprintf("AND category = '%s' ", $category) if defined $category; - $query .= "ORDER by description"; + $query = "SELECT DISTINCT category FROM $table ORDER by category"; $sth = $dbh->prepare($query); if ($sth && (my $rc = $sth->execute) > 0) { while (@row = $sth->fetchrow_array) { @@ -206,49 +201,159 @@ sub get_descriptions return @arr; } -sub get_categories +sub categories { - my $query; - my @row; - my $sth; - my @arr = (); + my ($text, $line, $start) = @_; - $query = "SELECT DISTINCT category FROM $table ORDER by category"; - $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; + return () if $line =~ /\s/; + + @categories = get_categories unless @categories; + + return @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 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; } @@ -276,96 +381,83 @@ sub get_next_nr sub buchung_input { - my @fieldname = ('Datum','PDF','Year','Category','Description','Ein/Aus','Tax percent','Tax assigned','Price','Paid'); - my @input = (); my $weiter = 'y'; - my $i; my $ans; - my $query; - my @descriptions; 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' => \&categories}, + '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}, + '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; - @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 (nr,date,pdf,year,category,description,tax_percent,tax_assigned,price,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 "Year") { - $attribs->{completion_entry_function} = $attribs->{list_completion_function}; - $input[$i] = substr($input[0],-4); - $attribs->{completion_word} = $input[$i]; - } elsif ($fieldname[$i] eq "Description") { - $attribs->{completion_entry_function} = $attribs->{list_completion_function}; - @descriptions = get_descriptions $input[1]; - $attribs->{completion_word} = \@descriptions; - } elsif ($fieldname[$i] eq "Tax assigned") { - if ($input[$i-1] == 0) { - $input[$i++] = 0; - next; - } - } else { - $attribs->{completion_word} = undef; - } - $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" || $fieldname[$i] eq "PDF") { - if ($ans =~ /[1jJyY]/) { - $input[$i] = 1; - } else { - $input[$i] = 0; - } - $i++; - } else { - $input[$i] = $ans; - $i++; - } - } - if (!$input[7]) { # USt selbst berechnen - if ($input[6] != 0) { - $input[7] = $input[8] - ($input[8] / ((100+$input[6])/100)); - } - } - - if ($input[5] =~ /[EeIi\+]/) { - $input[7] *= -1 if ($input[7] < 0); - $input[8] *= -1 if ($input[8] < 0); - } else { - $input[7] *= -1 if ($input[7] > 0); - $input[8] *= -1 if ($input[8] > 0); + foreach my $f (@fields) { + $ans = read_input($f, $fields->{$f}); + $answers->{$f} = $ans; } - $sth->execute (get_next_nr(), date_to_string($input[0]), $input[1], $input[2], $input[3], $input[4], - $input[6], $input[7], $input[8], $input[9]); - $weiter = read_input("Weiter",'j'); - $input[7] = 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}, + $answers->{paid}); + + $weiter = $answers->{weiter}; + $answers->{tax_assigned} = 0.0; } exit; -- 2.20.1