From e8e8c27c134cc695ee9ce54f26b6bb3338d707ae Mon Sep 17 00:00:00 2001 From: Moacir Petry Date: Mon, 27 Jul 2026 17:57:07 -0300 Subject: [PATCH] Add Faker::Company.brazilian_company_alphanumeric --- lib/faker/default/company.rb | 26 ++++++++++++++++++++ test/faker/default/test_faker_company.rb | 30 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/lib/faker/default/company.rb b/lib/faker/default/company.rb index e694f9802f..204b747c8a 100644 --- a/lib/faker/default/company.rb +++ b/lib/faker/default/company.rb @@ -435,6 +435,32 @@ def brazilian_company_number(formatted: false) formatted ? format('%s.%s.%s/%s-%s', *number.scan(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/).flatten) : number end + ## + # Produces a company brazilian company alphanumeric. + # + # @return [String] + # + # @example + # Faker::Company.brazilian_company_alphanumeric #=> "AB12CD34EFGH83" + # + # @faker.version next + def brazilian_company_alphanumeric(formatted: false) + base = Faker::Alphanumeric.alphanumeric(number: 12).upcase.chars + + factors = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 6].cycle + + 2.times do + checksum = base.inject(0) do |acc, char| + acc + (char.ord - 48) * factors.next + end % 11 + base << (checksum < 2 ? '0' : (11 - checksum).to_s) + end + + alphanumeric = base.join + + formatted ? format('%s.%s.%s/%s-%s', *alphanumeric.scan(/(.{2})(.{3})(.{3})(.{4})(.{2})/).flatten) : alphanumeric + end + ## # Get a random Russian tax number. # @param region [String] Any region string diff --git a/test/faker/default/test_faker_company.rb b/test/faker/default/test_faker_company.rb index a6e1a6846e..b9e6f7cd27 100644 --- a/test/faker/default/test_faker_company.rb +++ b/test/faker/default/test_faker_company.rb @@ -201,6 +201,36 @@ def test_brazilian_company_number_formatted assert_match(/^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/, sample) end + def test_brazilian_company_alphanumeric + sample = @tester.brazilian_company_alphanumeric + + assert_match(/\A[A-Z0-9]{14}\z/, sample) + assert_match(/\A.{12}\d{2}\z/, sample) + + values = sample[0..11].chars.map { |c| c.ord - 48 } + + weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] + sum1 = values.each_with_index.inject(0) { |acc, (v, i)| acc + v * weights1[i] } + remainder = sum1 % 11 + first_digit = remainder < 2 ? '0' : (11 - remainder).to_s + + assert_equal sample[12], first_digit + + values << first_digit.to_i + weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] + sum2 = values.each_with_index.inject(0) { |acc, (v, i)| acc + v * weights2[i] } + remainder2 = sum2 % 11 + second_digit = remainder2 < 2 ? '0' : (11 - remainder2).to_s + + assert_equal sample[13], second_digit + end + + def test_brazilian_company_alphanumeric_formatted + sample = @tester.brazilian_company_alphanumeric(formatted: true) + + assert_match(/\A[A-Z0-9]{2}\.[A-Z0-9]{3}\.[A-Z0-9]{3}\/[A-Z0-9]{4}-\d{2}\z/, sample) + end + def test_russian_tax_number_default assert_match(/\d{10}/, @tester.russian_tax_number) end