-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
288 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
src/CfdiUtils/Validate/Cfdi33/RecepcionPagos/Pagos/MontoBetweenIntervalSumOfDocuments.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<?php | ||
namespace CfdiUtils\Validate\Cfdi33\RecepcionPagos\Pagos; | ||
|
||
use CfdiUtils\Nodes\NodeInterface; | ||
use CfdiUtils\Validate\Cfdi33\RecepcionPagos\Helpers\CalculateDocumentAmountTrait; | ||
|
||
/** | ||
* PAGO09: En un pago, el monto del pago debe encontrarse entre límites mínimo y máximo de la suma | ||
* de los valores registrados en el importe pagado de los documentos relacionados (CRP206) | ||
*/ | ||
class MontoBetweenIntervalSumOfDocuments extends AbstractPagoValidator | ||
{ | ||
use CalculateDocumentAmountTrait; | ||
|
||
protected $code = 'PAGO09'; | ||
protected $title = 'En un pago, el monto del pago debe encontrarse entre límites mínimo y máximo de la suma' | ||
. ' de los valores registrados en el importe pagado de los documentos relacionados (CRP206)'; | ||
|
||
public function validatePago(NodeInterface $pago): bool | ||
{ | ||
$pagoAmount = floatval($pago['Monto']); | ||
$bounds = $this->calculateDocumentsAmountBounds($pago); | ||
$lower = $bounds['lower']; | ||
$upper = $bounds['upper']; | ||
if ($pagoAmount < $lower || $pagoAmount > $upper) { | ||
throw new ValidatePagoException( | ||
sprintf('Monto del pago: "%s", Suma mínima: "%s", Suma máxima: "%s"', $pagoAmount, $lower, $upper) | ||
); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public function calculateDocumentsAmountBounds(NodeInterface $pago): array | ||
{ | ||
$documents = $pago->searchNodes('pago10:DoctoRelacionado'); | ||
$values = []; | ||
foreach ($documents as $document) { | ||
$values[] = $this->calculateDocumentAmountBounds($document, $pago); | ||
} | ||
$bounds = [ | ||
'lower' => array_sum(array_column($values, 'lower')), | ||
'upper' => array_sum(array_column($values, 'upper')), | ||
]; | ||
return $bounds; | ||
} | ||
|
||
public function calculateDocumentAmountBounds(NodeInterface $doctoRelacionado, NodeInterface $pago): array | ||
{ | ||
$amount = $this->calculateDocumentAmount($doctoRelacionado, $pago); | ||
$impPagado = $doctoRelacionado['ImpPagado'] ?? $amount; | ||
$tipoCambioDr = $doctoRelacionado['TipoCambioDR']; | ||
$exchangeRate = 1; | ||
if ('' !== $tipoCambioDr && $pago['MonedaP'] !== $pago['MonedaDR']) { | ||
$exchangeRate = floatval($tipoCambioDr); | ||
} | ||
$numDecimalsAmount = $this->getNumDecimals($impPagado); | ||
$numDecimalsExchangeRate = $this->getNumDecimals($tipoCambioDr); | ||
|
||
if (0 === $numDecimalsExchangeRate) { | ||
return [ | ||
'lower' => $amount / $exchangeRate, | ||
'upper' => $amount / $exchangeRate, | ||
]; | ||
} | ||
|
||
$almostTwo = 2 - (10 ** - 10); | ||
|
||
$lowerAmount = $amount - 10 ** - $numDecimalsAmount / 2; | ||
$lowerExchangeRate = $exchangeRate + (10 ** (- $numDecimalsExchangeRate) / $almostTwo); | ||
|
||
$upperAmount = $amount + 10 ** - $numDecimalsAmount / $almostTwo; | ||
$upperExchangeRate = $exchangeRate - (10 ** (- $numDecimalsExchangeRate) / 2); | ||
|
||
return [ | ||
'lower' => $lowerAmount / $lowerExchangeRate, | ||
'upper' => $upperAmount / $upperExchangeRate, | ||
]; | ||
} | ||
|
||
public function getNumDecimals(string $numeric): int | ||
{ | ||
if (! is_numeric($numeric)) { | ||
return 0; | ||
} | ||
$pointPosition = strpos($numeric, '.'); | ||
if (false === $pointPosition) { | ||
return 0; | ||
} | ||
return strlen($numeric) - 1 - $pointPosition; | ||
} | ||
} |
47 changes: 0 additions & 47 deletions
47
src/CfdiUtils/Validate/Cfdi33/RecepcionPagos/Pagos/MontoGreaterOrEqualThanSumOfDocuments.php
This file was deleted.
Oops, something went wrong.
53 changes: 53 additions & 0 deletions
53
...fdiUtilsTests/Validate/Cfdi33/RecepcionPagos/Helpers/CalculateDocumentAmountTraitTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
namespace CfdiUtilsTests\Validate\Cfdi33\RecepcionPagos\Helpers; | ||
|
||
use CfdiUtils\Elements\Pagos10\DoctoRelacionado; | ||
use CfdiUtils\Elements\Pagos10\Pago; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class CalculateDocumentAmountTraitTest extends TestCase | ||
{ | ||
public function testCalculateDocumentAmountWhenIsSet() | ||
{ | ||
$validator = new CalculateDocumentAmountUse(); | ||
$amount = $validator->calculateDocumentAmount(new DoctoRelacionado([ | ||
'ImpPagado' => '123.45', | ||
]), new Pago()); | ||
|
||
$this->assertEquals(123.45, $amount, '', 0.001); | ||
} | ||
|
||
public function testCalculateDocumentAmountWhenIsUndefined() | ||
{ | ||
$pago = new Pago(['Monto' => '123.45']); | ||
$docto = $pago->addDoctoRelacionado(); | ||
|
||
$validator = new CalculateDocumentAmountUse(); | ||
$amount = $validator->calculateDocumentAmount($docto, $pago); | ||
|
||
$this->assertEquals(123.45, $amount, '', 0.001); | ||
} | ||
|
||
public function testCalculateDocumentAmountWhenIsUndefinedWithExchangeRate() | ||
{ | ||
$pago = new Pago(['Monto' => '123.45']); | ||
$docto = $pago->addDoctoRelacionado(['TipoCambioDR' => 'EUR']); | ||
|
||
$validator = new CalculateDocumentAmountUse(); | ||
$amount = $validator->calculateDocumentAmount($docto, $pago); | ||
|
||
$this->assertEquals(0, $amount, '', 0.001); | ||
} | ||
|
||
public function testCalculateDocumentAmountWhenIsUndefinedWithMoreDocuments() | ||
{ | ||
$pago = new Pago(['Monto' => '123.45']); | ||
$pago->addDoctoRelacionado(); // first | ||
$docto = $pago->addDoctoRelacionado(); // second | ||
|
||
$validator = new CalculateDocumentAmountUse(); | ||
$amount = $validator->calculateDocumentAmount($docto, $pago); | ||
|
||
$this->assertEquals(0, $amount, '', 0.001); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
tests/CfdiUtilsTests/Validate/Cfdi33/RecepcionPagos/Helpers/CalculateDocumentAmountUse.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
namespace CfdiUtilsTests\Validate\Cfdi33\RecepcionPagos\Helpers; | ||
|
||
use CfdiUtils\Validate\Cfdi33\RecepcionPagos\Helpers\CalculateDocumentAmountTrait; | ||
|
||
class CalculateDocumentAmountUse | ||
{ | ||
use CalculateDocumentAmountTrait; | ||
} |
69 changes: 69 additions & 0 deletions
69
...tilsTests/Validate/Cfdi33/RecepcionPagos/Pagos/MontoBetweenIntervalSumOfDocumentsTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
namespace CfdiUtilsTests\Validate\Cfdi33\RecepcionPagos\Pagos; | ||
|
||
use CfdiUtils\Elements\Pagos10\Pago; | ||
use CfdiUtils\Validate\Cfdi33\RecepcionPagos\Pagos\MontoBetweenIntervalSumOfDocuments; | ||
use CfdiUtils\Validate\Cfdi33\RecepcionPagos\Pagos\ValidatePagoException; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class MontoBetweenIntervalSumOfDocumentsTest extends TestCase | ||
{ | ||
public function testValid() | ||
{ | ||
$pago = new Pago([ | ||
'MonedaP' => 'USD', | ||
'Monto' => '123.45', | ||
]); | ||
$pago->multiDoctoRelacionado(...[ | ||
['ImpPagado' => '50.00'], // 50.00 | ||
['MonedaDR' => 'EUR', 'TipoCambioDR' => '0.50', 'ImpPagado' => '25.00'], // 25.00 / 0.50 => 50 | ||
['MonedaDR' => 'MXN', 'TipoCambioDR' => '18.7894', 'ImpPagado' => '440.61'], // 440.61 / 18.7894 => 23.45 | ||
]); | ||
|
||
$validator = new MontoBetweenIntervalSumOfDocuments(); | ||
$this->assertTrue($validator->validatePago($pago)); | ||
} | ||
|
||
/** | ||
* This is testing lower bound (122.94) and upper bound (123.97) | ||
* @param string $monto | ||
* @testWith ["122.94"] | ||
* ["123.97"] | ||
*/ | ||
public function testInvalids(string $monto) | ||
{ | ||
$pago = new Pago([ | ||
'MonedaP' => 'USD', | ||
'Monto' => $monto, | ||
]); | ||
$pago->multiDoctoRelacionado(...[ | ||
['ImpPagado' => '20.00'], // 20.00 | ||
['MonedaDR' => 'USD', 'ImpPagado' => '30.00'], // 30.00 | ||
['MonedaDR' => 'EUR', 'TipoCambioDR' => '0.50', 'ImpPagado' => '25.00'], // 25.00 / 0.50 => 50 | ||
['MonedaDR' => 'MXN', 'TipoCambioDR' => '18.7894', 'ImpPagado' => '440.61'], // 440.61 / 18.7894 => 23.45 | ||
]); | ||
|
||
$validator = new MontoBetweenIntervalSumOfDocuments(); | ||
|
||
$this->expectException(ValidatePagoException::class); | ||
$validator->validatePago($pago); | ||
} | ||
|
||
public function testValidWithSeveralDecimals() | ||
{ | ||
// payment was made of 5,137.42 USD (ER: 18.7694) => 96,426.29 MXN | ||
// to pay a document on USD | ||
$pago = new Pago([ | ||
'MonedaP' => 'MXN', | ||
'Monto' => '96426.29', | ||
]); | ||
$pago->addDoctoRelacionado([ | ||
'MonedaDR' => 'USD', | ||
'TipoCambioDR' => number_format(1 / 18.7694, 4), | ||
'ImpPagado' => '5137.42', | ||
]); | ||
|
||
$validator = new MontoBetweenIntervalSumOfDocuments(); | ||
$this->assertTrue($validator->validatePago($pago)); | ||
} | ||
} |
Oops, something went wrong.