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

adding back CNP #988

Merged
merged 1 commit into from
Nov 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,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