Skip to content
This repository has been archived by the owner on Dec 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #988 from the-noob/ro_RO-add-CNP
Browse files Browse the repository at this point in the history
adding back CNP
  • Loading branch information
fzaninotto authored Nov 29, 2016
2 parents dfdfbbd + aec4bb2 commit 73bb74d
Show file tree
Hide file tree
Showing 4 changed files with 415 additions and 1 deletion.
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,18 @@ echo $faker->prefixFemale; // "d-na."
echo $faker->firstNameMale; // "Adrian"
// Generates a random female fist name
echo $faker->firstNameFemale; // "Miruna"


// Generates a random Personal Numerical Code (CNP)
echo $faker->cnp; // "2800523081231"
// Valid option values:
// $gender: null (random), male, female
// $dateOfBirth (1800+): null (random), Y-m-d, Y-m (random day), Y (random month and day)
// i.e. '1981-06-16', '2015-03', '1900'
// $county: 2 letter ISO 3166-2:RO county codes and B1, B2, B3, B4, B5, B6 for Bucharest's 6 sectors
// $isResident true/false flag if the person resides in Romania
echo $faker->cnp($gender = null, $dateOfBirth = null, $county = null, $isResident = true);

```

### `Faker\Provider\ro_RO\PhoneNumber`
Expand Down
148 changes: 148 additions & 0 deletions src/Faker/Provider/ro_RO/Person.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,152 @@ class Person extends \Faker\Provider\Person

protected static $titleMale = array('dl.', 'ing.', 'dr.');
protected static $titleFemale = array('d-na.', 'd-șoara', 'ing.', 'dr.');

protected static $cnpCountyCodes = array(
'AB' => '01', 'AR' => '02', 'AG' => '03', 'B' => '40', 'BC' => '04', 'BH' => '05',
'BN' => '06', 'BT' => '07', 'BV' => '08', 'BR' => '09', 'BZ' => '10', 'CS' => '11',
'CL' => '51', 'CJ' => '12', 'CT' => '13', 'CV' => '14', 'DB' => '15', 'DJ' => '16',
'GL' => '17', 'GR' => '52', 'GJ' => '18', 'HR' => '19', 'HD' => '20', 'IL' => '21',
'IS' => '22', 'IF' => '23', 'MM' => '24', 'MH' => '25', 'MS' => '26', 'NT' => '27',
'OT' => '28', 'PH' => '29', 'SM' => '30', 'SJ' => '31', 'SB' => '32', 'SV' => '33',
'TR' => '34', 'TM' => '35', 'TL' => '36', 'VS' => '37', 'VL' => '38', 'VN' => '39',

'B1' => '41', 'B2' => '42', 'B3' => '43', 'B4' => '44', 'B5' => '45', 'B6' => '46'
);

/**
* Personal Numerical Code (CNP)
*
* @link http://ro.wikipedia.org/wiki/Cod_numeric_personal
* @example 1111111111118
*
* @param null|string $gender Person::GENDER_MALE or Person::GENDER_FEMALE
* @param null|string $dateOfBirth (1800-2099) 'Y-m-d', 'Y-m', 'Y' I.E. '1981-06-16', '2085-03', '1900'
* @param null|string $county county code where the CNP was issued
* @param null|bool $isResident flag if the person resides in Romania
* @return string 13 digits CNP code
*/
public function cnp($gender = null, $dateOfBirth = null, $county = null, $isResident = true)
{
$genders = array(Person::GENDER_MALE, Person::GENDER_FEMALE);
if (empty($gender)) {
$gender = static::randomElement($genders);
} elseif (!in_array($gender, $genders)) {
throw new \InvalidArgumentException("Gender must be '{Person::GENDER_MALE}' or '{Person::GENDER_FEMALE}'");
}

$date = $this->getDateOfBirth($dateOfBirth);

if (is_null($county)) {
$countyCode = static::randomElement(array_values(static::$cnpCountyCodes));
} elseif (!array_key_exists($county, static::$cnpCountyCodes)) {
throw new \InvalidArgumentException("Invalid county code '{$county}' received");
} else {
$countyCode = static::$cnpCountyCodes[$county];
}

$cnp = (string)$this->getGenderDigit($date, $gender, $isResident)
. $date->format('ymd')
. $countyCode
. static::numerify('##%')
;

$checksum = $this->getChecksumDigit($cnp);

return $cnp.$checksum;
}

/**
* @param $dateOfBirth
* @return \DateTime
*/
protected function getDateOfBirth($dateOfBirth)
{
if (empty($dateOfBirth)) {
$dateOfBirthParts = array(static::numberBetween(1800, 2099));
} else {
$dateOfBirthParts = explode('-', $dateOfBirth);
}
$baseDate = \Faker\Provider\DateTime::dateTimeBetween("first day of {$dateOfBirthParts[0]}", "last day of {$dateOfBirthParts[0]}");

switch (count($dateOfBirthParts)) {
case 1:
$dateOfBirthParts[] = $baseDate->format('m');
//don't break, we need the day also
case 2:
$dateOfBirthParts[] = $baseDate->format('d');
//don't break, next line will
case 3:
break;
default:
throw new \InvalidArgumentException("Invalid date of birth - must be null or in the 'Y-m-d', 'Y-m', 'Y' format");
}

if ($dateOfBirthParts[0] < 1800 || $dateOfBirthParts[0] > 2099) {
throw new \InvalidArgumentException("Invalid date of birth - year must be between 1900 and 2099, '{$dateOfBirthParts[0]}' received");
}

$dateOfBirthFinal = implode('-', $dateOfBirthParts);
$date = \DateTime::createFromFormat('Y-m-d', $dateOfBirthFinal);
//a full (invalid) date might have been supplied, check if it converts
if ($date->format('Y-m-d') !== $dateOfBirthFinal) {
throw new \InvalidArgumentException("Invalid date of birth - '{$date->format('Y-m-d')}' generated based on '{$dateOfBirth}' received");
}

return $date;
}

/**
*
* https://ro.wikipedia.org/wiki/Cod_numeric_personal#S
*
* @param \DateTime $dateOfBirth
* @param bool $isResident
* @param string $gender
* @return int
*/
protected static function getGenderDigit(\DateTime $dateOfBirth, $gender, $isResident)
{
if (!$isResident) {
return 9;
}

if ($dateOfBirth->format('Y') < 1900) {
if ($gender == Person::GENDER_MALE) {
return 3;
}
return 4;
}

if ($dateOfBirth->format('Y') < 2000) {
if ($gender == Person::GENDER_MALE) {
return 1;
}
return 2;
}

if ($gender == Person::GENDER_MALE) {
return 5;
}
return 6;
}

/**
* Calculates a checksum for the Personal Numerical Code (CNP).
*
* @param string $value 12 digit CNP
* @return int checksum digit
*/
protected function getChecksumDigit($value)
{
$checkNumber = 279146358279;

$checksum = 0;
foreach (range(0, 11) as $digit) {
$checksum += (int)substr($value, $digit, 1) * (int)substr($checkNumber, $digit, 1);
}
$checksum = $checksum % 11;

return $checksum == 10 ? 1 : $checksum;
}
}
Loading

0 comments on commit 73bb74d

Please sign in to comment.