Skip to content

Commit 245a1c5

Browse files
Merge pull request #21 from brazanation/cns
CNS document implemented fix #20
2 parents 193ce86 + b9df36a commit 245a1c5

18 files changed

+202
-29
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ echo $state; // prints P011004243002
176176
echo $state->format(); // prints P-01100424.3/002
177177
```
178178

179+
### Cartão Nacional de Saúde (SUS)
180+
181+
National Health Card
182+
183+
```php
184+
use Brazanation\Documents\Cns;
185+
186+
$cns = new Cns('242912018460005')
187+
echo $state; // prints 242912018460005
188+
echo $state->format(); // prints 242 9120 1846 0005
189+
```
190+
179191
### License
180192

181193
MIT, hell yeah!

src/AbstractDocument.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Brazanation\Documents\Exception\InvalidDocument as InvalidDocumentException;
66

7-
abstract class AbstractDocument implements DocumentInterface
7+
abstract class AbstractDocument implements DigitCalculable, Formattable
88
{
99
/**
1010
* @var string

src/Cnh.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class Cnh extends AbstractDocument implements DocumentInterface
5+
final class Cnh extends AbstractDocument
66
{
77
const LENGTH = 11;
88

src/Cnpj.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class Cnpj extends AbstractDocument implements DocumentInterface
5+
final class Cnpj extends AbstractDocument
66
{
77
const LENGTH = 14;
88

src/Cns.php

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Brazanation\Documents;
4+
5+
use Brazanation\Documents\Cns\CnsCalculator;
6+
use Brazanation\Documents\Cns\TemporaryCalculator;
7+
8+
final class Cns extends AbstractDocument
9+
{
10+
const LENGTH = 15;
11+
12+
const LABEL = 'CNS';
13+
14+
const REGEX = '/^([\d]{3})([\d]{4})([\d]{4})([\d]{4})$/';
15+
16+
const FORMAT = '$1 $2 $3 $4';
17+
18+
const DIGIT_COUNT = 1;
19+
20+
/**
21+
* CNS constructor.
22+
*
23+
* @param string $number
24+
*/
25+
public function __construct($number)
26+
{
27+
$number = preg_replace('/\D/', '', $number);
28+
parent::__construct($number, self::LENGTH, self::DIGIT_COUNT, self::LABEL);
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function format()
35+
{
36+
return preg_replace(self::REGEX, self::FORMAT, "{$this}");
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*
42+
* Based on given number, it will decide what kind of calculator will use.
43+
*
44+
* For numbers starting with 7, 8 or 9 will use TemporaryCalculator,
45+
* otherwise CnsCalculator.
46+
*/
47+
public function calculateDigit($baseNumber)
48+
{
49+
$calculator = new CnsCalculator();
50+
51+
if (in_array(substr($baseNumber, 0, 1), [7, 8, 9])) {
52+
$calculator = new TemporaryCalculator();
53+
}
54+
55+
$digit = $calculator->calculateDigit($baseNumber);
56+
57+
return "{$digit}";
58+
}
59+
}

src/Cns/CnsCalculator.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Brazanation\Documents\Cns;
4+
5+
use Brazanation\Documents\DigitCalculable;
6+
use Brazanation\Documents\DigitCalculator;
7+
8+
final class CnsCalculator implements DigitCalculable
9+
{
10+
/**
11+
* {@inheritdoc}
12+
*/
13+
public function calculateDigit($baseNumber)
14+
{
15+
$pis = substr($baseNumber, 0, 11);
16+
17+
$calculator = new DigitCalculator($pis);
18+
$calculator->useComplementaryInsteadOfModule();
19+
$calculator->replaceWhen('8', 10);
20+
$calculator->replaceWhen('0', 11);
21+
$calculator->withMultipliersInterval(5, 15);
22+
23+
$digit = $calculator->calculate();
24+
25+
return "{$digit}";
26+
}
27+
}

src/Cns/TemporaryCalculator.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Brazanation\Documents\Cns;
4+
5+
use Brazanation\Documents\DigitCalculable;
6+
use Brazanation\Documents\DigitCalculator;
7+
8+
class TemporaryCalculator implements DigitCalculable
9+
{
10+
/**
11+
* {@inheritdoc}
12+
*/
13+
public function calculateDigit($baseNumber)
14+
{
15+
$calculator = new DigitCalculator($baseNumber);
16+
$calculator->withMultipliersInterval(1, 15);
17+
18+
$digit = $calculator->calculate();
19+
20+
return "{$digit}";
21+
}
22+
}

src/Cpf.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class Cpf extends AbstractDocument implements DocumentInterface
5+
final class Cpf extends AbstractDocument
66
{
77
const LENGTH = 11;
88

src/DocumentInterface.php renamed to src/DigitCalculable.php

+1-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
interface DocumentInterface
5+
interface DigitCalculable
66
{
77
/**
88
* Calculate check digit from base number.
@@ -12,11 +12,4 @@ interface DocumentInterface
1212
* @return string Returns the checker digit.
1313
*/
1414
public function calculateDigit($baseNumber);
15-
16-
/**
17-
* Formats current number.
18-
*
19-
* @return string Returns formatted number.
20-
*/
21-
public function format();
2215
}

src/DigitCalculator.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,12 @@ private function calculateAdditionalDigit($digit)
260260
*
261261
* @param int $total A total to be calculated.
262262
*
263-
* @return float Returns a calculated total.
263+
* @return int Returns a calculated total.
264264
*/
265265
private function calculateSingleSum($total)
266266
{
267267
if ($this->singleSum) {
268-
return ($total / 10) + ($total % 10);
268+
return intval(($total / 10) + ($total % 10));
269269
}
270270

271271
return $total;

src/Formattable.php

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Brazanation\Documents;
4+
5+
interface Formattable
6+
{
7+
/**
8+
* Formats current number.
9+
*
10+
* @return string Returns formatted number.
11+
*/
12+
public function format();
13+
}

src/NFeAccessKey.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class NFeAccessKey extends AbstractDocument implements DocumentInterface
5+
final class NFeAccessKey extends AbstractDocument
66
{
77
const LABEL = 'NFeAccessKey';
88

src/PisPasep.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class PisPasep extends AbstractDocument implements DocumentInterface
5+
final class PisPasep extends AbstractDocument
66
{
77
const LENGTH = 11;
88

src/StateRegistration.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
* @method static StateRegistration SP($number)
6565
* @method static StateRegistration TO($number)
6666
*/
67-
final class StateRegistration extends AbstractDocument implements DocumentInterface
67+
final class StateRegistration extends AbstractDocument
6868
{
6969
/**
7070
* @var StateInterface

src/StateRegistration/StateInterface.php

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Brazanation\Documents\StateRegistration;
44

5-
interface StateInterface
5+
use Brazanation\Documents\DigitCalculable;
6+
7+
interface StateInterface extends DigitCalculable
68
{
79
/**
810
* @return string
@@ -29,13 +31,6 @@ public function getFormat();
2931
*/
3032
public function getNumberOfDigits();
3133

32-
/**
33-
* @param string $baseNumber
34-
*
35-
* @return string
36-
*/
37-
public function calculateDigit($baseNumber);
38-
3934
/**
4035
* Normalizes number removing non-digit chars.
4136
*

src/Voter.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Brazanation\Documents;
44

5-
final class Voter extends AbstractDocument implements DocumentInterface
5+
final class Voter extends AbstractDocument
66
{
77
const LENGTH = 12;
88

tests/CnsTest.php

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Brazanation\Documents\Tests;
4+
5+
use Brazanation\Documents\Cns;
6+
7+
class CnsTest extends DocumentTestCase
8+
{
9+
public function createDocument($number)
10+
{
11+
return new Cns($number);
12+
}
13+
14+
public function provideValidNumbers()
15+
{
16+
return [
17+
['242912018460005'],
18+
['202652786480004'],
19+
['130660713310009'],
20+
['161406744690005'],
21+
['131638083510018'],
22+
['153146911870018'],
23+
['126556169380018'],
24+
['112737911470018'],
25+
];
26+
}
27+
28+
public function provideValidNumbersAndExpectedFormat()
29+
{
30+
return [
31+
['242912018460005', '242 9120 1846 0005'],
32+
];
33+
}
34+
35+
public function provideEmptyData()
36+
{
37+
return [
38+
[Cns::LABEL, ''],
39+
[Cns::LABEL, null],
40+
[Cns::LABEL, 0],
41+
];
42+
}
43+
44+
public function provideInvalidNumber()
45+
{
46+
return [
47+
[Cns::LABEL, 1],
48+
[Cns::LABEL, '123123232323'],
49+
[Cns::LABEL, '861238979874'],
50+
];
51+
}
52+
}

tests/DocumentTestCase.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
namespace Brazanation\Documents\Tests;
44

5-
use Brazanation\Documents\DocumentInterface;
5+
use Brazanation\Documents\AbstractDocument;
66
use Brazanation\Documents\Exception\InvalidDocument;
77

88
abstract class DocumentTestCase extends \PHPUnit_Framework_TestCase
99
{
1010
/**
1111
* @param string $number
1212
*
13-
* @return DocumentInterface
13+
* @return AbstractDocument
1414
*/
1515
abstract public function createDocument($number);
1616

@@ -50,7 +50,7 @@ abstract public function provideInvalidNumber();
5050
final public function testShouldCreateInstance($number)
5151
{
5252
$document = $this->createDocument($number);
53-
$this->assertInstanceOf(DocumentInterface::class, $document);
53+
$this->assertInstanceOf(AbstractDocument::class, $document);
5454
$this->assertEquals(preg_replace('/[^\dXP]/i', '', $number), (string) $document);
5555
}
5656

0 commit comments

Comments
 (0)