Passed
Push — development ( e0dfaa )
by Carlos C
06:49
created

Calculator::setPaymentTaxesPrecision()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace CfdiUtils\SumasPagos20;
4
5
use CfdiUtils\Nodes\NodeInterface;
6
use CfdiUtils\Nodes\Nodes;
7
8
class Calculator
9
{
10
    /** @var int */
11
    private $paymentTaxesPrecision;
12
13
    /** @var Currencies */
14
    private $currencies;
15
16 13
    public function __construct(int $paymentTaxesPrecision = 6, ?Currencies $currencies = null)
17
    {
18 13
        $this->setPaymentTaxesPrecision($paymentTaxesPrecision);
19 13
        $this->currencies = $currencies ?? new Currencies(['MXN' => 2, 'USD' => 2]);
20
    }
21
22 13
    public function getPaymentTaxesPrecision(): int
23
    {
24 13
        return $this->paymentTaxesPrecision;
25 13
    }
26 13
27
    public function setPaymentTaxesPrecision(int $paymentTaxesPrecision): void
28
    {
29 13
        $this->paymentTaxesPrecision = min(6, max(0, $paymentTaxesPrecision));
30 13
    }
31
32
    public function getCurrencies(): Currencies
33 13
    {
34
        return $this->currencies;
35 13
    }
36 13
37 13
    public function setCurrencies(Currencies $currencies): void
38 13
    {
39 13
        $this->currencies = $currencies;
40 13
    }
41
42 13
    public function calculate(NodeInterface $nodePagos): Pagos
43 13
    {
44 13
        $pagos = [];
45 13
        foreach ($nodePagos->searchNodes('pago20:Pago') as $nodePago) {
46 13
            $pagos[] = $this->buildPago($nodePago);
47
        }
48
49 13
        $totales = $this->buildTotales($pagos);
50
        return new Pagos($totales, ...$pagos);
51 13
    }
52
53 13
    private function buildPago(NodeInterface $nodePago): Pago
54 13
    {
55
        $sumMonto = new Decimal('0');
56 13
        $impuestos = new Impuestos();
57 13
        foreach ($nodePago->searchNodes('pago20:DoctoRelacionado') as $nodeDoctoRelacionado) {
58 13
            $doctoRelacionado = $this->buildDoctoRelacionado($nodeDoctoRelacionado);
59 13
            $sumMonto = $sumMonto->sum($doctoRelacionado->getImpPagado());
60 13
            $impuestos = $impuestos->aggregate($doctoRelacionado->getImpuestos());
61 13
        }
62 13
        $montoMinimo = $sumMonto->truncate($this->currencies->get($nodePago['MonedaP']));
63 13
        $monto = (isset($nodePago['Monto'])) ? new Decimal($nodePago['Monto']) : $montoMinimo;
64 13
        $impuestos = $impuestos->round($this->paymentTaxesPrecision);
65
        $tipoCambioP = new Decimal($nodePago['TipoCambioP']);
66 13
        return new Pago($monto, $montoMinimo, $tipoCambioP, $impuestos);
67
    }
68
69
    private function buildDoctoRelacionado(NodeInterface $nodeDoctoRelacionado): DoctoRelacionado
70 13
    {
71
        $equivalenciaDr = new Decimal($nodeDoctoRelacionado['EquivalenciaDR']);
72 13
73 13
        $impPagado = new Decimal($nodeDoctoRelacionado['ImpPagado']);
74 12
        $impPagado = $impPagado->divide($equivalenciaDr);
75 12
76 12
        $traslados = $this->processImpuestosTraslados(
77 12
            $equivalenciaDr,
78 12
            $nodeDoctoRelacionado->searchNodes('pago20:ImpuestosDR', 'pago20:TrasladosDR', 'pago20:TrasladoDR')
79 12
        );
80 12
        $retenciones = $this->processImpuestosRetenciones(
81 12
            $equivalenciaDr,
82 12
            $nodeDoctoRelacionado->searchNodes('pago20:ImpuestosDR', 'pago20:RetencionesDR', 'pago20:RetencionDR')
83 12
        );
84
        $impuestos = new Impuestos(...$traslados, ...$retenciones);
85 13
86
        return new DoctoRelacionado($impPagado, $impuestos);
87
    }
88
89 13
    /** @return list<Impuesto> */
0 ignored issues
show
Bug introduced by
The type CfdiUtils\SumasPagos20\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
90
    private function processImpuestosTraslados(Decimal $equivalenciaDr, Nodes $nodeImpuestos): array
91 13
    {
92 13
        $impuestos = [];
93 3
        foreach ($nodeImpuestos as $nodeImpuesto) {
94 3
            $impuesto = new Impuesto(
95 3
                'Traslado',
96 3
                $nodeImpuesto['ImpuestoDR'],
97 3
                $nodeImpuesto['TipoFactorDR'],
98 3
                $nodeImpuesto['TasaOCuotaDR'],
99 3
                new Decimal($nodeImpuesto['BaseDR']),
100 3
                new Decimal($nodeImpuesto['ImporteDR'])
101 3
            );
102 3
            $impuesto = $impuesto->divide($equivalenciaDr);
103
            $impuestos[] = $impuesto;
104 13
        }
105
        return $impuestos;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $impuestos returns the type CfdiUtils\SumasPagos20\Impuesto[]|array which is incompatible with the documented return type CfdiUtils\SumasPagos20\list.
Loading history...
106
    }
107
108 13
    /** @return list<Impuesto> */
109
    private function processImpuestosRetenciones(Decimal $equivalenciaDr, Nodes $nodeImpuestos): array
110 13
    {
111 13
        $impuestos = [];
112 13
        foreach ($nodeImpuestos as $nodeImpuesto) {
113 13
            $impuesto = new Impuesto(
114 13
                'Retencion',
115 13
                $nodeImpuesto['ImpuestoDR'],
116
                '',
117 13
                '',
118
                new Decimal('0'),
119 13
                new Decimal($nodeImpuesto['ImporteDR'])
120 13
            );
121 13
            $impuesto = $impuesto->divide($equivalenciaDr);
122 13
            $impuestos[] = $impuesto;
123 13
        }
124 13
        return $impuestos;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $impuestos returns the type CfdiUtils\SumasPagos20\Impuesto[]|array which is incompatible with the documented return type CfdiUtils\SumasPagos20\list.
Loading history...
125 13
    }
126
127 13
    /** @param Pago[] $pagos */
128 13
    private function buildTotales(array $pagos): Totales
129 13
    {
130 13
        $total = new Decimal('0');
131 13
        $impuestos = new Impuestos();
132 13
        foreach ($pagos as $pago) {
133 13
            $tipoCambioP = $pago->getTipoCambioP();
134 13
            $impuestos = $impuestos->aggregate($pago->getImpuestos()->multiply($tipoCambioP));
135 13
            $total = $total->sum($pago->getMonto()->multiply($tipoCambioP));
136 13
        }
137 13
        $impuestos = $impuestos->round(2); // MXN
138 13
139 13
        $retencionIva = $impuestos->find('Retencion', '002');
140
        $retencionIsr = $impuestos->find('Retencion', '001');
141
        $retencionIeps = $impuestos->find('Retencion', '003');
142
        $trasladoIva16 = $impuestos->find('Traslado', '002', 'Tasa', '0.160000');
143
        $trasladoIva08 = $impuestos->find('Traslado', '002', 'Tasa', '0.080000');
144
        $trasladoIva00 = $impuestos->find('Traslado', '002', 'Tasa', '0.000000');
145
        $trasladoIvaEx = $impuestos->find('Traslado', '002', 'Exento');
146
147
        return new Totales(
148
            $retencionIva ? $retencionIva->getImporte() : null,
149
            $retencionIsr ? $retencionIsr->getImporte() : null,
150
            $retencionIeps ? $retencionIeps->getImporte() : null,
151
            $trasladoIva16 ? $trasladoIva16->getBase() : null,
152
            $trasladoIva16 ? $trasladoIva16->getImporte() : null,
153
            $trasladoIva08 ? $trasladoIva08->getBase() : null,
154
            $trasladoIva08 ? $trasladoIva08->getImporte() : null,
155
            $trasladoIva00 ? $trasladoIva00->getBase() : null,
156
            $trasladoIva00 ? $trasladoIva00->getImporte() : null,
157
            $trasladoIvaEx ? $trasladoIvaEx->getBase() : null,
158
            $total->round(2) // MXN
159
        );
160
    }
161
}
162