#!/usr/bin/perl
###############################################################################################################
# Vereinfachte Berechnung des Nettogehalts für Angestellte von 2002 bis 2024:
#
#  Berücksichtigt sind: Arbeitnehmer- und Verkehrsabsetzbetrag bzw. Sonderausgaben- und Webungskostenpauschale.
#  Nicht berücksichtigt sind: Pendlerpauschale, Sachbezug, Alleinverdiener-, Alleinerzieher-, Unterhalts- und 
#  Kinderabsetzbetrag, etc. Sonderzahlungen (13.+14. Gehalt) sind nur berücksichtigt bei selektiertem "SZ".
#
# (c) 2014-2022 by Ing. Peter Grobner, peter@grobner.at, http://paudorf142.at/cgi-bin/brutto2netto.cgi
###############################################################################################################

BEGIN { push @INC,'.'; }

use CGI; $q=new CGI;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);

use Brutto2Netto;

my($minYEAR,$maxYEAR)=brutto2netto();  my $YEARs=join '|',$minYEAR..$maxYEAR;

my $brutto=$q->param('brutto');     my %selectet;
my $year  =$q->param('year')||2022;    $selectet{$year}=' selected';
my %years=();                          $selectet{pens} =' checked' if($q->param('pens'));
my @netto=();                          $selectet{pa}   =' checked' if($q->param('pa'));
                        my($pa,$perN)=($selectet{pa})  ? (-1,'pro Jahr (inkl. 13.+14.Gehalt)')
                                                       : ( 0,'pro Monat');
