defra_ruby_companies_house 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []