diff --git a/readme.md b/readme.md index d2cd41ff51..a1daedf640 100644 --- a/readme.md +++ b/readme.md @@ -931,6 +931,27 @@ echo $faker->dni; // '77446565E' echo $faker->vat; // "A35864370" ``` +### `Faker\Provider\fi_FI\Payment` + +```php +bankAccountNumber; // "FI8350799879879616" +``` + +### `Faker\Provider\fi_FI\Person` + +```php +personalIdentityNumber() // '170974-007J' + +//Since the numbers are different for male and female persons, optionally you can specify gender. +echo $faker->personalIdentityNumber(\DateTime::createFromFormat('Y-m-d', '2015-12-14'), 'female') // '141215A520B' +``` + ### `Faker\Provider\fr_BE\Payment` ```php diff --git a/src/Faker/Provider/fi_FI/Person.php b/src/Faker/Provider/fi_FI/Person.php index a48621d5e1..90dabd80d7 100644 --- a/src/Faker/Provider/fi_FI/Person.php +++ b/src/Faker/Provider/fi_FI/Person.php @@ -85,4 +85,61 @@ class Person extends \Faker\Provider\Person protected static $titleMale = array('Hra.', 'Tri.'); protected static $titleFemale = array('Rva.', 'Nti.', 'Tri.'); + + /** + * National Personal Identity Number (Henkilötunnus) + * @link http://www.finlex.fi/fi/laki/ajantasa/2010/20100128 + * @param \DateTime $birthdate + * @param string $gender Person::GENDER_MALE || Person::GENDER_FEMALE + * @return string on format DDMMYYCZZZQ, where DDMMYY is the date of birth, C the century sign, ZZZ the individual number and Q the control character (checksum) + */ + public function personalIdentityNumber(\DateTime $birthdate = null, $gender = null) + { + $checksumCharacters = '0123456789ABCDEFHJKLMNPRSTUVWXY'; + + if (!$birthdate) { + $birthdate = \Faker\Provider\DateTime::dateTimeThisCentury(); + } + $datePart = $birthdate->format('dmy'); + + switch ((int)($birthdate->format('Y')/100)) { + case 18: + $centurySign = '+'; + break; + case 19: + $centurySign = '-'; + break; + case 20: + $centurySign = 'A'; + break; + default: + throw new \InvalidArgumentException('Year must be between 1800 and 2099 inclusive.'); + } + + $randomDigits = self::numberBetween(0, 89); + if ($gender && $gender == static::GENDER_MALE) { + if ($randomDigits === 0) { + $randomDigits .= static::randomElement(array(3,5,7,9)); + } else { + $randomDigits .= static::randomElement(array(1,3,5,7,9)); + } + } elseif ($gender && $gender == static::GENDER_FEMALE) { + if ($randomDigits === 0) { + $randomDigits .= static::randomElement(array(2,4,6,8)); + } else { + $randomDigits .= static::randomElement(array(0,2,4,6,8)); + } + } else { + if ($randomDigits === 0) { + $randomDigits .= self::numberBetween(2, 9); + } else { + $randomDigits .= (string)static::numerify('#'); + } + } + $randomDigits = str_pad($randomDigits, 3, '0', STR_PAD_LEFT); + + $checksum = $checksumCharacters[(int)($datePart . $randomDigits) % strlen($checksumCharacters)]; + + return $datePart . $centurySign . $randomDigits . $checksum; + } } diff --git a/test/Faker/Provider/fi_FI/PersonTest.php b/test/Faker/Provider/fi_FI/PersonTest.php new file mode 100644 index 0000000000..6c77097e73 --- /dev/null +++ b/test/Faker/Provider/fi_FI/PersonTest.php @@ -0,0 +1,74 @@ +addProvider(new DateTime($faker)); + $faker->addProvider(new Person($faker)); + $this->faker = $faker; + } + + public function provideSeedAndExpectedReturn() + { + return array( + array(1, '1800-01-01', '010100+5207'), + array(2, '1930-08-08', '080830-508R'), + array(3, '1999-12-31', '311299-409D'), + array(4, '2000-01-01', '010100A039P'), + array(5, '2015-06-17', '170615A690X') + ); + } + + /** + * @dataProvider provideSeedAndExpectedReturn + */ + public function testPersonalIdentityNumberUsesBirthDateIfProvided($seed, $birthdate, $expected) + { + $faker = $this->faker; + $faker->seed($seed); + $pin = $faker->personalIdentityNumber(\DateTime::createFromFormat('Y-m-d', $birthdate)); + $this->assertEquals($expected, $pin); + } + + public function testPersonalIdentityNumberGeneratesCompliantNumbers() + { + for ($i = 0; $i < 10; $i++) { + $birthdate = $this->faker->dateTimeBetween('1800-01-01 00:00:00', '1899-12-31 23:59:59'); + $pin = $this->faker->personalIdentityNumber($birthdate); + $this->assertRegExp('/^[0-9]{6}\+[0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/', $pin); + } + for ($i = 0; $i < 10; $i++) { + $birthdate = $this->faker->dateTimeBetween('1900-01-01 00:00:00', '1999-12-31 23:59:59'); + $pin = $this->faker->personalIdentityNumber($birthdate); + $this->assertRegExp('/^[0-9]{6}-[0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/', $pin); + } + for ($i = 0; $i < 10; $i++) { + $birthdate = $this->faker->dateTimeBetween('2000-01-01 00:00:00', '2099-12-31 23:59:59'); + $pin = $this->faker->personalIdentityNumber($birthdate); + $this->assertRegExp('/^[0-9]{6}A[0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/', $pin); + } + } + + public function testPersonalIdentityNumberGeneratesOddValuesForMales() + { + $pin = $this->faker->personalIdentityNumber(null, 'male'); + $this->assertEquals(1, $pin{9} % 2); + } + + public function testPersonalIdentityNumberGeneratesEvenValuesForFemales() + { + $pin = $this->faker->personalIdentityNumber(null, 'female'); + $this->assertEquals(0, $pin{9} % 2); + } +}