Skip to content
Open
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
31 changes: 28 additions & 3 deletions src/ec/ruc.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { validate, format } from './ruc';
import { InvalidLength, InvalidChecksum } from '../exceptions';
import {
InvalidLength,
InvalidChecksum,
InvalidComponent,
} from '../exceptions';

describe('ec/ruc', () => {
it('format:1792060346001', () => {
Expand Down Expand Up @@ -29,9 +33,30 @@ describe('ec/ruc', () => {
expect(result.error).toBeInstanceOf(InvalidLength);
});

it('validate:1792060347-001', () => {
const result = validate('1792060347-001');
// Company RUCs are issued by SRI without a check-digit algorithm, so
// numbers that fail the historical mod-11 scheme are still valid.
test.each(['1792060347001', '0993381661001', '1760001550001'])(
'validate:%s',
value => {
const result = validate(value);

expect(result.isValid).toEqual(true);
},
);

it('validate:0926687851-001', () => {
// Natural-person RUC with an invalid cedula check digit
const result = validate('0926687851-001');

expect(result.error).toBeInstanceOf(InvalidChecksum);
});

test.each(['0993381661000', '1760001550000', '2593381661001'])(
'validate-invalid-component:%s',
value => {
const result = validate(value);

expect(result.error).toBeInstanceOf(InvalidComponent);
},
);
});
42 changes: 14 additions & 28 deletions src/ec/ruc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
* The RUC is a tax identification number for legal entities. It has 13 digits
* where the third digit is a number denoting the type of entity.
*
* Source
* Company RUCs (third digit 6 = public, 9 = private/juridical) are issued by
* the SRI without any check-digit algorithm, so only structural checks apply
* to them; the historical mod-11 scheme rejects real registry-valid numbers.
* Cedula-based RUCs (third digit 0-5) do carry the cedula's check digit.
*
* Source
* https://minka.gob.ec/mintel/ge/rutr/gobec_forms/-/issues/32
* https://www.sri.gob.ec/en/web/intersri/consulta-al-ruc
*
* TAX/VAT
*/

import * as exceptions from '../exceptions';
import * as ci from './ci';
import { strings, weightedSum } from '../util';
import { strings } from '../util';
import { Validator, ValidateReturn } from '../types';

function clean(input: string): ReturnType<typeof strings.cleanUnicode> {
Expand Down Expand Up @@ -67,39 +73,19 @@ const impl: Validator = {
}

if (value[2] === '6') {
// Public RUC
const [front, end] = strings.splitAt(value, 9);
// Public RUC: SRI issues these without a check-digit algorithm, so
// only the establishment number is checked.
const [, end] = strings.splitAt(value, 9);
if (end === '0000') {
return { isValid: false, error: new exceptions.InvalidComponent() };
}

if (
weightedSum(front, {
weights: [3, 2, 7, 6, 5, 4, 3, 2, 1],
modulus: 11,
}) !== 0
) {
// If it's not a public, try natural
if (end.endsWith('000')) {
return { isValid: false, error: new exceptions.InvalidComponent() };
}

return ci.validate(value.substring(0, 10));
}
} else if (value[2] === '9') {
// Juridical RUC
const [front, end] = strings.splitAt(value, 10);
// Juridical RUC: SRI issues these without a check-digit algorithm, so
// only the establishment number is checked.
const [, end] = strings.splitAt(value, 10);
if (end === '000') {
return { isValid: false, error: new exceptions.InvalidComponent() };
}
if (
weightedSum(front, {
weights: [4, 3, 2, 7, 6, 5, 4, 3, 2, 1],
modulus: 11,
}) !== 0
) {
return { isValid: false, error: new exceptions.InvalidChecksum() };
}
} else {
return { isValid: false, error: new exceptions.InvalidComponent() };
}
Expand Down
Loading