dbf9abdd9d5b1fbda206cbce7cbc1ce85ba81997
[infodrom.org/service.infodrom.org] / src / InfoCon / buch / vorsteueranmeldung
1 #! /usr/bin/perl
2
3 #  infocon - Administration tool for InfoCon
4 #  Copyright (c) 2000-2016  Joey Schulze <joey@infodrom.org>
5 #
6 #  This program is free software; you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation; either version 2 of the License, or
9 #  (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15 #
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
19
20 use strict;
21 use warnings;
22
23 use DBI;
24 use Switch;
25 use Getopt::Long;
26 use Config::Simple;
27 use Term::ANSIColor;
28 use Scalar::Util qw/looks_like_number/;
29
30 use constant CONFIG => '/etc/infocon.cfg';
31
32 my $opt_mode = 'month';
33 my $opt_nocolor = 0;
34 my $opt_start;
35 my $opt_end;
36 my $cfg;
37 my $dbh;
38
39 sub help()
40 {
41     print <<EOT;
42 vorsteueranmeldung [-h|--help] [-q|--quarter] [-m|--month] [year quarter|month] [--no-color]
43 EOT
44     exit;
45 }
46
47 sub cprint
48 {
49     print color $_[0] unless $opt_nocolor;
50     print $_[1];
51     print color 'reset' unless $opt_nocolor;
52 }
53
54 sub calculate_start_end_quarter
55 {
56     my $year;
57     my $month;
58
59     if (scalar @_ == 2) {
60         $year = $_[0];
61         switch ($_[1]) {
62             case 1 { $month = 4; }
63             case 2 { $month = 7; }
64             case 3 { $month = 10; }
65             case 4 { $month = 13; }
66         }
67     } else {
68         my @now = localtime;
69         $year = $now[5] + 1900;
70         $month = $now[4] + 1;
71     }
72
73     if ($month % 3 == 1) {
74         if ($month < 13 ) {
75             $opt_start = sprintf('%04d%02d01', $year, $month - 3);
76             $opt_end = sprintf('%04d%02d01', $year, $month);
77         } else {
78             $opt_start = sprintf('%04d1001', $year);
79             $opt_end = sprintf('%04d0101', $year + 1);
80         }
81     } else {
82         die "No automatic quarter calculation possible\n";
83     }
84 }
85
86 sub calculate_start_end_month
87 {
88     my $year;
89     my $month;
90
91     if (scalar @_ == 2) {
92         $year = $_[0];
93         $month = $_[1];
94     } else {
95         my @now = localtime;
96         $year = $now[5] + 1900;
97         $month = $now[4];
98     }
99
100     if ($month > 0 && $month < 13) {
101         if ($month < 12 ) {
102             $opt_start = sprintf('%04d%02d01', $year, $month);
103             $opt_end = sprintf('%04d%02d01', $year, $month + 1);
104         } else {
105             $opt_start = sprintf('%04d%02d01', $year, $month);
106             $opt_end = sprintf('%04d0101', $year + 1);
107         }
108     } else {
109         die "No automatic month calculation possible\n";
110     }
111 }
112
113 sub calculate_start_end
114 {
115     calculate_start_end_quarter @_ if $opt_mode eq 'quarter';
116     calculate_start_end_month @_ if $opt_mode eq 'month';
117 }
118
119 sub print_table
120 {
121     my $dbh = shift;
122     my $sql = shift;
123     my @length;
124
125     return unless $sql =~ /SELECT\s+(.*?)\s+FROM/is;
126     my @columns = split /,/, $1;
127     my $i=0; while ($i < @columns) {
128         $columns[$i] = $1 if $columns[$i] =~ /.*\sAS\s(.*)/is;
129         $i++;
130     }
131
132     push @length, length $_ foreach @columns;
133
134     my $rows = $dbh->selectall_arrayref($sql);
135
136     return unless scalar @$rows && scalar @{$rows->[0]} && defined $rows->[0][0];
137
138     foreach my $row (@$rows) {
139         $i=0; while ($i < @$row) {
140             $row->[$i] = '' unless defined $row->[$i];
141             $length[$i] = length $row->[$i] if length $row->[$i] > $length[$i];
142             $i++;
143         }
144     }
145
146     my $formatstr = '';
147     my $formatlen = 0;
148     my $tablesep = '';
149     $i=0; while ($i < @columns) {
150         if (length $formatstr) {
151             $formatstr .= '|';
152             $formatlen += 1;
153             $tablesep .= '+';
154         }
155         $formatstr .= sprintf(' %%%s%ds ', (looks_like_number $rows->[0][$i]?'':'-'), $length[$i]);
156         $formatlen += 2 + $length[$i];
157         $tablesep .= '-' x (2 + $length[$i]);
158         $i++;
159     }
160     $formatstr .= "\n";
161     $tablesep .= "\n";
162
163     printf $formatstr, @columns;
164     print $tablesep;
165     printf $formatstr, @$_ foreach @$rows;
166     print "\n";
167 }
168
169 sub print_income
170 {
171     my $dbh = shift;
172     my $sql;
173
174     cprint 'bold yellow', 'Lieferungen (Einnahmen)';
175     print "\n" . "~" x 23 . "\n\n";
176
177     $sql = qq{
178 SELECT date,description,tax_percent,tax_assigned,price
179         FROM sales
180 WHERE date >= '$opt_start'  AND date < '$opt_end'
181         AND price > 0.0 AND visible = 1
182         ORDER BY date,nr};
183     print_table $dbh, $sql;
184
185     $sql = qq{
186 SELECT tax_percent as percent,sum(price) AS brutto, sum(price) - sum(tax_assigned) AS netto, sum(tax_assigned) AS tax
187         FROM sales
188 WHERE date >= '$opt_start'  AND date < '$opt_end'
189         AND price > 0.0 AND visible = 1
190         GROUP BY tax_percent
191         ORDER BY tax_percent};
192     print_table $dbh, $sql;
193
194     $sql = qq{
195 SELECT sum(price) AS brutto, sum(price) - sum(tax_assigned) AS netto, sum(tax_assigned) AS tax
196         FROM sales
197 WHERE date >= '$opt_start'  AND date < '$opt_end'
198         AND price > 0.0 AND visible = 1};
199     print_table $dbh, $sql;
200 }
201
202 sub print_outgoing
203 {
204     my $dbh = shift;
205     my $sql;
206
207     cprint 'bold yellow', 'Abziehbare Vorsteuerbeträge (Ausgaben)';
208     print "\n" . "~" x 38 . "\n\n";
209
210     $sql = qq{
211 SELECT date,description,tax_percent,tax_assigned * -1 as tax_assigned,price * -1 as price
212         FROM sales
213 WHERE date >= '$opt_start'  AND date < '$opt_end'
214         AND price < 0.0 AND visible = 1
215         AND category <> 'privat'
216         AND category <> 'tax'
217         ORDER BY date,nr};
218     print_table $dbh, $sql;
219
220     $sql = qq{
221 SELECT tax_percent AS percent,sum(price) * -1 AS brutto, sum(price) * -1 - sum(tax_assigned) * -1 AS netto, sum(tax_assigned) * -1 AS tax
222         FROM sales
223 WHERE date >= '$opt_start'  AND date < '$opt_end'
224         AND price < 0.0 AND visible = 1
225         AND category <> 'privat'
226         AND category <> 'tax'
227         GROUP BY tax_percent
228         ORDER BY tax_percent};
229     print_table $dbh, $sql;
230
231     $sql = qq{
232 SELECT sum(price) * -1 AS brutto, sum(price) * -1 - sum(tax_assigned) * -1 AS netto, sum(tax_assigned) * -1 AS tax
233         FROM sales
234 WHERE date >= '$opt_start'  AND date < '$opt_end'
235         AND price < 0.0 AND visible = 1
236         AND category <> 'privat'
237         AND category <> 'tax'};
238     print_table $dbh, $sql;
239 }
240
241 sub print_summary
242 {
243     my $dbh = shift;
244     my $sql;
245
246     cprint 'bold yellow', 'Umsatzsteuer-Voranmeldung';
247     print "\n" . "~" x 25 . "\n\n";
248
249     $sql = qq{
250 SELECT '1 Einnahmen' AS type, sum(price) AS brutto, sum(price) - sum(tax_assigned) AS netto, sum(tax_assigned) AS tax
251         FROM sales
252 WHERE date >= '$opt_start'  AND date < '$opt_end'
253         AND price > 0.0 AND visible = 1
254 UNION
255 SELECT '2 Ausgaben' AS type, sum(price) * -1 AS brutto, sum(price) * -1 - sum(tax_assigned) * -1 AS netto, sum(tax_assigned) * -1 AS tax
256         FROM sales
257 WHERE date >= '$opt_start'  AND date < '$opt_end'
258         AND price < 0.0 AND visible = 1
259         AND category <> 'privat'
260         AND category <> 'tax'
261 UNION
262 SELECT '3 Summe' AS type, sum(price) AS brutto, sum(price) - sum(tax_assigned) AS netto, sum(tax_assigned) AS tax
263         FROM sales
264 WHERE date >= '$opt_start'  AND date < '$opt_end'
265         AND visible = 1
266         AND category <> 'privat'
267         AND category <> 'tax'
268 ORDER BY type
269 };
270     print_table $dbh, $sql;
271
272 }
273
274 GetOptions ('help|h' => \&help,
275             'quarter|q' => sub {$opt_mode = 'quarter'},
276             'month|m' => sub {$opt_mode = 'month'},
277             'no-color|nocolor' => \$opt_nocolor,
278             'start' => \$opt_start,
279             'end' => \$opt_end)
280     or die("Error in command line arguments\n");
281
282 $cfg = new Config::Simple(CONFIG);
283
284 if (!defined $opt_start || !defined $opt_end) {
285     calculate_start_end @ARGV;
286 }
287
288 die "Unknown date format (yyyymmdd required)\n" unless length $opt_start == 8 && length $opt_end == 8;
289
290 $dbh = DBI->connect('dbi:Pg:dbname='.$cfg->param('local.database'), $cfg->param('local.username'));
291
292 print_income $dbh;
293 print_outgoing $dbh;
294 print_summary $dbh;
295
296 $dbh->disconnect;