X-Git-Url: https://git.infodrom.org/?p=infodrom.org%2Fservice.infodrom.org;a=blobdiff_plain;f=src%2FInfoCon%2Fbuch%2Finfocon;h=c10413b7a5fb262a77af79b92d00570aa6e322be;hp=4e2ba984ed5d1096b6337b7ad46d9fd9ba2a7b75;hb=65cb3d52b45296e9a5f6a5d06fdb5d7f4d99d749;hpb=cfd80d31b3325d263b4d7ddc5269c468740c63b4 diff --git a/src/InfoCon/buch/infocon b/src/InfoCon/buch/infocon index 4e2ba98..c10413b 100755 --- a/src/InfoCon/buch/infocon +++ b/src/InfoCon/buch/infocon @@ -1,7 +1,7 @@ #! /usr/bin/perl -# infocon - Admin-Tool for InfoCon -# Copyright (c) 1998-2003,2005-7 Martin Schulze +# infocon - Administration tool for InfoCon +# 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,20 +17,30 @@ # 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; -$table = "sales"; -$engine = "dbi:Pg:dbname=infocon"; -$dbh = DBI->connect($engine); +my $table = "sales"; +my $engine = "dbi:Pg:dbname=infocon"; +my $dbh = DBI->connect($engine); if (!$dbh) { print "Access to database denied!\n"; return 1; } -@categories = (); +my %data; +my @categories = (); +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 { @@ -43,9 +53,11 @@ sub sdate # sub date_to_string { + my ($day,$mon,$year); + return "" if (!$_[0]); - ($date_sec,$date_min,$date_hour,$date_mday,$date_mon,$date_year,$date_wday,$date_isdst) + my ($date_sec,$date_min,$date_hour,$date_mday,$date_mon,$date_year,$date_wday,$date_isdst) = localtime; if ($_[0] eq "heute" || $_[0] eq "sofort" || $_[0] eq "pronto" || $_[0] eq "today" || $_[0] eq "now") { @@ -75,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); } @@ -110,7 +155,7 @@ sub sales_list my $sth; my $d; - if ($where !~ /visible/ && (!$opt_all || $opt_all == 0)) { + if ($where && $where !~ /visible/ && (!$opt_all || $opt_all == 0)) { if ($where) { $where .= " AND visible = 1"; } else { @@ -119,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) { @@ -140,51 +187,38 @@ 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 && ($rc = $sth->execute) > 0) { - print " Nr. Datum Bezeichnung Betrag\n"; - print "------------------------------------------------------------------\n"; + if ($sth && (my $rc = $sth->execute) > 0) { + 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; } -} - -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 && ($rc = $sth->execute) > 0) { - while (@row = $sth->fetchrow_array) { - push(@arr, $row[0]) if ($row[0]); - } - } - return @arr; + $data{'done'} = 1; } sub get_categories @@ -196,7 +230,7 @@ sub get_categories $query = "SELECT DISTINCT category FROM $table ORDER by category"; $sth = $dbh->prepare($query); - if ($sth && ($rc = $sth->execute) > 0) { + if ($sth && (my $rc = $sth->execute) > 0) { while (@row = $sth->fetchrow_array) { push(@arr, $row[0]) if ($row[0]); } @@ -206,27 +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 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 = ''; } + + 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; } @@ -254,83 +427,122 @@ 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 $query; + my $ans; my ($date_sec,$date_min,$date_hour,$date_mday,$date_mon,$date_year,$date_wday,$date_isdst) = localtime; - @categories = get_categories unless @categories; - my @descriptions = get_descriptions; + 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'); - $term->addhistory($_) foreach (@categories); - $term->addhistory($_) foreach (@descriptions); + @categories = get_categories unless @categories; - my $attribs = $term->Attribs; + $term = new Term::ReadLine '' unless $term; - $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; - } 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; +} + +sub buchung_hidden +{ + $table = "sales_dm"; + sales_list("visible = 0"); + $table = "sales"; + sales_list("visible = 0"); + exit; +} + +sub buchung_unpaid +{ + $table = "sales"; + sales_list("paid = 0"); + exit; } sub usage @@ -340,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"; @@ -352,114 +565,76 @@ sub usage exit 0; } -$term = new Term::ReadLine ''; -$i = 0; -$opt_all = 0; -$opt_verbose = 0; -$opt_year = 0; -usage unless @ARGV; -while ($i <= $#ARGV) { - # Some aliases - if ($ARGV[$i] eq "-bc") { - $ARGV[$i] = "--buchung-category"; - } elsif ($ARGV[$i] eq "-bi") { - $ARGV[$i] = "--buchung-input"; - } elsif ($ARGV[$i] eq "-bh") { - $ARGV[$i] = "--buchung-hidden"; - } elsif ($ARGV[$i] eq "-bu") { - $ARGV[$i] = "--buchung-unpaid"; - } elsif ($ARGV[$i] eq "-lc") { - $ARGV[$i] = "--list-categories"; - } +%data = ( + 'category' => undef, + 'done' => undef, + 'pay' => undef, + '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}, + 'pay=s' => \$data{pay}, + 'unpay=s' => \$data{unpay}, + 'hide=s' => \$data{hide}, + 'unhide=s' => \$data{unhide}, + 'year=i' => \$opt_year, + 'date=s' => \$opt_date, + 'direction|d=s' => \$opt_direction, + 'mailto:s' => \$data{mailto}, + 'all' => \$opt_all, + 'verbose' => \$opt_verbose, + 'help' => \&usage, + 'dm' => sub {$table = "sales_dm"}, + 'buchung-input|bi' => \&buchung_input, + 'buchung-unpaid|bu' => \&buchung_unpaid, + 'buchung-hidden|bh' => \&buchung_hidden, + 'list-categories|lc' => \$data{'list-categories'}, + ); + +my $cmdln = 'infocon ' . join (' ', @ARGV); +GetOptions(%options); + +if ($opt_year != 0 && $opt_year < 2002) { + $table = "sales_dm"; +} - if ($ARGV[$i] eq "-h" || $ARGV[$i] eq "--help") { - usage; - } elsif ($ARGV[$i] =~ /^--list-/) { - $ARGV[$i] =~ s/^--list-//; - if ($ARGV[$i] eq "categories") { - list_categories; - } else { - usage; - } - } elsif ($ARGV[$i] =~ /^--buchung-/) { - $ARGV[$i] =~ s/^--buchung-//; - if ($ARGV[$i] eq "category") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] !~ /^-/)) { - $i++; - sales_list("category = '$ARGV[$i]'"); - } else { - sales_list; - } - } elsif ($ARGV[$i] eq "hidden") { - $saved_table = $table; - $table = "sales_dm"; - sales_list("visible = 0"); - $table = "sales"; - sales_list("visible = 0"); - $table = $table_saved; - } elsif ($ARGV[$i] eq "input") { - buchung_input; - } elsif ($ARGV[$i] eq "unpaid") { - $saved_table = $table; - $table = "sales_dm"; - sales_list("paid = 0"); - $table = "sales"; - sales_list("paid = 0"); - $table = $table_saved; - } else { - usage; - } - } elsif ($ARGV[$i] eq "--pay") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] !~ /^-/) - && ($ARGV[$i+1] =~ /^\d+$/)) { - $i++; - pay_invoice ($ARGV[$i], 1); - } - } elsif ($ARGV[$i] eq "--unpay") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] !~ /^-/) - && ($ARGV[$i+1] =~ /^\d+$/)) { - $i++; - pay_invoice ($ARGV[$i], 0); - } - } elsif ($ARGV[$i] eq "--hide") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] !~ /^-/) - && ($ARGV[$i+1] =~ /^\d+$/)) { - $i++; - hide_invoice ($ARGV[$i], 1); - } - } elsif ($ARGV[$i] eq "--unhide") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] !~ /^-/) - && ($ARGV[$i+1] =~ /^\d+$/)) { - $i++; - hide_invoice ($ARGV[$i], 0); - } - } elsif ($ARGV[$i] eq "--year" || $ARGV[$i] eq "-y") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] =~ /^(\d+)$/)) { - $i++; - $opt_year = $1; - if ($opt_year < 70) { - $opt_year += 2000; - } elsif ($opt_year < 100) { - $opt_year += 1900; - } - if ($opt_year < 2002) { - $table = "sales_dm"; - } elsif ($opt_year > 2001) { - $table = "sales"; - } - } - } elsif ($ARGV[$i] eq "--direction" || $ARGV[$i] eq "--dir" - || $ARGV[$i] eq "-d") { - if ($i+1 <= $#ARGV && ($ARGV[$i+1] =~ /^(in|out)$/i)) { - $i++; - $opt_direction = $1; - } - } elsif ($ARGV[$i] eq "--dm") { - $table = "sales_dm"; - } elsif ($ARGV[$i] eq "-a" || $ARGV[$i] eq "--all") { - $opt_all = 1; - } elsif ($ARGV[$i] eq "-v" || $ARGV[$i] eq "--verbose") { - $opt_verbose = 1; +if (defined $opt_direction) { + usage unless $opt_direction =~ /^(in|out)$/i; +} + +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"; } - $i++; +} + +if (defined $data{category}) { + sales_list; + exit; +} elsif (defined $data{'list-categories'}) { + list_categories; +} elsif (defined $data{pay}) { + pay_invoice($data{pay}, 1); +} elsif (defined $data{unpay}) { + pay_invoice($data{unpay}, 0); +} elsif (defined $data{hide}) { + hide_invoice($data{hide}, 1); +} elsif (defined $data{unhide}) { + hide_invoice($data{unhide}, 0); +} else { + usage; }