From 2ddafeab2ee89b69a75a261df8eb91909fac903d Mon Sep 17 00:00:00 2001 From: ankitkhadria <86760336+ankitkhadria@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:42:30 +0530 Subject: [PATCH 1/4] Added Faker::Company.indian_gst_number fixed #2823 --- doc/default/company.md | 4 +++ lib/faker/default/company.rb | 42 ++++++++++++++++++++++++ test/faker/default/test_faker_company.rb | 9 +++++ 3 files changed, 55 insertions(+) diff --git a/doc/default/company.md b/doc/default/company.md index 303c100da0..5e0774c65d 100644 --- a/doc/default/company.md +++ b/doc/default/company.md @@ -84,4 +84,8 @@ Faker::Company.russian_tax_number #=> "0965855857" Faker::Company.russian_tax_number(region: '77') #=> "7717152803" Faker::Company.russian_tax_number(type: :individual) #=> "488935903348" Faker::Company.russian_tax_number(region: '77', type: :individual) #=> "779124694601" + +# Get a random formatted Indian tax number (GST) +Faker::Company.indian_gst_number #=> "15VQPNZ2126J2ZU" +Faker::Company.indian_gst_number(state_code: "22") #=> "22ZVWEY6632K0ZN" ``` diff --git a/lib/faker/default/company.rb b/lib/faker/default/company.rb index ec3feb6fcb..31dd87038b 100644 --- a/lib/faker/default/company.rb +++ b/lib/faker/default/company.rb @@ -464,6 +464,35 @@ def sic_code fetch('company.sic_code') end + ## + # Get a random Indian Goods and Services Tax (GST) number. + # For more on Indian tax number here: + # https://simple.wikipedia.org/wiki/GSTIN + # @params state code [String] Any state code. + # + # @return [String] + # @example + # Faker::Company.indian_gst_number #=> "15VQPNZ2126J2ZU" + # Faker::Company.indian_gst_number(state_code: "22") #=> "22ZVWEY6632K0ZN" + # + # @faker.version 3.2.1 + def indian_gst_number(state_code: nil) + state_code_list = %w[01 02 03 04 05 06 07 08 09 10 11 12 13 14 97] + state_code = state_code_list.sample(random: Faker::Config.random) if state_code.nil? + taxpayer_number = Array.new(3) { ('A'..'Z').to_a.sample(random: Faker::Config.random) } + Array.new(1) { + %w[A B C F G H L J P T + K].to_a.sample(random: Faker::Config.random) + } + Array.new(1) { + ('A'..'Z').to_a.sample(random: Faker::Config.random) + } + Array.new(4) { + rand(10) + } + [('A'..'Z').to_a.sample(random: Faker::Config.random)] + taxpayer_number = taxpayer_number.join + registration_number = rand(10).to_s + checksum = calculate_gst_checksum(state_code, taxpayer_number, registration_number) + "#{state_code}#{taxpayer_number}#{registration_number}Z#{checksum}" + end + private # Mod11 functionality from https://github.com/badmanski/mod11/blob/master/lib/mod11.rb @@ -605,6 +634,19 @@ def spanish_b_algorithm(value) result.to_s[0].to_i + result.to_s[1].to_i end + + def calculate_gst_checksum(state_code, taxpayer_number, registration_number) + gst_base = "#{state_code}#{taxpayer_number}#{registration_number}" + chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.chars + values = gst_base.upcase.chars + sum = values.map.with_index do |char, index| + product = chars.index(char) * (index.odd? ? 2 : 1) + (product / chars.length).floor + (product % chars.length) + end.reduce(:+) + + checksum = (chars.length - (sum % chars.length)) % chars.length + chars[checksum] + end end end end diff --git a/test/faker/default/test_faker_company.rb b/test/faker/default/test_faker_company.rb index f9e190f840..35d46e0277 100644 --- a/test/faker/default/test_faker_company.rb +++ b/test/faker/default/test_faker_company.rb @@ -250,6 +250,15 @@ def test_spanish_b_algorithm assert_equal(3, @tester.send(:spanish_b_algorithm, 6)) end + def text_indian_gst_number + assert_match(/^([0-2][0-9]|[3][0-7])[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number) + end + + def test_indian_gst_number_with_state_code + assert_match(/^(22)[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number(state_code: '22')) + assert_match(/^(01)[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number(state_code: '01')) + end + private def czech_o_n_checksum(org_no) From a03a8581721d2164e67a6778da9237774909f3d7 Mon Sep 17 00:00:00 2001 From: ankitkhadria <86760336+ankitkhadria@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:17:13 +0530 Subject: [PATCH 2/4] refactor: using positional generator and added state code validation --- lib/faker/default/company.rb | 52 +++++++++++++++++------- test/faker/default/test_faker_company.rb | 7 +++- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/faker/default/company.rb b/lib/faker/default/company.rb index 31dd87038b..9d16b2dc6c 100644 --- a/lib/faker/default/company.rb +++ b/lib/faker/default/company.rb @@ -477,20 +477,44 @@ def sic_code # # @faker.version 3.2.1 def indian_gst_number(state_code: nil) - state_code_list = %w[01 02 03 04 05 06 07 08 09 10 11 12 13 14 97] - state_code = state_code_list.sample(random: Faker::Config.random) if state_code.nil? - taxpayer_number = Array.new(3) { ('A'..'Z').to_a.sample(random: Faker::Config.random) } + Array.new(1) { - %w[A B C F G H L J P T - K].to_a.sample(random: Faker::Config.random) - } + Array.new(1) { - ('A'..'Z').to_a.sample(random: Faker::Config.random) - } + Array.new(4) { - rand(10) - } + [('A'..'Z').to_a.sample(random: Faker::Config.random)] - taxpayer_number = taxpayer_number.join - registration_number = rand(10).to_s - checksum = calculate_gst_checksum(state_code, taxpayer_number, registration_number) - "#{state_code}#{taxpayer_number}#{registration_number}Z#{checksum}" + # Check if state code is valid + state_code_ranges = ['02'..'38', ['98']] + raise ArgumentError, 'state code must be in a range of 02 to 38 or 98' if state_code && (!state_code_ranges[0].cover?(state_code) || state_code_ranges[1][0] != '98') + + PositionalGenerator.new(:string) do |gen| + # Generate a state code if not given + if state_code + gen.lit(state_code, name: :state_code_param) + else + gen.letter(name: :state_code_param, length: 1, ranges: state_code_ranges) + end + + # Construct taxpayer number + gen.group(name: :taxpayer_number) do |g_| + g_.letter(length: 3, ranges: ['A'..'Z']) + g_.letter(length: 1, ranges: [%w[A B C F G H L J P T K]].to_a) + g_.letter(length: 1, ranges: ['A'..'Z']) + g_.int(length: 4, ranges: [0..9999]) + g_.letter(length: 1, ranges: ['A'..'Z']) + end + + gen.int(name: :registration_number, length: 1, ranges: [0..9]) + + gen.letter(name: :z_char, length: 1, ranges: [['Z']]) + + gen.computed(deps: %i[state_code_param taxpayer_number registration_number]) do |state_code_param, taxpayer_number, registration_number| + gst_base = "#{state_code_param}#{taxpayer_number}#{registration_number}" + chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.chars + values = gst_base.chars + sum = values.map.with_index do |char, index| + product = chars.index(char) * (index.odd? ? 2 : 1) + (product / chars.length).floor + (product % chars.length) + end.reduce(:+) + + checksum = (chars.length - (sum % chars.length)) % chars.length + chars[checksum] + end + end.generate end private diff --git a/test/faker/default/test_faker_company.rb b/test/faker/default/test_faker_company.rb index 35d46e0277..9b23bc270e 100644 --- a/test/faker/default/test_faker_company.rb +++ b/test/faker/default/test_faker_company.rb @@ -254,9 +254,14 @@ def text_indian_gst_number assert_match(/^([0-2][0-9]|[3][0-7])[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number) end + def test_state_code_in_indian_gst_number + assert_raise ArgumentError do + @tester.indian_gst_number(state_code: '01') + end + end + def test_indian_gst_number_with_state_code assert_match(/^(22)[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number(state_code: '22')) - assert_match(/^(01)[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z][A-Z0-9][Z][A-Z0-9]$/i, @tester.indian_gst_number(state_code: '01')) end private From 0e5572aacd62647672d7c726c4809c9d797b99ec Mon Sep 17 00:00:00 2001 From: ankitkhadria <86760336+ankitkhadria@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:54:23 +0530 Subject: [PATCH 3/4] fix: state code validation condition --- lib/faker/default/company.rb | 4 ++-- test/faker/default/test_faker_company.rb | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/faker/default/company.rb b/lib/faker/default/company.rb index 9d16b2dc6c..6707ce7e18 100644 --- a/lib/faker/default/company.rb +++ b/lib/faker/default/company.rb @@ -478,8 +478,8 @@ def sic_code # @faker.version 3.2.1 def indian_gst_number(state_code: nil) # Check if state code is valid - state_code_ranges = ['02'..'38', ['98']] - raise ArgumentError, 'state code must be in a range of 02 to 38 or 98' if state_code && (!state_code_ranges[0].cover?(state_code) || state_code_ranges[1][0] != '98') + state_code_ranges = [('02'..'38'), ['98']] + raise ArgumentError, 'state code must be in a range of 02 to 38 or 98' if state_code && !(state_code_ranges[0].include?(state_code) || state_code == '98') PositionalGenerator.new(:string) do |gen| # Generate a state code if not given diff --git a/test/faker/default/test_faker_company.rb b/test/faker/default/test_faker_company.rb index 61e50c1340..2a62220c24 100644 --- a/test/faker/default/test_faker_company.rb +++ b/test/faker/default/test_faker_company.rb @@ -258,6 +258,9 @@ def test_state_code_in_indian_gst_number assert_raise ArgumentError do @tester.indian_gst_number(state_code: '01') end + assert_raise ArgumentError do + @tester.indian_gst_number(state_code: '100') + end end def test_indian_gst_number_with_state_code From e6d0db1085a841f70095b19d01c166e00c1f82c2 Mon Sep 17 00:00:00 2001 From: ankitkhadria <86760336+ankitkhadria@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:10:50 +0530 Subject: [PATCH 4/4] Update styling of if condition to check state code validation Co-authored-by: Stefanni Brasil --- lib/faker/default/company.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/faker/default/company.rb b/lib/faker/default/company.rb index 6707ce7e18..590cf3086d 100644 --- a/lib/faker/default/company.rb +++ b/lib/faker/default/company.rb @@ -479,7 +479,9 @@ def sic_code def indian_gst_number(state_code: nil) # Check if state code is valid state_code_ranges = [('02'..'38'), ['98']] - raise ArgumentError, 'state code must be in a range of 02 to 38 or 98' if state_code && !(state_code_ranges[0].include?(state_code) || state_code == '98') + if state_code && !(state_code_ranges[0].include?(state_code) || state_code == '98') + raise ArgumentError, 'state code must be in a range of 02 to 38 or 98' + end PositionalGenerator.new(:string) do |gen| # Generate a state code if not given