{"record":{"id":"28038e911dcec7a0","repo":"aureuserp/aureuserp","slug":"invoice-total-positive-tax-percentages-must-equal","errorCode":null,"errorMessage":"Invoice total positive TAX percentages must equal 100% (got {$positive}%).","messagePattern":"Invoice total positive TAX percentages must equal 100% \\(got (.+?)%\\)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"plugins/webkul/accounts/src/Filament/Resources/TaxResource.php","lineNumber":106,"sourceCode":"                ! $refLine ||\n                $invLine['repartition_type'] !== $refLine['repartition_type'] ||\n                $invPercent !== $refPercent\n\n            ) {\n                throw new Exception('Line #'.($index + 1).' does not match between Invoice and Refund.');\n            }\n        }\n\n        $positive = $invoice\n            ->filter(fn ($l) => $l['repartition_type'] === 'tax' && is_numeric($l['factor_percent'] ?? null) && $l['factor_percent'] > 0)\n            ->sum(fn ($l) => (float) $l['factor_percent']);\n\n        $negative = $invoice\n            ->filter(fn ($l) => $l['repartition_type'] === 'tax' && is_numeric($l['factor_percent'] ?? null) && $l['factor_percent'] < 0)\n            ->sum(fn ($l) => (float) $l['factor_percent']);\n\n        if (bccomp(number_format($positive, 2, '.', ''), '100', 2) !== 0) {\n            throw new Exception(\"Invoice total positive TAX percentages must equal 100% (got {$positive}%).\");\n        }\n\n        if ($negative && bccomp(number_format($negative, 2, '.', ''), '-100', 2) !== 0) {\n            throw new Exception(\"Invoice total negative TAX percentages must equal -100% (got {$negative}%).\");\n        }\n    }\n}\n","sourceCodeStart":88,"sourceCodeEnd":114,"githubUrl":"https://github.com/aureuserp/aureuserp/blob/bd7cbeeb0c620985dfd9b88c56be7f3ea86be6b4/plugins/webkul/accounts/src/Filament/Resources/TaxResource.php#L88-L114","documentation":"Thrown by TaxResource::validateRepartitionData() when the sum of positive factor_percent values over TAX rows on the invoice side does not equal exactly 100.00. The comparison uses bccomp(number_format($positive, 2, '.', ''), '100', 2), so the sum must total 100.00 at two decimal places — a tax must fully allocate 100% of its computed amount across the positive tax repartition rows.","triggerScenarios":"Saving a tax whose TAX rows sum to something other than 100: three rows of 33.33 (sums to 99.99), a split of 50/40/10 (sums to 100 but a typo makes 50/40/5), or a single row of 50 because a second row was removed after splitting.","commonSituations":"Rounding splits like 33.33 x 3 instead of 33.34 + 33.33 + 33.33; partial allocation in the mistaken belief the remaining percent can be left unassigned; currency-style percentages (e.g. 21.5 total plus a 50% deduction where the negative side is handled separately — positive rows must still total 100).","solutions":["Adjust positive TAX factor percents so they total exactly 100.00 (use 33.34 + 33.33 + 33.33 for thirds).","Remove unused TAX rows instead of zeroing their factor — a 0% row is harmless to the sum but usually means a leftover row.","For taxes with deductions, keep positive rows summing to 100 and put the deduction in negative rows (see the -100 check)."],"exampleFix":"// before (33.33 x 3 = 99.99)\n$invoiceLines = [\n    ['repartition_type' => 'base', 'factor_percent' => null],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.33],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.33],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.33],\n];\n\n// after (33.34 + 33.33 + 33.33 = 100.00)\n$invoiceLines = [\n    ['repartition_type' => 'base', 'factor_percent' => null],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.34],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.33],\n    ['repartition_type' => 'tax', 'factor_percent' => 33.33],\n];","handlingStrategy":"validation","validationCode":"$positive = collect($invoiceLines)\n    ->filter(fn ($l) => ($l['repartition_type'] ?? null) === 'tax' && ($l['factor_percent'] ?? 0) > 0)\n    ->sum(fn ($l) => (float) $l['factor_percent']);\nif (bccomp(number_format($positive, 2, '.', ''), '100', 2) !== 0) {\n    // adjust factors to total exactly 100.00 before saving\n}","typeGuard":"function positiveTaxFactorsTotal100(array $lines): bool\n{\n    $sum = collect($lines)\n        ->filter(fn ($l) => ($l['repartition_type'] ?? null) === 'tax' && ($l['factor_percent'] ?? 0) > 0)\n        ->sum(fn ($l) => (float) $l['factor_percent']);\n    return bccomp(number_format($sum, 2, '.', ''), '100', 2) === 0;\n}","tryCatchPattern":"catch (Exception $e) when (str_contains($e->getMessage(), 'positive TAX percentages')) { /* read the reported total from the message and rebalance */ }","preventionTips":["Use 2-decimal factors that sum exactly to 100.00 (33.34 + 33.33 + 33.33).","Show a live sum of positive TAX factors next to the repeater in the form."],"tags":["tax","repartition","percentage","bccomp","validation"],"backgroundTag":"percentage-total-validation","analyzedSha":"bd7cbeeb0c620985dfd9b88c56be7f3ea86be6b4","analyzedAt":"2026-08-21T06:41:00.338Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}