Payroll::US::StateIncome.pm

StateIncome->calculate(
    gross,            # - gross pay
    date,             #- date of payment format YYYYMMDD
    method,         #- specifies mthod to use. currently only 1
    allowances    #, - state allowances claimed, integer
    period,             #- annual, semiannual, quarterly, monthly, semimonthly, biweekly, weekly, daily
    marital,             #- single, married
    federal,             #- amount of federal tax withheld here
    fYTD             #- total federal tax withheld yeart to date
)
The data will be stored by date in a hash, so that calculations will use the proper rates.

iterate over sorted keys descending in data hash.  
  Compare $date to keys.  
  Stop when $date >= key.  
  set $foundDate = $key.
  If date < all keys, that is an error.  

data{$foundDate}->
{tables}

ex. data{20010101}->
{dailyWithholdingAllowance}
= 11.15

{dailyTableRows}[X]


The periodDays hash holds the number of days in a period
periodDays->
{annual}
= 260

{semiannual}
= 130

{quarterly}
= 65

{monthly}
= 21.67

{semimonthly}
= 10.84

{biweekly}
= 10

{weekly}
= 5

{daily}
= 1

To calculate the withholding allowance
withholdingAllowance = periodDays->{$period} * data->{$foundDate}->{dailyWithholdingAllowance}
modifiedGross = gross - (allowances * withholdingAllowance)

Use modifiedGross value to determine tax bracket and subsequent percentage by looking up in data{$foundDate}->{tables}.  Only generate withholding tables as needed.  This will allow for caching type functionality and speed optimizations.

How to generate a table.

generate_table ( period, marital, table=>data{$foundDate}->{tables} )
{
   @dailyTableRows = $data->{$foundDate}->{$dailyTableRows}
   for $row = 0; row < scalar ($dailyTableRows); row++
   {
      if $row == 0
         $base = 0;
     else
     {
        base = $dailyTableRows[row -1]->percent *
             ($dailyTableRows[row]->top - $dailyTableRows[row -1]->top)
             + $dailyTableRows[row-1]->base
     }
     $top = $row->{top} * periodDays{period}
     $top *= $row->{marriedRatio} if $marital eq "married"

     %tempRow = { top => $top,
        base => base ,  
        percent => $row->{percent} } ;
     #dont forget to create array single first       
     push($table->{$period}->{$marital}, \%tempRow)
  }
}

The lookuptables are generated from the data stored in the daily table.  
There is an array for the rows sorted descending.  This allows us to check the greatest case first.  No corner cases.
{dailyTableRows}
[$row]->
{top}


{percent}


{marriedRatio}

generated tables look like this

tables
{$period =>
{ single =>
[



{top => , base => , percent => } ,



] ,


married =>
[



{top => , base => , percent => } ,



]


},


}




these variables will be lookups from the above generated table.
if !tableexists
  generate_table(period, marital, table =>)
tax = $base + (( modifiedGross - $top)  * $percent)