Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.00% covered (success)
96.00%
24 / 25
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractTaxCalculator
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
4 / 4
5
100.00% covered (success)
100.00%
1 / 1
 calculateBaseAmount
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isStandardTaxableRate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 buildResult
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 buildZeroTaxResult
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Tax\Domain\Service\Calculator;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Modules\Tax\Domain\Model\TaxRate;
12use App\Modules\Tax\Domain\ValueObject\LineTaxResult;
13use App\Modules\Tax\Domain\ValueObject\RoundingMethod;
14use App\Modules\Tax\Domain\ValueObject\TaxStatus;
15
16/**
17 * Base abstract calculator providing shared base amount calculation, zero-tax resolution,
18 * and result formatting for specialized tax calculation algorithms.
19 */
20abstract readonly class AbstractTaxCalculator implements TaxCalculatorInterface
21{
22    /**
23     * Calculates rounded base amount after discount.
24     */
25    protected function calculateBaseAmount(
26        float $unitPrice,
27        float $quantity,
28        float $discountAmount,
29        RoundingMethod $roundingMethod
30    ): float {
31        $raw = max(0.0, ($unitPrice * $quantity) - $discountAmount);
32        return $roundingMethod->round($raw, 2);
33    }
34
35    /**
36     * Checks if given tax rate requires standard non-zero calculation.
37     */
38    protected function isStandardTaxableRate(TaxRate $taxRate): bool
39    {
40        return $taxRate->taxStatus === TaxStatus::STANDARD && $taxRate->ratePercent > 0.0;
41    }
42
43    /**
44     * Builds standardized LineTaxResult.
45     */
46    protected function buildResult(
47        TaxRate $taxRate,
48        float $netAmount,
49        float $taxAmount,
50        float $grossAmount,
51        float $whtAmount = 0.0,
52        ?string $defaultLegalClause = null
53    ): LineTaxResult {
54        return new LineTaxResult(
55            taxCode: $taxRate->taxCode,
56            taxName: $taxRate->taxName,
57            ratePercent: $taxRate->ratePercent,
58            calculationMode: $taxRate->calculationMode,
59            taxStatus: $taxRate->taxStatus,
60            netAmount: $netAmount,
61            taxAmount: $taxAmount,
62            grossAmount: $grossAmount,
63            whtAmount: $whtAmount,
64            legalClause: $taxRate->legalExemptionNote ?? $defaultLegalClause,
65            fiscalCode: $taxRate->fiscalCode,
66        );
67    }
68
69    /**
70     * Builds zero-tax LineTaxResult for exempt, reverse charge, or 0% rates.
71     */
72    protected function buildZeroTaxResult(
73        TaxRate $taxRate,
74        float $amount,
75        ?string $defaultLegalClause = null
76    ): LineTaxResult {
77        return $this->buildResult(
78            taxRate: $taxRate,
79            netAmount: $amount,
80            taxAmount: 0.0,
81            grossAmount: $amount,
82            whtAmount: 0.0,
83            defaultLegalClause: $defaultLegalClause
84        );
85    }
86}