Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
MarginVatCalculator
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
4.00
0.00% covered (danger)
0.00%
0 / 1
 calculate
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
4.00
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;
14
15/**
16 * Calculator for Margin Scheme VAT (Special scheme: Tax is calculated only on positive gross margin).
17 */
18final readonly class MarginVatCalculator extends AbstractTaxCalculator
19{
20    private const string DEFAULT_MARGIN_CLAUSE = 'Special scheme - Margin procedure';
21
22    /**
23     * @inheritDoc
24     */
25    public function calculate(
26        float $unitPrice,
27        float $quantity,
28        float $discountAmount,
29        TaxRate $taxRate,
30        RoundingMethod $roundingMethod,
31        ?float $costPrice = null,
32    ): LineTaxResult {
33        $sellingTotal = $this->calculateBaseAmount($unitPrice, $quantity, $discountAmount, $roundingMethod);
34        $totalCost = ($costPrice !== null) ? $roundingMethod->round($costPrice * $quantity, 2) : 0.0;
35        $marginGross = max(0.0, $sellingTotal - $totalCost);
36
37        if ($marginGross <= 0.0 || !$this->isStandardTaxableRate($taxRate)) {
38            return $this->buildZeroTaxResult($taxRate, $sellingTotal, self::DEFAULT_MARGIN_CLAUSE);
39        }
40
41        $divisor = 1.0 + ($taxRate->ratePercent / 100.0);
42        $marginNet = $roundingMethod->round($marginGross / $divisor, 2);
43        $taxOnMargin = $roundingMethod->round($marginGross - $marginNet, 2);
44        $effectiveNet = $roundingMethod->round($sellingTotal - $taxOnMargin, 2);
45
46        return $this->buildResult(
47            taxRate: $taxRate,
48            netAmount: $effectiveNet,
49            taxAmount: $taxOnMargin,
50            grossAmount: $sellingTotal,
51            whtAmount: 0.0,
52            defaultLegalClause: self::DEFAULT_MARGIN_CLAUSE
53        );
54    }
55}