defra_ruby_companies_house 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b916c7f7519769a21a038a9f8aad59c9bac9fe370c0d97c39679722f80c21ed0
4
+ data.tar.gz: 23c12287100df332cf28a65a1f82600d73f75f0ef0c1ad255828a632356f4804
5
+ SHA512:
6
+ metadata.gz: 55feda28269d6f06426f2adaaf9a502e0c60a29cba2413e4d48740595c5ab03dff94fa70aa994af05e80bf5b34412bbf0e63bac09661eb6e1dfc474ed6666195
7
+ data.tar.gz: d6d45480e0aac478a41a27496fa8b4d34f4ba17671c83970abd0097815a061b094f7759fd85406238a273b3ae263e074122fa54fad4fad0cff878c5d9c6aea22
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The Open Government Licence (OGL) Version 3
2
+
3
+ Copyright (c) 2024 Environment Agency
4
+
5
+ This source code is licensed under the Open Government Licence v3.0. To view this
6
+ licence, visit www.nationalarchives.gov.uk/doc/open-government-licence/version/3
7
+ or write to the Information Policy Team, The National Archives, Kew, Richmond,
8
+ Surrey, TW9 4DU.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Defra Ruby Companies House
2
+
3
+ ![Build Status](https://github.com/DEFRA/defra-ruby-companies-house/workflows/CI/badge.svg?branch=main)
4
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_defra-ruby-companies-house&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=DEFRA_defra-ruby-companies-house)
5
+ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_defra-ruby-companies-house&metric=coverage)](https://sonarcloud.io/dashboard?id=DEFRA_defra-ruby-companies-house)
6
+ [![Gem Version](https://badge.fury.io/rb/defra_ruby_companies_house.svg)](https://badge.fury.io/rb/defra_ruby_companies_house)
7
+ [![Licence](https://img.shields.io/badge/Licence-OGLv3-blue.svg)](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3)
8
+
9
+ Single point of access to the Companies House API with standardised initial error handling.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile
14
+
15
+ ```ruby
16
+ gem "defra_ruby_companies_house"
17
+ ```
18
+
19
+ And then update your dependencies by calling
20
+
21
+ ```bash
22
+ bundle install
23
+ ```
24
+
25
+ ## Usage
26
+ Call the Api.run method with the company number:
27
+
28
+ ```ruby
29
+ DefraRuby::CompaniesHouse.run("12345678")
30
+ ```
31
+ If the company is found, the response will consist of a Hash including:
32
+ - `company_name`
33
+ - `company_type`, e.g. "ltd", "llp", "plc"
34
+ - `company_status`, e.g. "active"
35
+ - `registered_address`, an array of address lines
36
+
37
+ ## Error handling
38
+ The gem catches errors from the Companies House API and from the REST client and maps them to custom errors as follows.
39
+ - Company not found: `DefraRuby::CompaniesHouse::CompanyNotFoundError`
40
+ - Companies House API timeout: `DefraRuby::CompaniesHouse::ApiTimeoutError`
41
+ - General Companies House API errors: `DefraRuby::CompaniesHouse::ApiError`
42
+
43
+ The gem will log these errors to Airbrake if it is enabled, in which case there is no need for the app to also log the error.
44
+
45
+ ## Contributing to this project
46
+
47
+ If you have an idea you'd like to contribute please log an issue.
48
+
49
+ All contributions should be submitted via a pull request.
50
+
51
+ ## License
52
+
53
+ THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
54
+
55
+ http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
56
+
57
+ The following attribution statement MUST be cited in your products and applications when using this information.
58
+
59
+ > Contains public sector information licensed under the Open Government license v3
60
+
61
+ ### About the license
62
+
63
+ The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
64
+
65
+ It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ # This is wrapped to prevent an error when rake is called in environments where
12
+ # rspec may not be available, e.g. production. As such we don't need to handle
13
+ # the error.
14
+ begin
15
+ require "rspec/core/rake_task"
16
+
17
+ RSpec::Core::RakeTask.new(:spec)
18
+
19
+ task default: :spec
20
+ rescue LoadError
21
+ # no rspec available
22
+ end
23
+
24
+ begin
25
+ require "github_changelog_generator/task"
26
+
27
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
28
+ config.user = "defra"
29
+ config.project = "defra-ruby-companies-house"
30
+ end
31
+ rescue LoadError
32
+ # no changelog available
33
+ end
@@ -0,0 +1,7 @@
1
+ en:
2
+ defra_ruby:
3
+ companies_house:
4
+ errors:
5
+ timeout: Companies House API timeout
6
+ invalid_company_number: "Invalid company number: %{company_number}"
7
+ company_not_found: "Company not found: %{company_number}"
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rest-client"
4
+
5
+ # for deep_symbolize_keys
6
+ require "active_support/core_ext/hash/keys"
7
+
8
+ module DefraRuby
9
+ module CompaniesHouse
10
+
11
+ # https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/426891/uniformResourceIdentifiersCustomerGuide.pdf
12
+ VALID_COMPANY_NUMBER_REGEX = /\A(\d{8,8}$)|([a-zA-Z]{2}\d{6}$)|([a-zA-Z]{2}\d{5}[a-zA-Z]{1}$)\z/i
13
+
14
+ # Custom error classes to handle Companies House API errors
15
+ class ApiTimeoutError < StandardError
16
+ def message
17
+ I18n.t(".defra_ruby.companies_house.errors.timeout")
18
+ end
19
+ end
20
+
21
+ class InvalidCompanyNumberError < StandardError
22
+ def initialize(company_number)
23
+ @company_number = company_number
24
+ super
25
+ end
26
+
27
+ def message
28
+ I18n.t(".defra_ruby.companies_house.errors.invalid_company_number", company_number: @company_number)
29
+ end
30
+ end
31
+
32
+ class CompanyNotFoundError < StandardError
33
+ def initialize(company_number)
34
+ @company_number = company_number
35
+ super
36
+ end
37
+
38
+ def message
39
+ I18n.t(".defra_ruby.companies_house.errors.company_not_found", company_number: @company_number)
40
+ end
41
+ end
42
+
43
+ # The API class is responsible for making requests to the Companies House API.
44
+ # It handles the construction of request URLs, headers, and payload,
45
+ # and also deals with any errors that occur during the API request.
46
+ class API
47
+
48
+ attr_accessor :company_number
49
+
50
+ def self.run(company_number:)
51
+ new.run(company_number:)
52
+ end
53
+
54
+ def run(company_number:)
55
+ @company_number = format_company_number(company_number)
56
+ validate_company_number
57
+
58
+ companies_house_details
59
+ rescue InvalidCompanyNumberError
60
+ # just re-raise - this is to prevent the StandardError rescue logging it again
61
+ raise
62
+ rescue RestClient::Exceptions::Timeout => e
63
+ log_error(e)
64
+ raise DefraRuby::CompaniesHouse::ApiTimeoutError
65
+ rescue RestClient::ResourceNotFound, RestClient::NotFound => e
66
+ log_error(e)
67
+ raise DefraRuby::CompaniesHouse::CompanyNotFoundError, company_number
68
+ rescue StandardError => e
69
+ log_error(e)
70
+ raise e
71
+ end
72
+
73
+ private
74
+
75
+ def companies_house_details
76
+ @companies_house_details ||= {
77
+ company_name: companies_house_api_response[:company_name],
78
+ company_type: companies_house_api_response[:type].to_sym,
79
+ company_status: companies_house_api_response[:company_status].to_sym,
80
+ registered_office_address: registered_office_address_lines
81
+ }
82
+ end
83
+
84
+ def companies_house_api_response
85
+ @companies_house_api_response ||= JSON.parse(
86
+ RestClient::Request.execute(
87
+ method: :get,
88
+ url: companies_house_endpoint,
89
+ user: api_key,
90
+ password: ""
91
+ )
92
+ ).deep_symbolize_keys
93
+ end
94
+
95
+ def companies_house_endpoint
96
+ "#{DefraRuby::CompaniesHouse.configuration.companies_house_host}/company/#{company_number}"
97
+ end
98
+
99
+ def api_key
100
+ DefraRuby::CompaniesHouse.configuration.companies_house_api_key
101
+ end
102
+
103
+ # rubocop:disable Naming/VariableNumber
104
+ def registered_office_address_lines
105
+ address = companies_house_api_response[:registered_office_address]
106
+
107
+ [
108
+ address[:address_line_1],
109
+ address[:address_line_2],
110
+ address[:locality],
111
+ address[:postal_code]
112
+ ].compact
113
+ end
114
+ # rubocop:enable Naming/VariableNumber
115
+
116
+ def validate_company_number
117
+ return if company_number.match?(VALID_COMPANY_NUMBER_REGEX) && !company_number.match(/^0+$/)
118
+
119
+ error = DefraRuby::CompaniesHouse::InvalidCompanyNumberError.new(company_number)
120
+
121
+ log_error(error)
122
+ raise error
123
+ end
124
+
125
+ def format_company_number(raw_company_number)
126
+ raw_company_number.to_s.upcase.rjust(8, "0")
127
+ end
128
+
129
+ def log_error(error)
130
+ logged_error = "Error getting details for company \"#{company_number}\": #{error}"
131
+ DefraRuby::CompaniesHouse.logger.error logged_error
132
+ Airbrake.notify(logged_error) if defined?(Airbrake)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRuby
4
+ module CompaniesHouse
5
+ class Configuration
6
+ attr_accessor :companies_house_host, :companies_house_api_key
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRuby
4
+ module CompaniesHouse
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace DefraRuby::CompaniesHouse
7
+
8
+ # Add a load path for this specific Engine
9
+ config.autoload_paths += Dir[File.join(config.root, "lib", "**")]
10
+
11
+ # Load I18n translation files from engine before loading ones from the host app
12
+ # This means values in the host app can override those in the engine
13
+ config.before_initialize do
14
+ # engine_locales = Dir["#{config.root}/config/locales/**/*.yml"]
15
+ engine_locales = Dir.glob( File.dirname(__FILE__) + "lib/locales/*.{rb,yml}" )
16
+ config.i18n.load_path = engine_locales + config.i18n.load_path
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRuby
4
+ module CompaniesHouse
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ require_relative "companies_house/version"
6
+ require_relative "companies_house/configuration"
7
+ require_relative "companies_house/api"
8
+
9
+ # The DefraRuby::CompaniesHouse module facilitates integration with the Companies House API.
10
+ # It provides a consistemt, convenient way to interact with the Companies House API in Defra's ruby applications.
11
+ module DefraRuby
12
+ module CompaniesHouse
13
+ class << self
14
+ attr_accessor :configuration
15
+ end
16
+
17
+ def self.configure
18
+ self.configuration ||= Configuration.new
19
+ yield(configuration)
20
+ end
21
+
22
+ # Use DefraRubyGovpay.logger if it exists, else use a simple console logger
23
+ def self.logger
24
+ @logger ||= defined?(Rails) ? Rails.logger : Logger.new($stdout)
25
+ end
26
+
27
+ def self.logger=(logger)
28
+ @logger = logger
29
+ end
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: defra_ruby_companies_house
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Defra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: i18n
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: Single point of access to the Companies House API with associated error
42
+ handling, used in Defra Rails based digital services
43
+ email:
44
+ - pauldoyle1@environment-agency.gov.uk
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE
50
+ - README.md
51
+ - Rakefile
52
+ - config/locales/en.yml
53
+ - lib/defra_ruby/companies_house.rb
54
+ - lib/defra_ruby/companies_house/api.rb
55
+ - lib/defra_ruby/companies_house/configuration.rb
56
+ - lib/defra_ruby/companies_house/engine.rb
57
+ - lib/defra_ruby/companies_house/version.rb
58
+ homepage: https://github.com/DEFRA/defra-ruby-companies-house
59
+ licenses:
60
+ - The Open Government Licence (OGL) Version 3
61
+ metadata:
62
+ allowed_push_host: https://rubygems.org
63
+ rubygems_mfa_required: 'true'
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '3.1'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.3.7
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Defra ruby on rails helper for Companies House API
83
+ test_files: []