defra_ruby_mocks 1.4.1 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37b80527c008c3d05100caffb316ae36fd75050a7d5612db07a180f163e3e17a
4
- data.tar.gz: 622dc9a174d7e0af97046b33a12164b37deec2d3574afebd42932b7c7b699171
3
+ metadata.gz: bc69209c2d4b90b3726d7486bb0f4f0f001d80aff649951f4e8eaa5e17e46cec
4
+ data.tar.gz: 2f8ca2c6731b2d0eae695e7aeae936c20288480bf758c4f16fcdcf3a27f70067
5
5
  SHA512:
6
- metadata.gz: ab9dec997252c0e656cb39c4364e9d2f28e28bfd707309178a3d0e17d3d3289241720cc4c78a1f542edef1545a5d30e43573aea389e6fc69ee33237e47414c95
7
- data.tar.gz: e3f3707826e51e569703a04aaaaeb4593f99db011331ffd73018909c8548f702cf317ccefe0f30308047b3734107b4ce292c8ef740fb362e9647834b3eb79e4c
6
+ metadata.gz: ed7a96c4eb66607adbe341b441181b339b60e28cf1d66e92e1eb6467606d82676110efc587d921a309fec419c472095a82c7b1b1bb8ebbff64740182c38723f4
7
+ data.tar.gz: f9b8847f14ac049e9b1cef302cfbe8893c6b56797e5f48e6b6548f939c16f923111c2f79be4023ab8c1c5a62aa91db10eebfc73b797de9feb7326798a65af215
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Defra Ruby Mocks
2
2
 
