diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 6df58bf..da47ffb 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: - php-versions: [8.5] + php-versions: ['8.4', '8.5'] steps: - name: Checkout diff --git a/src/Service/IRPF.php b/src/Service/IRPF.php index 549a029..b3ec723 100644 --- a/src/Service/IRPF.php +++ b/src/Service/IRPF.php @@ -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; } @@ -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 diff --git a/src/Service/modeloTabelaINSS.json b/src/Service/modeloTabelaINSS.json index 40bdf4b..ab015c4 100644 --- a/src/Service/modeloTabelaINSS.json +++ b/src/Service/modeloTabelaINSS.json @@ -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, diff --git a/src/Service/modeloTabelaIRPF.json b/src/Service/modeloTabelaIRPF.json index 294aa9c..6c0d823 100644 --- a/src/Service/modeloTabelaIRPF.json +++ b/src/Service/modeloTabelaIRPF.json @@ -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, @@ -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, @@ -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, @@ -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 }, @@ -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 }, @@ -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": [ @@ -212,7 +249,7 @@ "aliquotas": [ { "min": 0, - "max": 2428.80, + "max": 2428.8, "aliquota": 0, "deducao": 0 }, diff --git a/tests/php/Service/INSSTest.php b/tests/php/Service/INSSTest.php index 8ea43ba..2bda1a4 100644 --- a/tests/php/Service/INSSTest.php +++ b/tests/php/Service/INSSTest.php @@ -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], diff --git a/tests/php/Service/IRPFRegressionTest.php b/tests/php/Service/IRPFRegressionTest.php new file mode 100644 index 0000000..5f28626 --- /dev/null +++ b/tests/php/Service/IRPFRegressionTest.php @@ -0,0 +1,64 @@ +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); + } +} diff --git a/tests/php/Service/IRPFTest.php b/tests/php/Service/IRPFTest.php index 4287aae..4c96e43 100644 --- a/tests/php/Service/IRPFTest.php +++ b/tests/php/Service/IRPFTest.php @@ -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'], @@ -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'],