Completed
Push — master ( a59117...ff30f9 )
by Luis Andrés
01:03
created

EcuadorIdentification::validateAllIdentificatons()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2888
c 0
b 0
f 0
cc 5
nc 5
nop 1
1
<?php
2
3
namespace Luilliarcec\LaravelEcuadorIdentification\Support;
4
5
use Luilliarcec\LaravelEcuadorIdentification\Exceptions\EcuadorIdentificationException;
6
7
/**
8
 * Class to validate Ecuadorian identity card, Natural ruc, Private ruc and Public ruc
9
 *
10
 * @link https://www.sri.gob.ec/web/guest/RUC#%C2%BFc%C3%B3mo-se
11
 * @link http://www.sri.gob.ec/DocumentosAlfrescoPortlet/descargar/1ee224e6-b84b-4a8f-8127-59f8cd99ae58/LOGARITMO_VALIDA_RUC.docx
12
 * @package Luilliarcec\LaravelEcuadorIdentification\Support
13
 */
14
class EcuadorIdentification
15
{
16
    /**
17
     * Natural person ruc
18
     */
19
    const NaturalPerson = 'NaturalPerson';
20
21
    /**
22
     * Private company ruc
23
     */
24
    const PrivateCompany = 'PrivateCompany';
25
26
    /**
27
     * Public company ruc
28
     */
29
    const PublicCompany = 'PublicCompany';
30
31
    /**
32
     * Error encapsulator variable
33
     *
34
     * @var string
35
     */
36
    private $error;
37
38
    /**
39
     * Number of provinces of Ecuador
40
     *
41
     * @var \Illuminate\Config\Repository
42
     */
43
    private $provinces;
44
45
    /**
46
     * Length of the different types of identification
47
     *
48
     * @var array
49
     */
50
    private $lenght;
51
52
    /**
53
     * Billing code for identification types
54
     *
55
     * @var array
56
     */
57
    private $billingCode;
58
59
    public function __construct()
60
    {
61
        $this->provinces = config('laravel-ecuador-identification.provinces');
62
63
        $this->lenght = [
64
            'ruc' => config('laravel-ecuador-identification.type-identifications.ruc.length'),
65
            'personal-identification' => config('laravel-ecuador-identification.type-identifications.personal-identification.length'),
66
        ];
67
68
        $this->billingCode = [
69
            'personal-identification' => config('laravel-ecuador-identification.type-identifications.personal-identification.billing-code'),
70
            'ruc' => config('laravel-ecuador-identification.type-identifications.ruc.billing-code'),
71
            'final-customer' => config('laravel-ecuador-identification.type-identifications.final-customer.billing-code'),
72
        ];
73
    }
74
75
    /**
76
     * Set Error
77
     *
78
     * @param string $error
79
     */
80
    protected function setError(string $error): void
81
    {
82
        $this->error = $error;
83
    }
84
85
    /**
86
     * Get Error
87
     *
88
     * @return string
89
     */
90
    public function getError(): string
91
    {
92
        return $this->error;
93
    }
94
95
    /**
96
     * Validates the Ecuadorian Identification Card
97
     *
98
     * @param string $number Number of Identification Card
99
     * @return string|null
100
     */
101
    public function validatePersonalIdentification($number)
102
    {
103
        $this->setError('');
104
105
        try {
106
            $this->initValidation($number, $this->lenght['personal-identification']);
107
            $this->provinceCodeValidation(substr($number, 0, 2));
108
            $this->thirdDigitValidation($number[2], self::NaturalPerson);
109
            $this->moduleTen($number);
110
        } catch (EcuadorIdentificationException $e) {
111
            $this->setError($e->getMessage());
112
            return null;
113
        }
114
115
        return $this->billingCode['personal-identification'];
116
    }
117
118
    /**
119
     * Validates the Ecuadorian RUC of Natural Person
120
     *
121
     * @param string $number Number of RUC Natural Person
122
     * @return string|null
123
     */
124 View Code Duplication
    public function validateNaturalPersonRuc($number)
125
    {
126
        $this->setError('');
127
128
        try {
129
            $this->initValidation($number, $this->lenght['ruc']);
130
            $this->provinceCodeValidation(substr($number, 0, 2));
131
            $this->thirdDigitValidation($number[2], self::NaturalPerson);
132
            $this->theLastDigitsValidation(substr($number, 10, 3), self::NaturalPerson);
133
            $this->moduleTen($number);
134
        } catch (EcuadorIdentificationException $e) {
135
            $this->setError($e->getMessage());
136
            return null;
137
        }
138
139
        return $this->billingCode['ruc'];
140
    }
141
142
    /**
143
     * Validates the Ecuadorian RUC of Private Companies
144
     *
145
     * @param string $number Number of RUC Private Companies
146
     * @return string|null
147
     */
148 View Code Duplication
    public function validatePrivateCompanyRuc($number)
149
    {
150
        $this->setError('');
151
152
        try {
153
            $this->initValidation($number, $this->lenght['ruc']);
154
            $this->provinceCodeValidation(substr($number, 0, 2));
155
            $this->thirdDigitValidation($number[2], self::PrivateCompany);
156
            $this->theLastDigitsValidation(substr($number, 10, 3), self::PrivateCompany);
157
            $this->moduleEleven($number, self::PrivateCompany);
158
        } catch (EcuadorIdentificationException $e) {
159
            $this->setError($e->getMessage());
160
            return null;
161
        }
162
163
        return $this->billingCode['ruc'];
164
    }
165
166
    /**
167
     * Validates the Ecuadorian RUC of Public Companies
168
     *
169
     * @param string $number Number of RUC Public Companies
170
     * @return string|null
171
     */
172 View Code Duplication
    public function validatePublicCompanyRuc($number)
173
    {
174
        $this->setError('');
175
176
        try {
177
            $this->initValidation($number, $this->lenght['ruc']);
178
            $this->provinceCodeValidation(substr($number, 0, 2));
179
            $this->thirdDigitValidation($number[2], self::PublicCompany);
180
            $this->theLastDigitsValidation(substr($number, 9, 4), self::PublicCompany);
181
            $this->moduleEleven($number, self::PublicCompany);
182
        } catch (EcuadorIdentificationException $e) {
183
            $this->setError($e->getMessage());
184
            return null;
185
        }
186
187
        return $this->billingCode['ruc'];
188
    }
189
190
    /**
191
     * Validates the Ecuadorian Final Consumer
192
     *
193
     * @param $number
194
     * @return string|null
195
     */
196
    public function validateFinalConsumer($number)
197
    {
198
        $this->setError('');
199
200
        try {
201
            if ($number != config('laravel-ecuador-identification.final-customer.unique-value')) {
202
                throw new EcuadorIdentificationException("Field is invalid");
203
            }
204
        } catch (EcuadorIdentificationException $e) {
205
            $this->setError($e->getMessage());
206
            return null;
207
        }
208
209
        return $this->billingCode['final-customer'];
210
    }
211
212
    /**
213
     * Validate that the number belongs to natural persons.
214
     *
215
     * @param $number
216
     * @return string|null
217
     */
218
    public function validateIsNaturalPersons($number)
219
    {
220
        return $this->validatePersonalIdentification($number) !== null ?
221
            $this->validatePersonalIdentification($number) : $this->validateNaturalPersonRuc($number);
222
    }
223
224
    /**
225
     * Validate that the number belongs to juridical persons.
226
     *
227
     * @param $number
228
     * @return string|null
229
     */
230
    public function validateIsJuridicalPersons($number)
231
    {
232
        return $this->validatePrivateCompanyRuc($number) !== null ?
233
            $this->validatePrivateCompanyRuc($number) : $this->validatePublicCompanyRuc($number);
234
    }
235
236
    /**
237
     * Validate the number with all types of documents.
238
     *
239
     * @param $number
240
     * @return string|null
241
     */
242
    public function validateAllIdentificatons($number)
243
    {
244
        if (($result = $this->validateFinalConsumer($number)) !== null) {
245
            return $result;
246
        }
247
248
        if (($result = $this->validatePersonalIdentification($number)) !== null) {
249
            return $result;
250
        }
251
252
        if (($result = $this->validateNaturalPersonRuc($number)) !== null) {
253
            return $result;
254
        }
255
256
        if (($result = $this->validatePrivateCompanyRuc($number)) !== null) {
257
            return $result;
258
        }
259
260
        return $this->validatePublicCompanyRuc($number);
261
    }
262
263
    /**
264
     * Initial validation of the identification, not empty, only digits, not less than the given length.
265
     *
266
     * @param string $value CI or RUC
267
     * @param int $len Number of characters required
268
     * @return bool
269
     * @throws EcuadorIdentificationException When the value is empty, when the value isn't digits and
270
     * when the value doesn't have the required length
271
     */
272
    private function initValidation($value, $len)
273
    {
274
        if (empty($value)) {
275
            throw new EcuadorIdentificationException('Field must have a value.');
276
        }
277
278
        if (!ctype_digit($value)) {
279
            throw new EcuadorIdentificationException('Must be digits.');
280
        }
281
282
        if (strlen($value) != $len) {
283
            throw new EcuadorIdentificationException("Must be {$len} digits.");
284
        }
285
286
        return true;
287
    }
288
289
    /**
290
     * Validate the province code (first two numbers of CI/RUC)
291
     * The first 2 positions correspond to the province where it was issued,
292
     * so the first two numbers will not be greater than 24 or less than 1
293
     *
294
     * @param string $value First two numbers of CI/RUC
295
     * @return boolean
296
     * @throws EcuadorIdentificationException When the province code is not between 1 and 24
297
     */
298
    private function provinceCodeValidation($value)
299
    {
300
        if ($value < 1 || $value > $this->provinces) {
301
            throw new EcuadorIdentificationException("In your province code must be between 01 and {$this->provinces}.");
302
        }
303
304
        return true;
305
    }
306
307
    /**
308
     * Valid the third digit
309
     *
310
     * It allows the third digit of the document to be valid.
311
     * Depending on the type field (type of identification) validations are performed.
312
     *
313
     * NATURAL_PERSON
314
     * For Certificates and RUC of natural persons the third digit is less than 6 so
315
     * it must be between 0 and 5 (0,1,2,3,4,5)
316
     *
317
     * PRIVATE_COMPANY
318
     * For RUC of private companies the third digit must be equal to 9.
319
     *
320
     * PUBLIC_COMPANY
321
     * For RUC of public companies the third digit must be equal to 6.
322
     *
323
     * @param string $value Third digit of CI/RUC
324
     * @param string $type Type of identifier
325
     * @return boolean
326
     * @throws EcuadorIdentificationException When it does not comply with the validation according to the type of identifier
327
     */
328
    private function thirdDigitValidation($value, $type)
329
    {
330
        switch ($type) {
331
            case self::NaturalPerson:
332
                $min = config('laravel-ecuador-identification.personal-identification.third-digit.min');
333
                $max = config('laravel-ecuador-identification.personal-identification.third-digit.max');
334
                if ($value < $min || $value > $max)
335
                    throw new EcuadorIdentificationException("Field must have the third digit between {$min} and {$max}.");
336
                break;
337
338 View Code Duplication
            case self::PublicCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
339
                $thirdDigit = config('laravel-ecuador-identification.public-ruc.third-digit');
340
                if ($value != $thirdDigit)
341
                    throw new EcuadorIdentificationException("Field must have the third digit equal to {$thirdDigit}.");
342
                break;
343
344 View Code Duplication
            case self::PrivateCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
345
                $thirdDigit = config('laravel-ecuador-identification.private-ruc.third-digit');
346
                if ($value != $thirdDigit)
347
                    throw new EcuadorIdentificationException("Field must have the third digit equal to {$thirdDigit}.");
348
                break;
349
350
            default:
351
                throw new EcuadorIdentificationException('Field does not have this type of identification.');
352
        }
353
354
        return true;
355
    }
356
357
    /**
358
     * Validation of the last digits
359
     *
360
     * Public Ruc => 0001
361
     * Other Ruc => 001
362
     *
363
     * @param string $value The last digits
364
     * @param string $type Type of identifier
365
     * @return boolean
366
     * @throws EcuadorIdentificationException When not equal to 001
367
     */
368
    private function theLastDigitsValidation($value, $type)
369
    {
370
        switch ($type) {
371 View Code Duplication
            case self::NaturalPerson:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
372
                $lastDigits = config('laravel-ecuador-identification.natural-ruc.last-digits');
373
                if ($value != $lastDigits) {
374
                    throw new EcuadorIdentificationException("Field does not have the last digits equal to {$lastDigits}");
375
                }
376
                break;
377
378 View Code Duplication
            case self::PrivateCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
                $lastDigits = config('laravel-ecuador-identification.private-ruc.last-digits');
380
                if ($value != $lastDigits) {
381
                    throw new EcuadorIdentificationException("Field does not have the last digits equal to {$lastDigits}");
382
                }
383
                break;
384
385 View Code Duplication
            case self::PublicCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
386
                $lastDigits = config('laravel-ecuador-identification.public-ruc.last-digits');
387
                if ($value != $lastDigits) {
388
                    throw new EcuadorIdentificationException("Field does not have the last digits equal to {$lastDigits}");
389
                }
390
                break;
391
392
            default:
393
                throw new EcuadorIdentificationException('Field does not have this type of identification.');
394
        }
395
396
        return true;
397
    }
398
399
    /**
400
     * Module 10 Algorithm to validate if Certificates and RUC of natural person are valid.
401
     *
402
     * Coefficients used to validate the tenth digit of the Certificates,
403
     * are:  2, 1, 2, 1, 2, 1, 2, 1, 2
404
     *
405
     * Step 1: Multiply each digit of the card by the coefficient,
406
     * except for the verification digit (tenth digit),
407
     * if it is greater than 10 sums between digits. Example:
408
     *
409
     * 2  1  2  1  2  1  2  1  2  (Coefficients)
410
     * 1  7  1  0  0  3  4  0  6  (Certificate)
411
     * 2  7  2  0  0  3  8  0  [12] => continue to step 2.
412
     *
413
     * Step 2: If any of the multiplication results is greater than 10,
414
     * it is added between digits of the result. Example: [12] => 1 + 2 = Result (3)
415
     *
416
     * Step 3: The result of the multiplications is added. Example:
417
     * 2  7  2  0  0  3  8  0  3 = Result (25)
418
     *
419
     * Step 4: The result of the sum is divided by 10 and the remainder of the division is obtained
420
     * If the remainder is 0 the check digit is 0
421
     * Otherwise, the residue is subtracted from 10
422
     *
423
     * If the result is equal to the verification digit, the value is correct.
424
     *
425
     * @param string $number Certificates or RUC of natural person
426
     * @return boolean
427
     * @throws EcuadorIdentificationException The verified digit does not match the verification digit.
428
     */
429
    protected function moduleTen($number)
430
    {
431
        $check_digit_position = config('laravel-ecuador-identification.personal-identification.check-digit-position');
432
        $coefficients = config('laravel-ecuador-identification.personal-identification.coefficients');
433
434
        $check_digit_value = $number[$check_digit_position - 1];
435
        $numbers = str_split(substr($number, 0, 9));
436
437
        $total = 0;
438
439
        foreach ($numbers as $key => $value) {
440
            $proceeds = ($value * $coefficients[$key]);
441
442
            if ($proceeds >= 10) {
443
                $proceeds = str_split($proceeds);
444
                $proceeds = array_sum($proceeds);
445
            }
446
447
            $total += $proceeds;
448
        }
449
450
        $residue = $total % 10;
451
452
        $verified_digit_value = $residue == 0 ? 0 : 10 - $residue;
453
454
        if ($verified_digit_value != $check_digit_value) {
455
            throw new EcuadorIdentificationException('Field is invalid');
456
        }
457
458
        return true;
459
    }
460
461
    /**
462
     * Module 11 Algorithm to validate if RUC of Public Companies and Private Companies are valid.
463
     *
464
     * For Public Companies (Third Digit => [6]):
465
     * => The verifier digit is the ninth digit.
466
     * => Coefficients used to validate the ninth digit of the Public Company RUC, (Third digit = [6])
467
     * are:  3, 2, 7, 6, 5, 4, 3, 2
468
     *
469
     *
470
     * For Private Companies (Third Digit => [9]):
471
     * => The verifier digit is the tenth digit.
472
     * => Coefficients used to validate the tenth digit of the Private Company RUC, (Third digit = [9])
473
     * are:  4, 3, 2, 7, 6, 5, 4, 3, 2
474
     *
475
     * Step 1: Multiply each digit of the RUC with its respective coefficient,
476
     * except the verification digit. Example:
477
     *
478
     * Public Companies
479
     * 3   2   7   6  5  4  3  2  (Coefficients)
480
     * 1   7   6   0  0  0  1  0  [4]  0  0  0  1  (Public RUC) [4] => Ninth Digit (Check Digit)
481
     * 3   14  42  0  0  0  3  0 => Multiplication Result
482
     *
483
     * Private Companies
484
     * 4   3   2   7   6   5   4   3   2  (Coefficients)
485
     * 1   7   9   0   0   8   5   7   8   [3]  0  0  1   (Private RUC) [3] => Tenth Digit (Check Digit)
486
     * 4   21  18  0   0   40  20  21  16 => Multiplication Result
487
     *
488
     * Step 2: The multiplication results are added
489
     *
490
     * Public Companies
491
     * 3  14  42  0  0  0  3  0 = Result (62)
492
     *
493
     * * Private Companies
494
     * 4  21  18  0  0  40  20  21  16 = Result (140)
495
     *
496
     * Step 3: The result of the sum is divided to 11 and the remainder of the division is obtained.
497
     * If the remainder is 0 the check digit is 0
498
     * Otherwise, the residue is subtracted from 11
499
     *
500
     * If the result is equal to the verification digit, the value is correct.
501
     *
502
     * @param string $number Private Company RUC or Public Compnay RUC
503
     * @param string $type Type of identifier
504
     * @return boolean
505
     * @throws EcuadorIdentificationException The verified digit does not match the verification digit.
506
     */
507
    protected function moduleEleven($number, $type)
508
    {
509
        switch ($type) {
510 View Code Duplication
            case self::PrivateCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
511
                $coefficients = config('laravel-ecuador-identification.private-ruc.coefficients');
512
                $check_digit_position = config('laravel-ecuador-identification.private-ruc.check-digit-position');
513
                $check_digit_value = $number[$check_digit_position - 1];
514
                $numbers = str_split(substr($number, 0, 9));
515
                break;
516 View Code Duplication
            case self::PublicCompany:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
517
                $coefficients = config('laravel-ecuador-identification.public-ruc.coefficients');
518
                $check_digit_position = config('laravel-ecuador-identification.public-ruc.check-digit-position');
519
                $check_digit_value = $number[$check_digit_position - 1];
520
                $numbers = str_split(substr($number, 0, 8));
521
                break;
522
            default:
523
                throw new EcuadorIdentificationException('Field does not have this type of identification.');
524
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
525
        }
526
527
        $total = 0;
528
529
        foreach ($numbers as $key => $value) {
530
            $proceeds = ($value * $coefficients[$key]);
531
            $total += $proceeds;
532
        }
533
534
        $residue = $total % 11;
535
536
        $verified_digit_value = $residue == 0 ? 0 : 11 - $residue;
537
538
        if ($verified_digit_value != $check_digit_value) {
539
            throw new EcuadorIdentificationException('Field is invalid');
540
        }
541
542
        return true;
543
    }
544
}
545