From 5a16833cdc3d30f440583c992b75d267633109fd Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 12:46:41 -0500 Subject: [PATCH 1/6] Improve test cases - Cases with A, 0, or [1-9], multibyte and invalid samples --- tests/Unit/CheckSumTest.php | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/Unit/CheckSumTest.php b/tests/Unit/CheckSumTest.php index 75c612f..e9b1308 100644 --- a/tests/Unit/CheckSumTest.php +++ b/tests/Unit/CheckSumTest.php @@ -9,20 +9,29 @@ final class CheckSumTest extends TestCase { - public function testCheckSum(): void + /** @return array */ + public function providerCheckSum(): array { - $expected = 'A'; - $rfc = 'COSC8001137NA'; + return [ + 'física 0' => ['CAMA911215CJ0', '0'], + 'física A' => ['COSC8001137NA', 'A'], + 'física [1-9]' => ['SORC591116FJ6', '6'], - $checksum = new CheckSum(); - $this->assertSame($expected, $checksum->calculate($rfc)); + 'moral A' => ['DIM8701081LA', 'A'], + 'moral 0' => ['A&A050908GT0', '0'], + 'moral [1-9]' => ['SAT970701NN3', '3'], + + 'multibyte' => ['AÑÑ801231JK0', '0'], + + 'empty rfc' => ['', '0'], + 'invalid rfc' => ['$', '0'], + 'invalid chars' => ['AAA010101$$$', '7'], // $ is managed as 0 + ]; } - public function testCheckSumWithMultiByte(): void + /** @dataProvider providerCheckSum */ + public function testCheckSum(string $rfc, string $expected): void { - $expected = '0'; - $rfc = 'AÑÑ801231JK0'; - $checksum = new CheckSum(); $this->assertSame($expected, $checksum->calculate($rfc)); } From 9665629a7d9029e5ad97cd2b69001357ea144bcd Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 22:26:38 -0500 Subject: [PATCH 2/6] Symplify checksum algorithm --- src/CheckSum.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/CheckSum.php b/src/CheckSum.php index 5bc4207..de3d1d8 100644 --- a/src/CheckSum.php +++ b/src/CheckSum.php @@ -8,23 +8,25 @@ final class CheckSum { private const DICTIONARY = [0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23, '&' => 24, 'O' => 25, 'P' => 26, 'Q' => 27, 'R' => 28, 'S' => 29, 'T' => 30, 'U' => 31, 'V' => 32, 'W' => 33, 'X' => 34, 'Y' => 35, 'Z' => 36, ' ' => 37, '#' => 38]; + private const DIGIT_OVERRIDE = [10 => 'A', 11 => '0']; + public function calculate(string $rfc): string { - // 'Ñ' translated to '#' because 'Ñ' is multibyte 0xC3 0xB1 + // 'Ñ' cambia a '#' porque 'Ñ' es multi-byte 0xC3 0xB1 $chars = str_split(str_replace('Ñ', '#', $rfc), 1); - array_pop($chars); // remove predefined checksum $length = count($chars); - $sum = (11 === $length) ? 481 : 0; // 481 para morales, 0 para físicas - $j = $length + 1; + array_pop($chars); // remover el dígito predefinido + + // Valor inicial de la suma: 481 para morales, 0 para físicas + $sum = (12 === $length) ? 481 : 0; + // suma de valores: Σ(Vi * (Pi + 1)) foreach ($chars as $i => $char) { - $sum += self::DICTIONARY[$char] * ($j - $i); + $sum += (self::DICTIONARY[$char] ?? 0) * ($length - $i); } - $digit = strval(11 - $sum % 11); - if ('11' === $digit) { - $digit = '0'; - } elseif ('10' === $digit) { - $digit = 'A'; - } - return $digit; + + // posibles valores: [1, 2, ..., 10, 11] porque $sum % 11 => int<0, 10> + $digit = 11 - $sum % 11; + // se retorna 10 => 0, 11 => A o el valor obtenido + return self::DIGIT_OVERRIDE[$digit] ?? strval($digit); } } From ba35822dd0e0ecf0ea172aacf20b411430cb38cc Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 22:31:16 -0500 Subject: [PATCH 3/6] Document checksum Rfc methods and class --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 8b68651..bc823be 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,21 @@ Provee métodos para crear una cadena de caracteres que es una clave RFC: - `RfcFaker::mexicanRfcMoral()` para persona moral (12 posiciones). - `RfcFaker::mexicanRfc()` indistintamente una persona moral o física. +## Dígito verificador + +Se puede obtener el dígito verificador calculado con el método `Rfc::calculateCheckSum()`, +así como conocer si el dígito verificador coincide con el método `Rfc::doesCheckSumMatch()`. + +La además provee la clase `CheckSum` para realizar el cálculo del dígito verificador de un RFC. +Cabe mencionar que, si bien debería ser siempre coincidente, hay algunos casos donde esto +no se respeta (SAT, ¿todo bien?), por ejemplo, el caso de *Restaurantes TOKS* ha tenido +los RFC `RT0840921REA` (dígito `A`) y también `RT0840921RE4`. + +Puede ver el procedimiento del dígito verificador en alguno de estos enlaces: + +- +- + ## Desarrollo Para entender esta librería en el ámbito de desarrollo (para extender o modificar), lee los siguientes documentos: From 36347091179d91ade8de396a40bf89d83f54b03f Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 22:34:28 -0500 Subject: [PATCH 4/6] Update development dependencies --- .phive/phars.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.phive/phars.xml b/.phive/phars.xml index 7aa1b73..2b77702 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,9 +1,9 @@ - + - - + + From 0b1f3844a7aefd418f2ce1e1856ed8c64418d421 Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 22:36:03 -0500 Subject: [PATCH 5/6] CI: build job phpcs run using folders in config file --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index acd0b0a..a7cc2c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: env: fail-fast: true - name: Code style (phpcs) - run: phpcs -q --report=checkstyle src/ tests/ | cs2pr + run: phpcs -q --report=checkstyle | cs2pr php-cs-fixer: name: Code style (php-cs-fixer) From 8519d6b0f111dcda161e7d5001ea254f347d8ed5 Mon Sep 17 00:00:00 2001 From: Carlos C Soto Date: Thu, 28 Apr 2022 22:36:59 -0500 Subject: [PATCH 6/6] Prepare version 1.1.2 --- docs/CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 080aa5d..27491f8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,6 +8,16 @@ Utilizamos [Versionado Semántico 2.0.0](SEMVER.md). Los cambios no liberados no requieren de una nueva versión y son incluidos en la rama principal. +## Versión 1.1.2 + +Se actualiza la clase `CheckSum` y se mejoran las pruebas unitarias sobre la misma. +Gracias a `@fitorec` por sus sugerencias en el [PR #14](https://github.com/phpcfdi/rfc/pull/14). + +Se actualizan las versiones de las herramientas de desarrollo. + +Al ejecutar el trabajo de integración continua en el trabajo `phpcs` se usan los directorios según +el archivo de configuración. + ## Versión 1.1.1 Se actualiza la expresión regular para lectura de RFC con las recomendaciones de simplificación: