diff --git a/src/Faker/Provider/fr_FR/Company.php b/src/Faker/Provider/fr_FR/Company.php index 81108873..0c9ca181 100644 --- a/src/Faker/Provider/fr_FR/Company.php +++ b/src/Faker/Provider/fr_FR/Company.php @@ -51,11 +51,6 @@ class Company extends \Faker\Provider\Company */ protected static $companySuffix = array('SA', 'S.A.', 'SARL', 'S.A.R.L.', 'S.A.S.', 'et Fils'); - /** - * @var string Siren format. - */ - protected static $sirenFormat = "### ### ###"; - /** * Returns a random catch phrase noun. * @@ -106,34 +101,95 @@ class Company extends \Faker\Provider\Company } /** - * Generates a siret number (14 digits). - * It is in fact the result of the concatenation of a siren number (9 digits), - * a sequential number (4 digits) and a control number (1 digit) concatenation. - * If $maxSequentialDigits is invalid, it is set to 2. - * + * Generates a siret number (14 digits) that passes the Luhn check. + * Use $maxSequentialDigits to make sure the digits at position 2 to 5 are not zeros. + * @see http://en.wikipedia.org/wiki/Luhn_algorithm * @param int $maxSequentialDigits The maximum number of digits for the sequential number (> 0 && <= 4). - * * @return string */ public static function siret($maxSequentialDigits = 2) { + if ($maxSequentialDigits > 4 || $maxSequentialDigits <= 0) { $maxSequentialDigits = 2; } - - $sequentialNumber = str_pad(static::randomNumber($maxSequentialDigits), 4, '0', STR_PAD_LEFT); - - return static::numerify(static::siren() . ' ' . $sequentialNumber . '#'); + + $controlDigit = mt_rand(0, 9); + $siret = $sum = $controlDigit; + + $position = 2; + for ($i = 0; $i < $maxSequentialDigits; $i++) { + + $sequentialDigit = mt_rand(0, 9); + $isEven = $position++ % 2 === 0; + + $tmp = $isEven ? $sequentialDigit * 2 : $sequentialDigit; + if ($tmp >= 10) $tmp -= 9; + $sum += $tmp; + + $siret = $sequentialDigit . $siret; + + } + + $siret = str_pad($siret, 5, '0', STR_PAD_LEFT); + + $position = 6; + for ($i = 0; $i < 7; $i++) { + + $digit = mt_rand(0, 9); + $isEven = $position++ % 2 === 0; + + $tmp = $isEven ? $digit * 2 : $digit; + if ($tmp >= 10) $tmp -= 9; + $sum += $tmp; + + $siret = $digit . $siret; + + } + + $mod = $sum % 10; + if ($mod === 0) { + $siret = '00' . $siret; + } else { + // Use the odd position to avoid multiplying by two + $siret = '0' . (10 - $mod) . $siret; + } + + return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{5})/", "$1 $2 $3 $4", $siret); + } /** - * Generates a siren number (9 digits). - * + * Generates a siren number (9 digits) that passes the Luhn check. + * @see http://en.wikipedia.org/wiki/Luhn_algorithm * @return string */ public static function siren() { - return static::numerify(static::$sirenFormat); + $siren = ''; + $sum = 0; + for ($i = 9; $i > 1; $i--) { + + $digit = mt_rand(0, 9); + $isEven = $i % 2 === 0; + + $tmp = $isEven ? $digit * 2 : $digit; + if ($tmp >= 10) $tmp -= 9; + $sum += $tmp; + + $siren = $digit . $siren; + + } + + $mod = $sum % 10; + if ($mod === 0) { + $siren = '0' . $siren; + } else { + $siren = (10 - $mod) . $siren; + } + + return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{3})/", "$1 $2 $3", $siren); + } /** diff --git a/test/Faker/PHPUnit/Framework/Constraint/IsValidSiren.php b/test/Faker/PHPUnit/Framework/Constraint/IsValidSiren.php new file mode 100644 index 00000000..b41930ac --- /dev/null +++ b/test/Faker/PHPUnit/Framework/Constraint/IsValidSiren.php @@ -0,0 +1,16 @@ +getLength()) + return false; + + $sum = 0; + // IMPORTANT : from right to left + $position = 1; + for ($i = strlen($code) - 1; $i >= 0; $i--) { + $isEven = (($position++ % 2) === 0); + $tmp = $isEven ? $code[$i] * 2 : $code[$i]; + if ($tmp >= 10) $tmp -= 9; + $sum += $tmp; + } + return ($sum % 10 === 0); + + } + + public function toString() { + return sprintf('is a valid %s number', $this->getName()); + } + + abstract protected function getLength(); + + abstract protected function getName(); + +} \ No newline at end of file diff --git a/test/Faker/PHPUnit/Framework/Constraint/IsValidSiret.php b/test/Faker/PHPUnit/Framework/Constraint/IsValidSiret.php new file mode 100644 index 00000000..54da7b74 --- /dev/null +++ b/test/Faker/PHPUnit/Framework/Constraint/IsValidSiret.php @@ -0,0 +1,16 @@ +assertThat($siret, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} 00[\d]{3}/", $siret); } public function testParagraphWithInvalidNbDigitsReturnsAWellFormattedSiret() { $siret = Company::siret(6); - + + $this->assertThat($siret, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} 00[\d]{3}/", $siret); } @@ -26,12 +43,24 @@ class CompanyTest extends \PHPUnit_Framework_TestCase $siret2 = Company::siret(2); $siret3 = Company::siret(3); $siret4 = Company::siret(4); - + + $this->assertThat($siret1, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} 000[\d]{2}/", $siret1); + $this->assertThat($siret2, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} 00[\d]{3}/", $siret2); + $this->assertThat($siret3, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} 0[\d]{4}/", $siret3); + $this->assertThat($siret4, self :: isValidSiret()); $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3} [\d]{5}/", $siret4); } + + public function testSirenReturnsAValidAndWellFormattedSiren() + { + $siret = Company::siren(); + + $this->assertThat($siret, self :: isValidSiren()); + $this->assertRegExp("/[\d]{3} [\d]{3} [\d]{3}/", $siret); + } public function testCatchPhraseValidationReturnsFalse() {