From 1cc922d26a8a15df5b6a1c7244abf38ca474bfe6 Mon Sep 17 00:00:00 2001 From: sheilagomes Date: Fri, 29 May 2026 15:42:13 -0300 Subject: [PATCH 1/4] Fix validation for new alphanumeric CNPJ --- CHANGELOG.md | 2 ++ react/rules/BRA.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5a82a64..c0b998c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +- Fix validation for new alphanumeric CNPJ + ## [2.21.0] - 2024-09-18 ### Added diff --git a/react/rules/BRA.js b/react/rules/BRA.js index c729493c..ee19056d 100644 --- a/react/rules/BRA.js +++ b/react/rules/BRA.js @@ -91,7 +91,7 @@ export default { name: 'corporateDocument', maxLength: 30, label: 'BRA_cnpj', - mask: value => msk.fit(value, '99.999.999/9999-99'), + mask: value => msk.fit(value, 'AA.AAA.AAA/AAAA-99'), validate: value => { const cleanValue = value.replace(/[^\d]/g, '') if (cleanValue.length != 14) return false From a5cdf5edeca65c9ba341041c1551bfbd885e0c3b Mon Sep 17 00:00:00 2001 From: sheilagomes Date: Fri, 29 May 2026 15:49:57 -0300 Subject: [PATCH 2/4] Fix mask and validation to fit the correct alphanumeric pattern --- react/rules/BRA.js | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/react/rules/BRA.js b/react/rules/BRA.js index ee19056d..94db08e6 100644 --- a/react/rules/BRA.js +++ b/react/rules/BRA.js @@ -91,37 +91,28 @@ export default { name: 'corporateDocument', maxLength: 30, label: 'BRA_cnpj', - mask: value => msk.fit(value, 'AA.AAA.AAA/AAAA-99'), + mask: value => msk.fit(value, 'SS.SSS.SSS/SSSS-99'), validate: value => { - const cleanValue = value.replace(/[^\d]/g, '') - if (cleanValue.length != 14) return false - - const isRepeatedNum = '0123456789' - .split('') - .some(digit => digit.repeat(14) === cleanValue) - if (isRepeatedNum) return false - - const firstWeights = '543298765432'.split('') - const firstReduce = cleanValue - .split('') + const cleanValue = value.replace(/[.\/-]/g, '').toUpperCase() + if (cleanValue.length !== 14) return false + if (!/^[A-Z0-9]{12}\d{2}$/.test(cleanValue)) return false + + if (/^(.)\1+$/.test(cleanValue)) return false + + const getCharValue = char => char.charCodeAt(0) - 48 + const values = cleanValue.split('').map(getCharValue) + + const firstWeights = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] + const firstReduce = values .slice(0, 12) - .reduce( - (acc, cur, index) => - acc + parseInt(cur) * parseInt(firstWeights[index]), - 0, - ) + .reduce((acc, cur, index) => acc + cur * firstWeights[index], 0) const firstDigit = firstReduce % 11 < 2 ? 0 : 11 - (firstReduce % 11) if (firstDigit != cleanValue.charAt(12)) return false - - const secondWeights = ['6', ...firstWeights] - const secondReduce = cleanValue - .split('') + + const secondWeights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] + const secondReduce = values .slice(0, 13) - .reduce( - (acc, cur, index) => - acc + parseInt(cur) * parseInt(secondWeights[index]), - 0, - ) + .reduce((acc, cur, index) => acc + cur * secondWeights[index], 0) const secondDigit = secondReduce % 11 < 2 ? 0 : 11 - (secondReduce % 11) return secondDigit == cleanValue.charAt(13) }, From ce5ce03d6a84ef1e1ca38f3ab455f5f1e19b9e2d Mon Sep 17 00:00:00 2001 From: sheilagomes Date: Fri, 29 May 2026 16:06:09 -0300 Subject: [PATCH 3/4] Add tests to validate alphanumeric CNPJ --- react/__tests__/BRA.test.js | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 react/__tests__/BRA.test.js diff --git a/react/__tests__/BRA.test.js b/react/__tests__/BRA.test.js new file mode 100644 index 00000000..5b8955f5 --- /dev/null +++ b/react/__tests__/BRA.test.js @@ -0,0 +1,52 @@ +import BRA from '../rules/BRA' + +const getCnpjField = () => + BRA.businessFields.find(field => field.name === 'corporateDocument') + +describe('BRA corporateDocument (CNPJ)', () => { + const { mask, validate } = getCnpjField() + + describe('mask', () => { + it('masks numeric CNPJ', () => { + expect(mask('11222333000181')).toBe('11.222.333/0001-81') + }) + + it('masks alphanumeric CNPJ', () => { + expect(mask('12ABC34501DE35')).toBe('12.ABC.345/01DE-35') + }) + + it('masks lowercase alphanumeric input', () => { + expect(mask('12abc34501de35')).toBe('12.abc.345/01de-35') + }) + }) + + describe('validate', () => { + it('accepts valid numeric CNPJ', () => { + expect(validate('11.222.333/0001-81')).toBe(true) + }) + + it('accepts valid alphanumeric CNPJ', () => { + expect(validate('12.ABC.345/01DE-35')).toBe(true) + }) + + it('accepts unformatted valid CNPJ', () => { + expect(validate('11222333000181')).toBe(true) + }) + + it('rejects CNPJ with wrong length', () => { + expect(validate('11.222.333/0001')).toBe(false) + }) + + it('rejects numeric CNPJ with invalid check digits', () => { + expect(validate('11.222.333/0001-00')).toBe(false) + }) + + it('rejects alphanumeric CNPJ with invalid check digits', () => { + expect(validate('12.ABC.345/01DE-00')).toBe(false) + }) + + it('rejects repeated characters', () => { + expect(validate('00.000.000/0000-00')).toBe(false) + }) + }) +}) From aef8f4bdcb16e60a08bceb8a064813b79f90acb0 Mon Sep 17 00:00:00 2001 From: Sheila Gomes Date: Tue, 2 Jun 2026 09:19:19 -0300 Subject: [PATCH 4/4] Update react/rules/BRA.js Co-authored-by: Wagner Lemos Duarte --- react/rules/BRA.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/rules/BRA.js b/react/rules/BRA.js index 94db08e6..82f595e6 100644 --- a/react/rules/BRA.js +++ b/react/rules/BRA.js @@ -109,7 +109,7 @@ export default { const firstDigit = firstReduce % 11 < 2 ? 0 : 11 - (firstReduce % 11) if (firstDigit != cleanValue.charAt(12)) return false - const secondWeights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] + const secondWeights = [6, ...firstWeights] const secondReduce = values .slice(0, 13) .reduce((acc, cur, index) => acc + cur * secondWeights[index], 0)