foreach(split /\n/,$brutto)
{
 my $n=$_;

      my $t=($n=~s{(\d+)(\.(\d\d\d))(\,(\d\d))(\D|$)}{$1$3$4$6}g);
      my $k=($n=~            s{(\d+)(\,(\d\d))(\D|$)}{$1.$3$4}g);

 $year=$2 if($n=~/^\s*("?)($YEARs)(\1)(:|\s*=>)(\s|$)/); $n=~s{(\d+\.\d\d)}{ sprintf('%.2f',brutto2netto($1,$year,$pa,$q->param('pens'))); }ge;
 $year=$1 if($n=~      /\D($YEARs):\s*$/);

             $n=~s{\.(\d\d)(\D|$)}   {,$1$2}g if($k);
             $n=~s{(\d)(\d\d\d,\d\d)}{$1.$2}g if($t); push @netto,$n; $years{$year}=1;
}

my $years=join ", ",sort keys %years;
my $netto=join "\n",@netto;

if($q->param('plain'))
{
 print $q->header(-type=>"text/plain").$netto;
}
else
{
 my $textarea='textarea';

 my $what=($q->param('pens'))? 'pension'     :'gehalt'; 
 my $who =($q->param('pens'))? 'Pensionisten':'Angestellte'; 
 my $pens=($q->param('pens'))?              1:0; 

                                          my @euros=map { 25*$_ }(1,1..6100/25);

 my $chartX1=join ',',map sprintf("'%d'",$_),@euros;
 my $chartY1;
    $chartY1.=sprintf("[ %s ],\n",(join ', ',map sprintf('%.2f',100-100*brutto2netto($_,$year,0,$pens)/$_),@euros));
    $chartY1.=sprintf("[ %s ],\n",(join ', ',map sprintf('%.2f',    100*          SV($_,$year,0,$pens)/$_),@euros));
    $chartY1.=sprintf("[ %s ],\n",(join ', ',map sprintf('%.2f',    100                                  ),@euros));

 my $chartX2=join ',',map sprintf("'%d'",$_),@euros;
 my $chartY2;
    $chartY2.=sprintf("[ %s ],\n",(join ', ',map sprintf('%.2f',        brutto2netto($_,$year,0,$pens)   ),@euros));

 my $chartX3="'Bto',".join ',',($minYEAR..$maxYEAR);
                                         my @bruttos3=map 100*$_,(1..15);
 my $chartY3;                foreach my $b (@bruttos3) {
    $chartY3.=sprintf("[ %.2f, %s ],\n",$b,(join ', ',map sprintf('%.2f',brutto2netto($b,$_,0,$pens)),($minYEAR..$maxYEAR))); };

 my $chartX4="'Bto',".join ',',($minYEAR..$maxYEAR);
                                         my @bruttos4=map 500*$_,(1..7);
 my $chartY4;                foreach my $b (@bruttos4) {
    $chartY4.=sprintf("[ %.2f, %s ],\n",$b,(join ', ',map sprintf('%.2f',brutto2netto($b,$_,0,$pens)),($minYEAR..$maxYEAR))); };

 print $q->header(-type=>"text/html").qq|
 <html>
  <head>
   <script src="/chartist.js"></script>
   <script src="/chartist-plugin-axistitle.js"></script>
   <link rel="stylesheet" href="/chartist.css">
   |.CSS().qq|
   <meta charset="iso-8859-15"/>
  </head>
  <body>
   <h3>Vereinfachte Berechnung des Nettogehalts f&uuml;r $who:</h3>
   <small><small>
    (Berücksichtigt sind: Arbeitnehmer-, Verkehrs- bzw. Pensionistensabsetzbetrag sowie Sonderausgaben- und Webungskostenpauschale.
     <br> &nbsp;Nicht ber&uuml;cksichtigt sind:|.($q->param('pa')?    '':' Sonderzahlungen,').qq| Pendlerpauschale, 
     Sachbezug, Alleinverdiener-, Alleinerzieher-, Unterhalts- und Kinderabsetzbetrag, etc.
     <br> &nbsp;Siehe auch: <a href="http://onlinerechner.haude.at/bmf/brutto-netto-rechner.html" target="new">Brutto-Netto-Rechner
     des Bundesministeriums f&uuml;r Finanzen</a>)
   </small></small>
   <form method="post"><div style="float:right" class="screen_only">
    <select name="year">|.(join "\n",map "<option$selectet{$_}>$_</option>",$minYEAR..$maxYEAR).qq|
    </select>
    <input type=checkbox name="pa"   $selectet{pa}  > pro Jahr &nbsp;
    <input type=checkbox name="pens" $selectet{pens}> für Pensionisten &nbsp;
    <input type=submit value="berechnen ..." class="runButton"></div></p>
    <p>Brutto$what $years pro Monat:<br><$textarea cols="120" rows="20" name="brutto">$brutto</$textarea></p>
    <p>Netto$what $years $perN:     <br><$textarea cols="120" rows="20" name="netto" >$netto</$textarea></p>
   </form>
   <div class="page">
    <p>Abgabenquote für $year:</p>
    <div class="ct-chart ct-perfect-fourth" id="chart1" style="height: 650px; width: 1100px"></div>
    <p>Netto$what für $year:</p>
    <div class="ct-chart ct-perfect-fourth" id="chart2" style="height: 500px; width: 1100px"></div>
    <script>
      new Chartist.Line('#chart1',
           { labels: [ $chartX1 ], 
             series: [ $chartY1 ] },
           { width: 1100, height: 650, showArea: true, showPoint: false, lineSmooth: false,
             axisX: { low: 0, high: 4100, showGrid: false, labelInterpolationFnc: function(v) { return v%500? '':v     }, },
             axisY: { low: 0, high:  100, showGrid: true,  labelInterpolationFnc: function(v) { return v%  5? '':v+'%' }, 
                      type : Chartist.FixedScaleAxis, ticks: [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ], },
             plugins: [ Chartist.plugins.ctAxisTitle({
              axisX: { axisTitle: 'Sozialversicherung',  offset: { x:  0,  y:   -10 }, textAnchor: 'middle', },
              axisY: { axisTitle: 'Lohnsteuer',          offset: { x: 140, y: -1060 }, textAnchor: 'middle', },
             }) ],
           });

      new Chartist.Line('#chart2',
           { labels: [ $chartX2 ], 
             series: [ $chartY2 ] },
           { width: 1100, height: 500, showArea: true, showPoint: false, lineSmooth: false, 
             axisX: { low: 0, high: 4100, showGrid: false, labelInterpolationFnc: function(v) { return v%500? '':v     }, },
             axisY: { low: 0, high: 3900, showGrid: true, 
                      type : Chartist.FixedScaleAxis, ticks: [ 0,|.(join ', ',@bruttos4).qq| ],
                    }
           });
    </script>
   </div>
   <div class="page">
    <p>Netto$what von  $minYEAR bis $maxYEAR:</p>
    <div class="ct-chart ct-perfect-fourth" id="chart3" style="height: 650px; width: 1100px"></div>
    <div class="ct-chart ct-perfect-fourth" id="chart4" style="height: 650px; width: 1100px"></div>
    <script>
      new Chartist.Line('#chart3',
           { labels: [ $chartX3 ], 
             series: [ $chartY3 ] },
           { width: 1100, height: 650, showArea: false, showPoint: false, lineSmooth: false,
             axisY: { low: 0, high:  1550, showGrid: true, 
                      type : Chartist.FixedScaleAxis, ticks: [ 0,|.(join ', ',@bruttos3).qq| ],
                    }
           });
      new Chartist.Line('#chart4',
           { labels: [ $chartX4 ], 
             series: [ $chartY4 ] },
           { width: 1100, height: 650, showArea: false, showPoint: false, lineSmooth: false,
             axisY: { low: 0, high:  3550, showGrid: true, 
                      type : Chartist.FixedScaleAxis, ticks: [ 0,|.(join ', ',@bruttos4).qq| ],
                    }
           });
    </script>
   </div>
  </body>
 </html>|;
}
exit(0);

sub CSS { return q[
   <style>
     .screen_only { display: block !important; }
     .print_only  { display: none  !important; }
     th,td        { text-align:right; padding: 0 6px 0 6px; }
     pre          { width: 100%; border: 1px solid gray; }

     .maxwidth    { width: ].(($ENV{HTTP_USER_AGENT}=~/Firefox/)? '95ch':'120ch').q[; }
     textarea     { width: 100%; }

    @media print 
    {
     .screen_only { display: none  !important; }
     .print_only  { display: block !important; }

     .pageNow     { page-break-before: always; }
     .page        { page-break-inside: avoid; }
     .maxwidth    { width: 110ch; }
     pre          { width: 116ch; border: 1px dotted gray; }
    }

    .runButton {
	-moz-box-shadow: 0px 1px 0px 0px #fff6af;
	-webkit-box-shadow: 0px 1px 0px 0px #fff6af;
	box-shadow: 0px 1px 0px 0px #fff6af;
	background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffec64), color-stop(1, #ffab23));
	background:-moz-linear-gradient(top, #ffec64 5%, #ffab23 100%);
	background:-webkit-linear-gradient(top, #ffec64 5%, #ffab23 100%);
	background:-o-linear-gradient(top, #ffec64 5%, #ffab23 100%);
	background:-ms-linear-gradient(top, #ffec64 5%, #ffab23 100%);
	background:linear-gradient(to bottom, #ffec64 5%, #ffab23 100%);
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffec64', endColorstr='#ffab23',GradientType=0);
	background-color:#ffec64;
	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border-radius:6px;
	border:1px solid #ffaa22;
	display:inline-block;
	cursor:pointer;
	color:#333333;
	font-family:Arial;
	font-size:15px;
	font-weight:bold;
	padding:6px 24px;
	text-decoration:none;
	text-shadow:0px 1px 0px #ffee66;
        float:right;
    }
    .runButton:hover {
	background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffab23), color-stop(1, #ffec64));
	background:-moz-linear-gradient(top, #ffab23 5%, #ffec64 100%);
	background:-webkit-linear-gradient(top, #ffab23 5%, #ffec64 100%);
	background:-o-linear-gradient(top, #ffab23 5%, #ffec64 100%);
	background:-ms-linear-gradient(top, #ffab23 5%, #ffec64 100%);
	background:linear-gradient(to bottom, #ffab23 5%, #ffec64 100%);
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffab23', endColorstr='#ffec64',GradientType=0);
	background-color:#ffab23;
    }
    .runButton:active {
	position:relative;
	top:1px;
    }

    .ct-series-a .ct-line { stroke: lightred; } .ct-series-a .ct-area { fill: orange;     }
    .ct-series-b .ct-line { stroke: green;    } .ct-series-b .ct-area { fill: lightblue;  }
    .ct-series-c .ct-line { stroke: orange;   } .ct-series-b .ct-area { fill: green;      }
   </style>
]}


1;
###############################################################################################################