3
- [![Build Status](https://travis-ci.com/DEFRA/defra-ruby-mocks.svg?branch=master)](https://travis-ci.com/DEFRA/defra-ruby-mocks)
3
+ ![Build Status](https://github.com/DEFRA/defra-ruby-mocks/workflows/CI/badge.svg?branch=main)
4
4
  [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_defra-ruby-mocks&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=DEFRA_defra-ruby-mocks)
5
5
  [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_defra-ruby-mocks&metric=coverage)](https://sonarcloud.io/dashboard?id=DEFRA_defra-ruby-mocks)
6
- [![security](https://hakiri.io/github/DEFRA/defra-ruby-mocks/master.svg)](https://hakiri.io/github/DEFRA/defra-ruby-mocks/master)
6
+ [![security](https://hakiri.io/github/DEFRA/defra-ruby-mocks/main.svg)](https://hakiri.io/github/DEFRA/defra-ruby-mocks/main)
7
7
  [![Licence](https://img.shields.io/badge/Licence-OGLv3-blue.svg)](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3)
8
8
 
9
9
  A Rails Engine used by the [Ruby services team](https://github.com/DEFRA/ruby-services-team) in their digital services.
@@ -21,7 +21,7 @@ Things to note
21
21
 
22
22
  Make sure you already have:
23
23
 
24
- - Ruby 2.4.2
24
+ - Ruby 2.7.1
25
25
  - [Bundler](http://bundler.io/) – for installing Ruby gems
26
26
 
27
27
  ## Mounting the engine
@@ -71,14 +71,38 @@ The project currently mocks the following services.
71
71
 
72
72
  When mounted into an app you can make requests to `/mocks/company/[company number]` to get a response that matches what our apps expect.
73
73
 
74
- This is an important distinction to note. When our apps like the [Waste Exemptions front office](https://github.com/DEFRA/waste-exemptions-front-office) make a real request to Companies House, they get a lot more information back in the JSON reponse. However the only thing they are interested in is the value of `"company_status"`.
74
+ This is an important distinction to note. When our apps like the [Waste Exemptions front office](https://github.com/DEFRA/waste-exemptions-front-office) make a real request to Companies House, they get a lot more information back in the JSON reponse. However the only things they are interested in are the value of `"company_name"`, `"company_status"`, `"company_type"` and `"registered_office"`, .
75
75
 
76
- So rather than maintain a lot of unused JSON data, the mock just returns that bit of the JSON.
76
+ So rather than maintain a lot of unused JSON data, the mock just returns those bits of the JSON.
77
77
 
78
78
  ```bash
79
79
  curl http://localhost:3000/mocks/company/SC123456
80
80
  {
81
- "company_status": "active"
81
+ "company_name": "Acme Industries",
82
+ "company_status": "active",
83
+ "company_type": "ltd",
84
+ "registered_office_address": {
85
+ "address_line_1": "10 Downing St",
86
+ "address_line_2": "Horizon House",
87
+ "locality": "Bristol",
88
+ "postal_code": "BS1 5AH"
89
+ }
90
+ }
91
+ ```
92
+
93
+ Additionally, an Officers endpoint is available at `/mocks/company/[company number]/officers`. This returns a list of partial Officer data, eg:
94
+ ```bash
95
+ curl http://localhost:3000/mocks/company/SC123456/officers
96
+ {
97
+ "items": [
98
+ {
99
+ "name": "APPLE, Alice",
100
+ "officer_role": "director"
101
+ },
102
+ {
103
+ "name": "BANANA, Bob",
104
+ "officer_role": "director"
105
+ },...
82
106
  }
83
107
  ```
84
108
 
@@ -99,6 +123,11 @@ The exceptions to this are the 'special' numbers listed below. Use them if you a
99
123
  - `33333333` will return `"open"`
100
124
  - `22222222` will return `"closed"`
101
125
 
126
+ Additionally, an `"active"` LLP company can be retrieved by using the following registration numbers:
127
+
128
+ - `XX999999`
129
+ - `YY999999`
130
+
102
131
  The list of possible statuses was taken from
103
132
 
104
133
  - [Companies House API](https://developer.companieshouse.gov.uk/api/docs/company/company_number/companyProfile-resource.html)
@@ -122,6 +151,30 @@ This Worldpay mock replicates those 2 interactions with the following urls
122
151
  - `../worldpay/payments-service`
123
152
  - `../worldpay/dispatcher`
124
153
 
154
+ ##### Cancelled payments
155
+
156
+ The engine has the ability to mock a user cancelling a payment when on the Worldpay site. To have the mock return a cancelled payment response just ensure the registration's company name includes the word `cancel` (case doesn't matter).
157
+
158
+ If it does the engine will redirect back to the cancelled url instead of the success url provided, plus set the payment status to `CANCELLED`.
159
+
160
+ This allows us to test how the application handles Worldpay responding with a cancelled payment response.
161
+
162
+ ##### Errored payments
163
+
164
+ The engine has the ability to Worldpay erroring during a payment. To have the mock return an errored payment response just ensure the registration's company name includes the word `error` (case doesn't matter).
165
+
166
+ If it does the engine will redirect back to the error url instead of the success url provided, plus set the payment status to `ERROR`.
167
+
168
+ This allows us to test how the application handles Worldpay responding with an errored payment response.
169
+
170
+ ##### Pending payments
171
+
172
+ The engine has the ability to also mock Worldpay marking a payment as pending. To have the mock return a payment pending response just ensure the registration's company name includes the word `pending` (case doesn't matter).
173
+
174
+ If it does the engine will redirect back to the pending url instead of the success url provided, plus set the payment status to `SENT_FOR_AUTHORISATION`.
175
+
176
+ This allows us to test how the application handles Worldpay responding with a payment pending response.
177
+
125
178
  ##### Refused payments
126
179
 
127
180
  The engine has the ability to also mock Worldpay refusing a payment. To have the mock refuse payment just ensure the registration's company name includes the word `reject` (case doesn't matter).
@@ -6,13 +6,20 @@ module DefraRubyMocks
6
6
  before_action :set_default_response_format
7
7
 
8
8
  def show
9
- @status = CompaniesHouseService.run(params[:id])
9
+ service = CompaniesHouseService.run(params[:id])
10
+
11
+ @company_status = service.company_status
12
+ @company_type = service.company_type
10
13
 
11
14
  respond_to :json
12
15
  rescue NotFoundError
13
16
  render "not_found", status: 404
14
17
  end
15
18
 
19
+ def officers
20
+ respond_to :json
21
+ end
22
+
16
23
  private
17
24
 
18
25
  def set_default_response_format
@@ -10,14 +10,18 @@ module DefraRubyMocks
10
10
 
11
11
  render_payment_response if @values[:request_type] == :payment
12
12
  render_refund_response if @values[:request_type] == :refund
13
- rescue StandardError
13
+ rescue StandardError => e
14
+ Rails.logger.error("MOCKS: Worldpay payments service error: #{e.message}")
14
15
  head 500
15
16
  end
16
17
 
17
18
  def dispatcher
18
19
  @response = WorldpayResponseService.run(
19
20
  success_url: params[:successURL],
20
- failure_url: params[:failureURL]
21
+ failure_url: params[:failureURL],
22
+ pending_url: params[:pendingURL],
23
+ cancel_url: params[:cancelURL],
24
+ error_url: params[:errorURL]
21
25
  )
22
26
 
23
27
  if @response.status == :STUCK
@@ -25,7 +29,8 @@ module DefraRubyMocks
25
29
  else
26
30
  redirect_to @response.url
27
31
  end
28
- rescue StandardError
32
+ rescue StandardError => e
33
+ Rails.logger.error("MOCKS: Worldpay dispatcher error: #{e.message}")
29
34
  head 500
30
35
  end
31
36
 
@@ -2,8 +2,14 @@
2
2
 
3
3
  module DefraRubyMocks
4
4
  class BaseService
5
- def self.run(attrs = nil)
6
- new.run(attrs)
5
+ def self.run(options = nil)
6
+ if options && !options.is_a?(Hash)
7
+ new.run(options)
8
+ elsif options
9
+ new.run(**options)
10
+ else
11
+ new.run
12
+ end
7
13
  end
8
14
  end
9
15
  end
@@ -31,15 +31,22 @@ module DefraRubyMocks
31
31
  }
32
32
  end
33
33
 
34
+ def self.llp_company_numbers
35
+ %w[XX999999 YY999999]
36
+ end
37
+
34
38
  def run(company_number)
35
39
  raise NotFoundError unless valid_company_number?(company_number)
36
40
  raise NotFoundError if company_number == NOT_FOUND
37
41
 
38
- return specials[company_number] if specials.key?(company_number)
42
+ @company_status = specials[company_number] || "active"
43
+ @company_type = llps.include?(company_number) ? "llp" : "ltd"
39
44
 
40
- "active"
45
+ self
41
46
  end
42
47
 
48
+ attr_reader :company_status, :company_type
49
+
43
50
  private
44
51
 
45
52
  def valid_company_number?(company_number)
@@ -50,5 +57,8 @@ module DefraRubyMocks
50
57
  self.class.special_company_numbers
51
58
  end
52
59
 
60
+ def llps
61
+ self.class.llp_company_numbers
62
+ end
53
63
  end
54
64
  end
@@ -3,11 +3,19 @@
3
3
  module DefraRubyMocks
4
4
  class WorldpayResponseService < BaseService
5
5
 
6
- def run(success_url:, failure_url:)
7
- parse_reference(success_url)
6
+ def run(success_url:, failure_url:, pending_url:, cancel_url:, error_url:)
7
+ urls = {
8
+ success: success_url,
9
+ failure: failure_url,
10
+ pending: pending_url,
11
+ cancel: cancel_url,
12
+ error: error_url
13
+ }
14
+
15
+ parse_reference(urls[:success])
8
16
  @resource = WorldpayResourceService.run(reference: @reference)
9
17
 
10
- generate_response(success_url, failure_url)
18
+ generate_response(urls)
11
19
  end
12
20
 
13
21
  private
@@ -59,27 +67,44 @@ module DefraRubyMocks
59
67
  def payment_status
60
68
  return :REFUSED if @resource.company_name.include?("reject")
61
69
  return :STUCK if @resource.company_name.include?("stuck")
70
+ return :SENT_FOR_AUTHORISATION if @resource.company_name.include?("pending")
71
+ return :CANCELLED if @resource.company_name.include?("cancel")
72
+ return :ERROR if @resource.company_name.include?("error")
62
73
 
63
74
  :AUTHORISED
64
75
  end
65
76
 
77
+ def url(payment_status, urls)
78
+ return urls[:failure] if %i[REFUSED STUCK].include?(payment_status)
79
+ return urls[:pending] if payment_status == :SENT_FOR_AUTHORISATION
80
+ return urls[:cancel] if payment_status == :CANCELLED
81
+ return urls[:error] if payment_status == :ERROR
82
+
83
+ urls[:success]
84
+ end
85
+
86
+ # Generate a mac that matches what Worldpay would generate
87
+ #
88
+ # For whatever reason, if the payment is cancelled by the user Worldpay does
89
+ # not include the payment status in the mac it generates. Plus the order of
90
+ # things in the array is important.
66
91
  def generate_mac(status)
67
92
  data = [
68
93
  order_key,
69
94
  order_value,
70
- "GBP",
71
- status,
72
- DefraRubyMocks.configuration.worldpay_mac_secret
95
+ "GBP"
73
96
  ]
97
+ data << status unless status == :CANCELLED
98
+ data << DefraRubyMocks.configuration.worldpay_mac_secret
74
99
 
75
100
  Digest::MD5.hexdigest(data.join).to_s
76
101
  end
77
102
 
78
- def generate_response(success_url, failure_url)
103
+ def generate_response(urls)
79
104
  status = payment_status
80
105
 
81
106
  WorldpayResponse.new(
82
- status == :AUTHORISED ? success_url : failure_url,
107
+ url(status, urls),
83
108
  @url_format == :new ? "?" : "&",
84
109
  order_key,
85
110
  generate_mac(status),
@@ -0,0 +1,26 @@
1
+ // https://developer-specs.company-information.service.gov.uk/companies-house-public-data-api/resources/officerlist
2
+ {
3
+ "items": [
4
+ {
5
+ "name": "APPLE, Alice",
6
+ "officer_role": "director"
7
+ },
8
+ {
9
+ "name": "BANANA, Bob",
10
+ "officer_role": "director"
11
+ },
12
+ {
13
+ "name": "CARROT, Charlie",
14
+ "officer_role": "director",
15
+ "resigned_on": "2020-01-21"
16
+ },
17
+ {
18
+ "name": "DONUT, Dave Dickie",
19
+ "officer_role": "llp-member"
20
+ },
21
+ {
22
+ "name": "ENDIVE, Eve Marie",
23
+ "officer_role": "llp-designated-member"
24
+ }
25
+ ]
26
+ }
@@ -1,3 +1,12 @@
1
+ // https://developer-specs.company-information.service.gov.uk/companies-house-public-data-api/resources/companyprofile
1
2
  {
2
- "company_status": "<%= @status %>"
3
+ "company_name": "Acme Industries",
4
+ "company_status": "<%= @company_status %>",
5
+ "type": "<%= @company_type %>",
6
+ "registered_office_address": {
7
+ "address_line_1": "10 Downing St",
8
+ "address_line_2": "Horizon House",
9
+ "locality": "Bristol",
10
+ "postal_code": "BS1 5AH"
11
+ }
3
12
  }
data/config/routes.rb CHANGED
@@ -6,6 +6,11 @@ DefraRubyMocks::Engine.routes.draw do
6
6
  as: "company",
7
7
  constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
8
8
 
9
+ get "/company/:id/officers",
10
+ to: "company#officers",
11
+ as: "company_officers",
12
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
13
+
9
14
  get "/worldpay/payments-service",
10
15
  to: "worldpay#payments_service",
11
16
  as: "worldpay_payments_service",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DefraRubyMocks
4
- VERSION = "1.4.1"
4
+ VERSION = "2.2.0"
5
5
  end