Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

strategy:
matrix:
php-versions: [8.5]
php-versions: ['8.4', '8.5']

steps:
- name: Checkout
Expand Down
16 changes: 8 additions & 8 deletions src/Service/IRPF.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,12 @@ private function usaDeducaoFavoravel(): bool

private function calculaDeducaoFavoravel(float $inss, int $dependentes): float
{
$simplificada = $this->calculaDeducaoSimplificada($inss);
$simplificada = $this->calculaDeducaoSimplificada();
$tradicional = $this->calculaDeducaoTradicional($inss, $dependentes);
if ($simplificada <= $this->tabela['aliquotas'][0]['max'] * 0.25) {
// Compare both actual deductions, including dependents. The previous
// test compared the simplified value with its cap and ignored the
// total traditional deduction when INSS was below the cap.
if ($simplificada > $tradicional) {
$this->tipoDeducao = 'simplificada';
return $simplificada;
}
Expand All @@ -156,13 +159,10 @@ public function getTipoDeducao(): string
return $this->tipoDeducao;
}

private function calculaDeducaoSimplificada(float $inss): float
private function calculaDeducaoSimplificada(): float
{
$deducaoAliquotaPrimeiraFaixa = $this->tabela['aliquotas'][0]['max'] * 0.25;
if ($deducaoAliquotaPrimeiraFaixa > $inss) {
return $deducaoAliquotaPrimeiraFaixa;
}
return $inss;
// This option replaces (rather than adds to) legally allowed deductions.
return $this->tabela['aliquotas'][0]['max'] * 0.25;
}

private function calculaDeducaoTradicional(float $inss, int $dependentes): float
Expand Down
8 changes: 4 additions & 4 deletions src/Service/modeloTabelaINSS.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"2023": {
"0.11": 7087.22,
"0.2": 7087.22
"0.11": 7507.49,
"0.2": 7507.49
},
"2024": {
"0.11": 7087.22,
"0.2": 7087.22
"0.11": 7786.02,
"0.2": 7786.02
},
"2025": {
"0.11": 8157.41,
Expand Down
59 changes: 48 additions & 11 deletions src/Service/modeloTabelaIRPF.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
"min": 1993.99,
"max": 2826.65,
"aliquota": 0.075,
"deducao": 142.80
"deducao": 142.8
},
{
"min": 2826.66,
"max": 3751.05,
"aliquota": 0.15,
"deducao": 354.80
"deducao": 354.8
},
{
"min": 3751.06,
Expand Down Expand Up @@ -52,13 +52,13 @@
"min": 2112.01,
"max": 2826.65,
"aliquota": 0.075,
"deducao": 158.40
"deducao": 158.4
},
{
"min": 2826.66,
"max": 3751.05,
"aliquota": 0.15,
"deducao": 370.40
"deducao": 370.4
},
{
"min": 3751.06,
Expand Down Expand Up @@ -91,13 +91,13 @@
"min": 2112.01,
"max": 2826.65,
"aliquota": 0.075,
"deducao": 158.40
"deducao": 158.4
},
{
"min": 2826.66,
"max": 3751.05,
"aliquota": 0.15,
"deducao": 370.40
"deducao": 370.4
},
{
"min": 3751.06,
Expand All @@ -114,13 +114,13 @@
]
},
{
"mes_inicio": 1,
"mes_inicio": 2,
"mes_fim": null,
"deducao_por_dependente": 189.59,
"aliquotas": [
{
"min": 0,
"max": 2259.20,
"max": 2259.2,
"aliquota": 0,
"deducao": 0
},
Expand Down Expand Up @@ -154,12 +154,12 @@
"2025": [
{
"mes_inicio": 1,
"mes_fim": null,
"mes_fim": 4,
"deducao_por_dependente": 189.59,
"aliquotas": [
{
"min": 0,
"max": 2259.20,
"max": 2259.2,
"aliquota": 0,
"deducao": 0
},
Expand Down Expand Up @@ -188,6 +188,43 @@
"deducao": 896
}
]
},
{
"mes_inicio": 5,
"mes_fim": 12,
"deducao_por_dependente": 189.59,
"aliquotas": [
{
"min": 0,
"max": 2428.8,
"aliquota": 0,
"deducao": 0
},
{
"min": 2428.81,
"max": 2826.65,
"aliquota": 0.075,
"deducao": 182.16
},
{
"min": 2826.66,
"max": 3751.05,
"aliquota": 0.15,
"deducao": 394.16
},
{
"min": 3751.06,
"max": 4664.68,
"aliquota": 0.225,
"deducao": 675.49
},
{
"min": 4664.69,
"max": null,
"aliquota": 0.275,
"deducao": 908.73
}
]
}
],
"2026": [
Expand All @@ -212,7 +249,7 @@
"aliquotas": [
{
"min": 0,
"max": 2428.80,
"max": 2428.8,
"aliquota": 0,
"deducao": 0
},
Expand Down
8 changes: 4 additions & 4 deletions tests/php/Service/INSSTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ public static function providerCalcula(): array
[7000, 2023, 0.2, 1400],
[7087.16, 2023, 0.2, 1417.43],
[7087.17, 2023, 0.2, 1417.43],
// Arredondamentos de centavos da base máxima começa aqui
// Valores abaixo do teto oficial de 2023 (R$ 7.507,49)
[7087.18, 2023, 0.2, 1417.44],
[7087.19, 2023, 0.2, 1417.44],
[7088, 2023, 0.2, 1417.44],
[8000, 2023, 0.2, 1417.44],
[100000, 2023, 0.2, 1417.44],
[7088, 2023, 0.2, 1417.60],
[8000, 2023, 0.2, 1501.50],
[100000, 2023, 0.2, 1501.50],
[8475.54, 2026, 0.2, 1695.11],
[8475.55, 2026, 0.2, 1695.11],
[8475.56, 2026, 0.2, 1695.11],
Expand Down
64 changes: 64 additions & 0 deletions tests/php/Service/IRPFRegressionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

use Impostos\Service\IRPF;
use PHPUnit\Framework\TestCase;

final class IRPFRegressionTest extends TestCase
{
public function testHistoricalInssCapsMatchPublishedOfficialValues(): void
{
self::assertEqualsWithDelta(1501.498, (new \Impostos\Service\INSS(2023))->calcula(10000), 0.001);
self::assertEqualsWithDelta(1557.204, (new \Impostos\Service\INSS(2024))->calcula(10000), 0.001);
self::assertEqualsWithDelta(1695.11, (new \Impostos\Service\INSS(2026))->calcula(10000), 0.001);
}

public function testFebruary2024AppliesUpdatedTableNotJanuaryTable(): void
{
self::assertSame(0.075, (new IRPF(2024, 1))->getFaixa(2200.00)['aliquota']);
self::assertSame(0, (new IRPF(2024, 2))->getFaixa(2200.00)['aliquota']);
}

public function testSimplifiedDiscountDoesNotAddToSocialSecurityContributions(): void
{
$irpf = new IRPF(2026, 5);
$base = $irpf->calculaBase(4000.00, 400.00, 0);
self::assertEqualsWithDelta(3392.80, $base, 0.001);
self::assertSame('simplificada', $irpf->getTipoDeducao());
}

public function testJanuary2025RetainsOlderBracket(): void
{
self::assertSame(0.075, (new IRPF(2025, 1))->getFaixa(2300.00)['aliquota']);
}

public function testMay2025UsesUpdatedOfficialBracket(): void
{
self::assertSame(0, (new IRPF(2025, 5))->getFaixa(2300.00)['aliquota']);
self::assertEqualsWithDelta(182.16, (new IRPF(2025, 5))->getFaixa(2700.00)['deducao'], 0.00001);
self::assertEqualsWithDelta(607.20, 2428.80 * 0.25, 0.00001);
}

public function testTraditionalDeductionWinsWhenDependentsExceedSimplifiedDiscount(): void
{
$irpf = new IRPF(2026, 1);
self::assertEqualsWithDelta(4248.82, $irpf->calculaBase(5200.00, 572.00, 2), 0.00001);
self::assertSame('tradicional', $irpf->getTipoDeducao());
}

public function testSimplifiedDeductionWinsWithoutDependents(): void
{
$irpf = new IRPF(2026, 1);
self::assertEqualsWithDelta(4592.80, $irpf->calculaBase(5200.00, 572.00, 0), 0.00001);
self::assertSame('simplificada', $irpf->getTipoDeducao());
}

public function test2026ReductionMatchesFederalRevenueExample(): void
{
$irpf = new IRPF(2026, 1);
$base = $irpf->calculaBase(6000.00, 649.60, 0);
self::assertEqualsWithDelta(5350.40, $base, 0.00001);
self::assertEqualsWithDelta(382.88, round($irpf->calcula($base, 0), 2), 0.01);
}
}
14 changes: 7 additions & 7 deletions tests/php/Service/IRPFTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public static function providerCalculaBase(): array
[2023, 5, 300, 0, 0, 'simplificada'],
[2023, 5, 1000, 0, 472, 'simplificada'],
[2023, 5, 3000, 0, 2400, 'tradicional'],
[2023, 5, 9000, 0, 7582.556, 'tradicional'],
[2023, 5, 9000, 0, 7498.502, 'tradicional'],
[2023, 5, 2600, 0, 2072, 'simplificada'],
[2023, 4, 2600, 0, 2080, 'tradicional'],
[2026, 1, 300, 0, 0, 'simplificada'],
Expand Down Expand Up @@ -201,20 +201,20 @@ public static function providerCalculaImposto(): array
# Sem dependente
[2023, 5, 1000, 0, 0, 'simplificada'],
[2023, 5, 3000, 0, 21.6, 'tradicional'],
[2023, 5, 9000, 0, 1200.24, 'tradicional'],
[2023, 5, 9000, 0, 1177.13, 'tradicional'],
[2023, 5, 2600, 0, 0, 'simplificada'],
[2023, 4, 2600, 0, 13.2, 'tradicional'],
# Com 1 dependente
[2023, 5, 1000, 1, 0, 'simplificada'],
[2023, 5, 3000, 1, 7.38, 'tradicional'],
[2023, 5, 9000, 1, 1148.11, 'tradicional'],
[2023, 5, 2600, 1, 0, 'simplificada'],
[2023, 5, 9000, 1, 1124.99, 'tradicional'],
[2023, 5, 2600, 1, 0, 'tradicional'],
[2023, 4, 2600, 1, 0, 'tradicional'],
# Com 2 dependentes
[2023, 5, 1000, 2, 0, 'simplificada'],
[2023, 5, 1000, 2, 0, 'tradicional'],
[2023, 5, 3000, 2, 0, 'tradicional'],
[2023, 5, 9000, 2, 1095.97, 'tradicional'],
[2023, 5, 2600, 2, 0, 'simplificada'],
[2023, 5, 9000, 2, 1072.85, 'tradicional'],
[2023, 5, 2600, 2, 0, 'tradicional'],
[2023, 4, 2600, 2, 0, 'tradicional'],
[2026, 1, 1000, 0, 0, 'simplificada'],
[2026, 1, 3000, 0, 0, 'simplificada'],
Expand Down
Loading