410
18 | # Gone.
19 | #
20 | # Example URL: /payout_items
21 | # @param options [Hash] parameters as a hash, under a params key.
22 | def list(options = {})
23 | path = '/payout_items'
24 |
25 | options[:retry_failures] = true
26 |
27 | response = make_request(:get, path, options)
28 |
29 | ListResponse.new(
30 | response: response,
31 | unenveloped_body: unenvelope_body(response.body),
32 | resource_class: Resources::PayoutItem
33 | )
34 | end
35 |
36 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically.
37 | #
38 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
39 | # Otherwise they will be the body of the request.
40 | def all(options = {})
41 | Paginator.new(
42 | service: self,
43 | options: options
44 | ).enumerator
45 | end
46 |
47 | private
48 |
49 | # Unenvelope the response of the body using the service's `envelope_key`
50 | #
51 | # @param body [Hash]
52 | def unenvelope_body(body)
53 | body[envelope_key] || body['data']
54 | end
55 |
56 | # return the key which API responses will envelope data under
57 | def envelope_key
58 | 'payout_items'
59 | end
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb:
--------------------------------------------------------------------------------
1 | module GoCardlessPro
2 | module Middlewares
3 | class RaiseGoCardlessErrors < Faraday::Middleware
4 | API_ERROR_STATUSES = 501..599
5 | CLIENT_ERROR_STATUSES = 400..500
6 | API_STATUS_NO_CONTENT = 204
7 |
8 | def on_complete(env)
9 | if !(env.status == API_STATUS_NO_CONTENT || json?(env)) || API_ERROR_STATUSES.include?(env.status)
10 | raise ApiError, generate_error_data(env)
11 | end
12 |
13 | return unless CLIENT_ERROR_STATUSES.include?(env.status)
14 |
15 | json_body ||= JSON.parse(env.body) unless env.body.empty?
16 | error_type = json_body['error']['type']
17 |
18 | error_class = error_class_for_status(env.status) || error_class_for_type(error_type)
19 |
20 | raise(error_class, json_body['error'])
21 | end
22 |
23 | private
24 |
25 | def error_class_for_status(code)
26 | {
27 | 401 => GoCardlessPro::AuthenticationError,
28 | 403 => GoCardlessPro::PermissionError,
29 | 429 => GoCardlessPro::RateLimitError
30 | }.fetch(code, nil)
31 | end
32 |
33 | def error_class_for_type(type)
34 | {
35 | validation_failed: GoCardlessPro::ValidationError,
36 | gocardless: GoCardlessPro::GoCardlessError,
37 | invalid_api_usage: GoCardlessPro::InvalidApiUsageError,
38 | invalid_state: GoCardlessPro::InvalidStateError
39 | }.fetch(type.to_sym)
40 | end
41 |
42 | def generate_error_data(env)
43 | {
44 | 'message' => "Something went wrong with this request\n" \
45 | "code: #{env.status}\n" \
46 | "headers: #{env.response_headers}\n" \
47 | "body: #{env.body}",
48 | 'code' => env.status
49 | }
50 | end
51 |
52 | def json?(env)
53 | content_type = env.response_headers['Content-Type'] ||
54 | env.response_headers['content-type'] || ''
55 |
56 | content_type.include?('application/json')
57 | end
58 | end
59 | end
60 | end
61 |
62 | Faraday::Response.register_middleware raise_gocardless_errors: GoCardlessPro::Middlewares::RaiseGoCardlessErrors
63 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/resources/scheme_identifier.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 |
8 | module GoCardlessPro
9 | # A module containing classes for each of the resources in the GC Api
10 | module Resources
11 | # Represents an instance of a scheme_identifier resource returned from the API
12 |
13 | # This represents a scheme identifier (e.g. a SUN in Bacs or a CID in SEPA).
14 | # Scheme identifiers are used to specify the beneficiary name that appears
15 | # on customers' bank statements.
16 | #
17 | class SchemeIdentifier
18 | attr_reader :address_line1, :address_line2, :address_line3, :can_specify_mandate_reference, :city, :country_code,
19 | :created_at, :currency, :email, :id, :minimum_advance_notice, :name, :phone_number, :postal_code, :reference, :region, :scheme, :status
20 |
21 | # Initialize a scheme_identifier resource instance
22 | # @param object [Hash] an object returned from the API
23 | def initialize(object, response = nil)
24 | @object = object
25 |
26 | @address_line1 = object['address_line1']
27 | @address_line2 = object['address_line2']
28 | @address_line3 = object['address_line3']
29 | @can_specify_mandate_reference = object['can_specify_mandate_reference']
30 | @city = object['city']
31 | @country_code = object['country_code']
32 | @created_at = object['created_at']
33 | @currency = object['currency']
34 | @email = object['email']
35 | @id = object['id']
36 | @minimum_advance_notice = object['minimum_advance_notice']
37 | @name = object['name']
38 | @phone_number = object['phone_number']
39 | @postal_code = object['postal_code']
40 | @reference = object['reference']
41 | @region = object['region']
42 | @scheme = object['scheme']
43 | @status = object['status']
44 | @response = response
45 | end
46 |
47 | def api_response
48 | ApiResponse.new(@response)
49 | end
50 |
51 | # Provides the scheme_identifier resource as a hash of all its readable attributes
52 | def to_h
53 | @object
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/resources/customer.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 |
8 | module GoCardlessPro
9 | # A module containing classes for each of the resources in the GC Api
10 | module Resources
11 | # Represents an instance of a customer resource returned from the API
12 |
13 | # Customer objects hold the contact details for a customer. A customer can
14 | # have several [customer bank
15 | # accounts](#core-endpoints-customer-bank-accounts), which in turn can have
16 | # several Direct Debit [mandates](#core-endpoints-mandates).
17 | class Customer
18 | attr_reader :address_line1, :address_line2, :address_line3, :city, :company_name, :country_code, :created_at,
19 | :danish_identity_number, :email, :family_name, :given_name, :id, :language, :metadata, :phone_number, :postal_code, :region, :swedish_identity_number
20 |
21 | # Initialize a customer resource instance
22 | # @param object [Hash] an object returned from the API
23 | def initialize(object, response = nil)
24 | @object = object
25 |
26 | @address_line1 = object['address_line1']
27 | @address_line2 = object['address_line2']
28 | @address_line3 = object['address_line3']
29 | @city = object['city']
30 | @company_name = object['company_name']
31 | @country_code = object['country_code']
32 | @created_at = object['created_at']
33 | @danish_identity_number = object['danish_identity_number']
34 | @email = object['email']
35 | @family_name = object['family_name']
36 | @given_name = object['given_name']
37 | @id = object['id']
38 | @language = object['language']
39 | @metadata = object['metadata']
40 | @phone_number = object['phone_number']
41 | @postal_code = object['postal_code']
42 | @region = object['region']
43 | @swedish_identity_number = object['swedish_identity_number']
44 | @response = response
45 | end
46 |
47 | def api_response
48 | ApiResponse.new(@response)
49 | end
50 |
51 | # Provides the customer resource as a hash of all its readable attributes
52 | def to_h
53 | @object
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/api_service.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 | require 'base64'
8 |
9 | module GoCardlessPro
10 | # GoCardless API
11 | class ApiService
12 | attr_reader :on_idempotency_conflict
13 |
14 | # Initialize an APIService
15 | #
16 | # @param url [String] the URL to make requests to
17 | # @param key [String] the API Key ID to use
18 | # @param secret [String] the API key secret to use
19 | # @param options [Hash] additional options to use when creating the service
20 | def initialize(url, token, options = {})
21 | @url = url
22 | root_url, @path_prefix = unpack_url(url)
23 | http_adapter = options[:http_adapter] || [:net_http]
24 | connection_options = options.fetch(:connection_options, {})
25 |
26 | @connection = Faraday.new(root_url, connection_options) do |faraday|
27 | faraday.response :raise_gocardless_errors
28 |
29 | faraday.adapter(*http_adapter)
30 | end
31 |
32 | @headers = options[:default_headers] || {}
33 | @headers['Authorization'] = "Bearer #{token}"
34 | @on_idempotency_conflict = options[:on_idempotency_conflict] || :fetch
35 |
36 | return if %i[fetch raise].include?(@on_idempotency_conflict)
37 |
38 | raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
39 | end
40 |
41 | # Make a request to the API
42 | #
43 | # @param method [Symbol] the method to use to make the request
44 | # @param path [String] the URL (without the base domain) to make the request to
45 | # @param options [Hash] the options hash
46 | def make_request(method, path, options = {})
47 | raise ArgumentError, 'options must be a hash' unless options.is_a?(Hash)
48 |
49 | options[:headers] ||= {}
50 | options[:headers] = @headers.merge(options[:headers])
51 | Request.new(@connection, method, @path_prefix + path, options).request
52 | end
53 |
54 | # inspect the API Service
55 | def inspect
56 | url = URI.parse(@url)
57 | url.password = 'REDACTED' unless url.password.nil?
58 | "#Restricted: 17 | # These endpoints are restricted to customers who want to collect their 18 | # merchant's 19 | # verification details and pass them to GoCardless via our API. Please 20 | # [get in 21 | # touch](mailto:help@gocardless.com) if you wish to enable this feature on 22 | # your 23 | # account.
24 | class VerificationDetail 25 | attr_reader :address_line1, :address_line2, :address_line3, :city, :company_number, :description, :directors, 26 | :name, :postal_code 27 | 28 | # Initialize a verification_detail resource instance 29 | # @param object [Hash] an object returned from the API 30 | def initialize(object, response = nil) 31 | @object = object 32 | 33 | @address_line1 = object['address_line1'] 34 | @address_line2 = object['address_line2'] 35 | @address_line3 = object['address_line3'] 36 | @city = object['city'] 37 | @company_number = object['company_number'] 38 | @description = object['description'] 39 | @directors = object['directors'] 40 | @links = object['links'] 41 | @name = object['name'] 42 | @postal_code = object['postal_code'] 43 | @response = response 44 | end 45 | 46 | def api_response 47 | ApiResponse.new(@response) 48 | end 49 | 50 | # Return the links that the resource has 51 | def links 52 | @verification_detail_links ||= Links.new(@links) 53 | end 54 | 55 | # Provides the verification_detail resource as a hash of all its readable attributes 56 | def to_h 57 | @object 58 | end 59 | 60 | class Links 61 | def initialize(links) 62 | @links = links || {} 63 | end 64 | 65 | def creditor 66 | @links['creditor'] 67 | end 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/services/scenario_simulators_service_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Services::ScenarioSimulatorsService do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#run' do 13 | subject(:post_response) { client.scenario_simulators.run(resource_id) } 14 | 15 | let(:resource_id) { 'ABC123' } 16 | 17 | let!(:stub) do 18 | # /scenario_simulators/%v/actions/run 19 | stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id) 20 | stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return( 21 | body: { 22 | 'scenario_simulators' => { 23 | 24 | 'id' => 'id-input' 25 | } 26 | }.to_json, 27 | 28 | headers: response_headers 29 | ) 30 | end 31 | 32 | it 'wraps the response and calls the right endpoint' do 33 | expect(post_response).to be_a(GoCardlessPro::Resources::ScenarioSimulator) 34 | 35 | expect(stub).to have_been_requested 36 | end 37 | 38 | describe 'retry behaviour' do 39 | it "doesn't retry errors" do 40 | stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id) 41 | stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/) 42 | .to_timeout 43 | 44 | expect { post_response }.to raise_error(Faraday::ConnectionFailed) 45 | expect(stub).to have_been_requested 46 | end 47 | end 48 | 49 | context 'when the request needs a body and custom header' do 50 | let(:body) { { foo: 'bar' } } 51 | let(:headers) { { 'Foo' => 'Bar' } } 52 | subject(:post_response) { client.scenario_simulators.run(resource_id, body, headers) } 53 | 54 | let(:resource_id) { 'ABC123' } 55 | 56 | let!(:stub) do 57 | # /scenario_simulators/%v/actions/run 58 | stub_url = '/scenario_simulators/:identity/actions/run'.gsub(':identity', resource_id) 59 | stub_request(:post, /.*api.gocardless.com#{stub_url}/) 60 | .with( 61 | body: { foo: 'bar' }, 62 | headers: { 'Foo' => 'Bar' } 63 | ).to_return( 64 | body: { 65 | 'scenario_simulators' => { 66 | 67 | 'id' => 'id-input' 68 | } 69 | }.to_json, 70 | headers: response_headers 71 | ) 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/bank_authorisation.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a bank_authorisation resource returned from the API 12 | 13 | # Bank Authorisations can be used to authorise Billing Requests. 14 | # Authorisations 15 | # are created against a specific bank, usually the bank that provides the 16 | # payer's 17 | # account. 18 | # 19 | # Creation of Bank Authorisations is only permitted from GoCardless hosted 20 | # UIs 21 | # (see Billing Request Flows) to ensure we meet regulatory requirements for 22 | # checkout flows. 23 | class BankAuthorisation 24 | attr_reader :authorisation_type, :authorised_at, :created_at, :expires_at, :id, :last_visited_at, :qr_code_url, 25 | :redirect_uri, :url 26 | 27 | # Initialize a bank_authorisation resource instance 28 | # @param object [Hash] an object returned from the API 29 | def initialize(object, response = nil) 30 | @object = object 31 | 32 | @authorisation_type = object['authorisation_type'] 33 | @authorised_at = object['authorised_at'] 34 | @created_at = object['created_at'] 35 | @expires_at = object['expires_at'] 36 | @id = object['id'] 37 | @last_visited_at = object['last_visited_at'] 38 | @links = object['links'] 39 | @qr_code_url = object['qr_code_url'] 40 | @redirect_uri = object['redirect_uri'] 41 | @url = object['url'] 42 | @response = response 43 | end 44 | 45 | def api_response 46 | ApiResponse.new(@response) 47 | end 48 | 49 | # Return the links that the resource has 50 | def links 51 | @bank_authorisation_links ||= Links.new(@links) 52 | end 53 | 54 | # Provides the bank_authorisation resource as a hash of all its readable attributes 55 | def to_h 56 | @object 57 | end 58 | 59 | class Links 60 | def initialize(links) 61 | @links = links || {} 62 | end 63 | 64 | def billing_request 65 | @links['billing_request'] 66 | end 67 | 68 | def institution 69 | @links['institution'] 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/payout.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a payout resource returned from the API 12 | 13 | # Payouts represent transfers from GoCardless to a 14 | # [creditor](#core-endpoints-creditors). Each payout contains the funds 15 | # collected from one or many [payments](#core-endpoints-payments). All the 16 | # payments in a payout will have been collected in the same currency. 17 | # Payouts are created automatically after a payment has been successfully 18 | # collected. 19 | class Payout 20 | attr_reader :amount, :arrival_date, :created_at, :currency, :deducted_fees, :fx, :id, :metadata, :payout_type, 21 | :reference, :status, :tax_currency 22 | 23 | # Initialize a payout resource instance 24 | # @param object [Hash] an object returned from the API 25 | def initialize(object, response = nil) 26 | @object = object 27 | 28 | @amount = object['amount'] 29 | @arrival_date = object['arrival_date'] 30 | @created_at = object['created_at'] 31 | @currency = object['currency'] 32 | @deducted_fees = object['deducted_fees'] 33 | @fx = object['fx'] 34 | @id = object['id'] 35 | @links = object['links'] 36 | @metadata = object['metadata'] 37 | @payout_type = object['payout_type'] 38 | @reference = object['reference'] 39 | @status = object['status'] 40 | @tax_currency = object['tax_currency'] 41 | @response = response 42 | end 43 | 44 | def api_response 45 | ApiResponse.new(@response) 46 | end 47 | 48 | # Return the links that the resource has 49 | def links 50 | @payout_links ||= Links.new(@links) 51 | end 52 | 53 | # Provides the payout resource as a hash of all its readable attributes 54 | def to_h 55 | @object 56 | end 57 | 58 | class Links 59 | def initialize(links) 60 | @links = links || {} 61 | end 62 | 63 | def creditor 64 | @links['creditor'] 65 | end 66 | 67 | def creditor_bank_account 68 | @links['creditor_bank_account'] 69 | end 70 | end 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/resources/transferred_mandate_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::TransferredMandate do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#transferred_mandates' do 13 | subject(:get_response) { client.transferred_mandates.transferred_mandates(resource_id) } 14 | 15 | let(:resource_id) { 'ABC123' } 16 | 17 | let!(:stub) do 18 | # /transferred_mandates/%v 19 | stub_url = '/transferred_mandates/:identity'.gsub(':identity', resource_id) 20 | stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return( 21 | body: { 22 | 'transferred_mandates' => { 23 | 24 | 'encrypted_customer_bank_details' => 'encrypted_customer_bank_details-input', 25 | 'encrypted_decryption_key' => 'encrypted_decryption_key-input', 26 | 'links' => 'links-input', 27 | 'public_key_id' => 'public_key_id-input' 28 | } 29 | }.to_json, 30 | 31 | headers: response_headers 32 | ) 33 | end 34 | 35 | it 'wraps the response and calls the right endpoint' do 36 | expect(get_response).to be_a(GoCardlessPro::Resources::TransferredMandate) 37 | 38 | expect(stub).to have_been_requested 39 | end 40 | 41 | context 'when the request needs a body and custom header' do 42 | let(:body) { { foo: 'bar' } } 43 | let(:headers) { { 'Foo' => 'Bar' } } 44 | subject(:get_response) { client.transferred_mandates.transferred_mandates(resource_id, body, headers) } 45 | 46 | let(:resource_id) { 'ABC123' } 47 | 48 | let!(:stub) do 49 | # /transferred_mandates/%v 50 | stub_url = '/transferred_mandates/:identity'.gsub(':identity', resource_id) 51 | stub_request(:get, /.*api.gocardless.com#{stub_url}/) 52 | .with( 53 | body: { foo: 'bar' }, 54 | headers: { 'Foo' => 'Bar' } 55 | ).to_return( 56 | body: { 57 | 'transferred_mandates' => { 58 | 59 | 'encrypted_customer_bank_details' => 'encrypted_customer_bank_details-input', 60 | 'encrypted_decryption_key' => 'encrypted_decryption_key-input', 61 | 'links' => 'links-input', 62 | 'public_key_id' => 'public_key_id-input' 63 | } 64 | }.to_json, 65 | headers: response_headers 66 | ) 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/billing_request_flows_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the BillingRequestFlow endpoints 12 | class BillingRequestFlowsService < BaseService 13 | # Creates a new billing request flow. 14 | # Example URL: /billing_request_flows 15 | # @param options [Hash] parameters as a hash, under a params key. 16 | def create(options = {}) 17 | path = '/billing_request_flows' 18 | 19 | params = options.delete(:params) || {} 20 | options[:params] = {} 21 | options[:params][envelope_key] = params 22 | 23 | options[:retry_failures] = true 24 | 25 | response = make_request(:post, path, options) 26 | 27 | return if response.body.nil? 28 | 29 | Resources::BillingRequestFlow.new(unenvelope_body(response.body), response) 30 | end 31 | 32 | # Returns the flow having generated a fresh session token which can be used to 33 | # power 34 | # integrations that manipulate the flow. 35 | # Example URL: /billing_request_flows/:identity/actions/initialise 36 | # 37 | # @param identity # Unique identifier, beginning with "BRF". 38 | # @param options [Hash] parameters as a hash, under a params key. 39 | def initialise(identity, options = {}) 40 | path = sub_url('/billing_request_flows/:identity/actions/initialise', { 41 | 'identity' => identity 42 | }) 43 | 44 | params = options.delete(:params) || {} 45 | options[:params] = {} 46 | options[:params]['data'] = params 47 | 48 | options[:retry_failures] = false 49 | 50 | response = make_request(:post, path, options) 51 | 52 | return if response.body.nil? 53 | 54 | Resources::BillingRequestFlow.new(unenvelope_body(response.body), response) 55 | end 56 | 57 | private 58 | 59 | # Unenvelope the response of the body using the service's `envelope_key` 60 | # 61 | # @param body [Hash] 62 | def unenvelope_body(body) 63 | body[envelope_key] || body['data'] 64 | end 65 | 66 | # return the key which API responses will envelope data under 67 | def envelope_key 68 | 'billing_request_flows' 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/exports_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the Export endpoints 12 | class ExportsService < BaseService 13 | # Returns a single export. 14 | # Example URL: /exports/:identity 15 | # 16 | # @param identity # Unique identifier, beginning with "EX". 17 | # @param options [Hash] parameters as a hash, under a params key. 18 | def get(identity, options = {}) 19 | path = sub_url('/exports/:identity', { 20 | 'identity' => identity 21 | }) 22 | 23 | options[:retry_failures] = true 24 | 25 | response = make_request(:get, path, options) 26 | 27 | return if response.body.nil? 28 | 29 | Resources::Export.new(unenvelope_body(response.body), response) 30 | end 31 | 32 | # Returns a list of exports which are available for download. 33 | # Example URL: /exports 34 | # @param options [Hash] parameters as a hash, under a params key. 35 | def list(options = {}) 36 | path = '/exports' 37 | 38 | options[:retry_failures] = true 39 | 40 | response = make_request(:get, path, options) 41 | 42 | ListResponse.new( 43 | response: response, 44 | unenveloped_body: unenvelope_body(response.body), 45 | resource_class: Resources::Export 46 | ) 47 | end 48 | 49 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 50 | # 51 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 52 | # Otherwise they will be the body of the request. 53 | def all(options = {}) 54 | Paginator.new( 55 | service: self, 56 | options: options 57 | ).enumerator 58 | end 59 | 60 | private 61 | 62 | # Unenvelope the response of the body using the service's `envelope_key` 63 | # 64 | # @param body [Hash] 65 | def unenvelope_body(body) 66 | body[envelope_key] || body['data'] 67 | end 68 | 69 | # return the key which API responses will envelope data under 70 | def envelope_key 71 | 'exports' 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/events_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the Event endpoints 12 | class EventsService < BaseService 13 | # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your 14 | # events. 15 | # Example URL: /events 16 | # @param options [Hash] parameters as a hash, under a params key. 17 | def list(options = {}) 18 | path = '/events' 19 | 20 | options[:retry_failures] = true 21 | 22 | response = make_request(:get, path, options) 23 | 24 | ListResponse.new( 25 | response: response, 26 | unenveloped_body: unenvelope_body(response.body), 27 | resource_class: Resources::Event 28 | ) 29 | end 30 | 31 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 32 | # 33 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 34 | # Otherwise they will be the body of the request. 35 | def all(options = {}) 36 | Paginator.new( 37 | service: self, 38 | options: options 39 | ).enumerator 40 | end 41 | 42 | # Retrieves the details of a single event. 43 | # Example URL: /events/:identity 44 | # 45 | # @param identity # Unique identifier, beginning with "EV". 46 | # @param options [Hash] parameters as a hash, under a params key. 47 | def get(identity, options = {}) 48 | path = sub_url('/events/:identity', { 49 | 'identity' => identity 50 | }) 51 | 52 | options[:retry_failures] = true 53 | 54 | response = make_request(:get, path, options) 55 | 56 | return if response.body.nil? 57 | 58 | Resources::Event.new(unenvelope_body(response.body), response) 59 | end 60 | 61 | private 62 | 63 | # Unenvelope the response of the body using the service's `envelope_key` 64 | # 65 | # @param body [Hash] 66 | def unenvelope_body(body) 67 | body[envelope_key] || body['data'] 68 | end 69 | 70 | # return the key which API responses will envelope data under 71 | def envelope_key 72 | 'events' 73 | end 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/resources/customer_notification_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::CustomerNotification do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#handle' do 13 | subject(:post_response) { client.customer_notifications.handle(resource_id) } 14 | 15 | let(:resource_id) { 'ABC123' } 16 | 17 | let!(:stub) do 18 | # /customer_notifications/%v/actions/handle 19 | stub_url = '/customer_notifications/:identity/actions/handle'.gsub(':identity', resource_id) 20 | stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return( 21 | body: { 22 | 'customer_notifications' => { 23 | 24 | 'action_taken' => 'action_taken-input', 25 | 'action_taken_at' => 'action_taken_at-input', 26 | 'action_taken_by' => 'action_taken_by-input', 27 | 'id' => 'id-input', 28 | 'links' => 'links-input', 29 | 'type' => 'type-input' 30 | } 31 | }.to_json, 32 | 33 | headers: response_headers 34 | ) 35 | end 36 | 37 | it 'wraps the response and calls the right endpoint' do 38 | expect(post_response).to be_a(GoCardlessPro::Resources::CustomerNotification) 39 | 40 | expect(stub).to have_been_requested 41 | end 42 | 43 | context 'when the request needs a body and custom header' do 44 | let(:body) { { foo: 'bar' } } 45 | let(:headers) { { 'Foo' => 'Bar' } } 46 | subject(:post_response) { client.customer_notifications.handle(resource_id, body, headers) } 47 | 48 | let(:resource_id) { 'ABC123' } 49 | 50 | let!(:stub) do 51 | # /customer_notifications/%v/actions/handle 52 | stub_url = '/customer_notifications/:identity/actions/handle'.gsub(':identity', resource_id) 53 | stub_request(:post, /.*api.gocardless.com#{stub_url}/) 54 | .with( 55 | body: { foo: 'bar' }, 56 | headers: { 'Foo' => 'Bar' } 57 | ).to_return( 58 | body: { 59 | 'customer_notifications' => { 60 | 61 | 'action_taken' => 'action_taken-input', 62 | 'action_taken_at' => 'action_taken_at-input', 63 | 'action_taken_by' => 'action_taken_by-input', 64 | 'id' => 'id-input', 65 | 'links' => 'links-input', 66 | 'type' => 'type-input' 67 | } 68 | }.to_json, 69 | headers: response_headers 70 | ) 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/verification_details_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the VerificationDetail endpoints 12 | class VerificationDetailsService < BaseService 13 | # Creates a new verification detail 14 | # Example URL: /verification_details 15 | # @param options [Hash] parameters as a hash, under a params key. 16 | def create(options = {}) 17 | path = '/verification_details' 18 | 19 | params = options.delete(:params) || {} 20 | options[:params] = {} 21 | options[:params][envelope_key] = params 22 | 23 | options[:retry_failures] = true 24 | 25 | response = make_request(:post, path, options) 26 | 27 | return if response.body.nil? 28 | 29 | Resources::VerificationDetail.new(unenvelope_body(response.body), response) 30 | end 31 | 32 | # Returns a list of verification details belonging to a creditor. 33 | # Example URL: /verification_details 34 | # @param options [Hash] parameters as a hash, under a params key. 35 | def list(options = {}) 36 | path = '/verification_details' 37 | 38 | options[:retry_failures] = true 39 | 40 | response = make_request(:get, path, options) 41 | 42 | ListResponse.new( 43 | response: response, 44 | unenveloped_body: unenvelope_body(response.body), 45 | resource_class: Resources::VerificationDetail 46 | ) 47 | end 48 | 49 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 50 | # 51 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 52 | # Otherwise they will be the body of the request. 53 | def all(options = {}) 54 | Paginator.new( 55 | service: self, 56 | options: options 57 | ).enumerator 58 | end 59 | 60 | private 61 | 62 | # Unenvelope the response of the body using the service's `envelope_key` 63 | # 64 | # @param body [Hash] 65 | def unenvelope_body(body) 66 | body[envelope_key] || body['data'] 67 | end 68 | 69 | # return the key which API responses will envelope data under 70 | def envelope_key 71 | 'verification_details' 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/payout_item.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a payout_item resource returned from the API 12 | 13 | # When we collect a payment on your behalf, we add the money you've 14 | # collected to your 15 | # GoCardless balance, minus any fees paid. Periodically (usually every 16 | # working day), 17 | # we take any positive balance in your GoCardless account, and pay it out to 18 | # your 19 | # nominated bank account. 20 | # 21 | # Other actions in your GoCardless account can also affect your balance. For 22 | # example, 23 | # if a customer charges back a payment, we'll deduct the payment's amount 24 | # from your 25 | # balance, but add any fees you paid for that payment back to your balance. 26 | # 27 | # The Payout Items API allows you to view, on a per-payout basis, the credit 28 | # and debit 29 | # items that make up that payout's amount. Payout items can only be 30 | # retrieved for payouts 31 | # created in the last 6 months. Requests for older payouts will return an 32 | # HTTP status 33 | #410 Gone.
34 | #
35 | class PayoutItem
36 | attr_reader :amount, :taxes, :type
37 |
38 | # Initialize a payout_item resource instance
39 | # @param object [Hash] an object returned from the API
40 | def initialize(object, response = nil)
41 | @object = object
42 |
43 | @amount = object['amount']
44 | @links = object['links']
45 | @taxes = object['taxes']
46 | @type = object['type']
47 | @response = response
48 | end
49 |
50 | def api_response
51 | ApiResponse.new(@response)
52 | end
53 |
54 | # Return the links that the resource has
55 | def links
56 | @payout_item_links ||= Links.new(@links)
57 | end
58 |
59 | # Provides the payout_item resource as a hash of all its readable attributes
60 | def to_h
61 | @object
62 | end
63 |
64 | class Links
65 | def initialize(links)
66 | @links = links || {}
67 | end
68 |
69 | def mandate
70 | @links['mandate']
71 | end
72 |
73 | def payment
74 | @links['payment']
75 | end
76 |
77 | def refund
78 | @links['refund']
79 | end
80 | end
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/services/tax_rates_service.rb:
--------------------------------------------------------------------------------
1 | require_relative './base_service'
2 |
3 | # encoding: utf-8
4 | #
5 | # This client is automatically generated from a template and JSON schema definition.
6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7 | #
8 |
9 | module GoCardlessPro
10 | module Services
11 | # Service for making requests to the TaxRate endpoints
12 | class TaxRatesService < BaseService
13 | # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of all tax
14 | # rates.
15 | # Example URL: /tax_rates
16 | # @param options [Hash] parameters as a hash, under a params key.
17 | def list(options = {})
18 | path = '/tax_rates'
19 |
20 | options[:retry_failures] = true
21 |
22 | response = make_request(:get, path, options)
23 |
24 | ListResponse.new(
25 | response: response,
26 | unenveloped_body: unenvelope_body(response.body),
27 | resource_class: Resources::TaxRate
28 | )
29 | end
30 |
31 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically.
32 | #
33 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
34 | # Otherwise they will be the body of the request.
35 | def all(options = {})
36 | Paginator.new(
37 | service: self,
38 | options: options
39 | ).enumerator
40 | end
41 |
42 | # Retrieves the details of a tax rate.
43 | # Example URL: /tax_rates/:identity
44 | #
45 | # @param identity # The unique identifier created by the jurisdiction, tax type and version
46 | # @param options [Hash] parameters as a hash, under a params key.
47 | def get(identity, options = {})
48 | path = sub_url('/tax_rates/:identity', {
49 | 'identity' => identity
50 | })
51 |
52 | options[:retry_failures] = true
53 |
54 | response = make_request(:get, path, options)
55 |
56 | return if response.body.nil?
57 |
58 | Resources::TaxRate.new(unenvelope_body(response.body), response)
59 | end
60 |
61 | private
62 |
63 | # Unenvelope the response of the body using the service's `envelope_key`
64 | #
65 | # @param body [Hash]
66 | def unenvelope_body(body)
67 | body[envelope_key] || body['data']
68 | end
69 |
70 | # return the key which API responses will envelope data under
71 | def envelope_key
72 | 'tax_rates'
73 | end
74 | end
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/services/bank_authorisations_service.rb:
--------------------------------------------------------------------------------
1 | require_relative './base_service'
2 |
3 | # encoding: utf-8
4 | #
5 | # This client is automatically generated from a template and JSON schema definition.
6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7 | #
8 |
9 | module GoCardlessPro
10 | module Services
11 | # Service for making requests to the BankAuthorisation endpoints
12 | class BankAuthorisationsService < BaseService
13 | # Create a Bank Authorisation.
14 | # Example URL: /bank_authorisations
15 | # @param options [Hash] parameters as a hash, under a params key.
16 | def create(options = {})
17 | path = '/bank_authorisations'
18 |
19 | params = options.delete(:params) || {}
20 | options[:params] = {}
21 | options[:params][envelope_key] = params
22 |
23 | options[:retry_failures] = true
24 |
25 | begin
26 | response = make_request(:post, path, options)
27 |
28 | # Response doesn't raise any errors until #body is called
29 | response.tap(&:body)
30 | rescue InvalidStateError => e
31 | if e.idempotent_creation_conflict?
32 | case @api_service.on_idempotency_conflict
33 | when :raise
34 | raise IdempotencyConflict, e.error
35 | when :fetch
36 | return get(e.conflicting_resource_id)
37 | end
38 | end
39 |
40 | raise e
41 | end
42 |
43 | return if response.body.nil?
44 |
45 | Resources::BankAuthorisation.new(unenvelope_body(response.body), response)
46 | end
47 |
48 | # Get a single bank authorisation.
49 | # Example URL: /bank_authorisations/:identity
50 | #
51 | # @param identity # Unique identifier, beginning with "BAU".
52 | # @param options [Hash] parameters as a hash, under a params key.
53 | def get(identity, options = {})
54 | path = sub_url('/bank_authorisations/:identity', {
55 | 'identity' => identity
56 | })
57 |
58 | options[:retry_failures] = true
59 |
60 | response = make_request(:get, path, options)
61 |
62 | return if response.body.nil?
63 |
64 | Resources::BankAuthorisation.new(unenvelope_body(response.body), response)
65 | end
66 |
67 | private
68 |
69 | # Unenvelope the response of the body using the service's `envelope_key`
70 | #
71 | # @param body [Hash]
72 | def unenvelope_body(body)
73 | body[envelope_key] || body['data']
74 | end
75 |
76 | # return the key which API responses will envelope data under
77 | def envelope_key
78 | 'bank_authorisations'
79 | end
80 | end
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/resources/instalment_schedule.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 |
8 | module GoCardlessPro
9 | # A module containing classes for each of the resources in the GC Api
10 | module Resources
11 | # Represents an instance of a instalment_schedule resource returned from the API
12 |
13 | # Instalment schedules are objects which represent a collection of related
14 | # payments, with the
15 | # intention to collect the `total_amount` specified. The API supports both
16 | # schedule-based
17 | # creation (similar to subscriptions) as well as explicit selection of
18 | # differing payment
19 | # amounts and charge dates.
20 | #
21 | # Unlike subscriptions, the payments are created immediately, so the
22 | # instalment schedule
23 | # cannot be modified once submitted and instead can only be cancelled (which
24 | # will cancel
25 | # any of the payments which have not yet been submitted).
26 | #
27 | # Customers will receive a single notification about the complete schedule
28 | # of collection.
29 | #
30 | class InstalmentSchedule
31 | attr_reader :created_at, :currency, :id, :metadata, :name, :payment_errors, :status, :total_amount
32 |
33 | # Initialize a instalment_schedule resource instance
34 | # @param object [Hash] an object returned from the API
35 | def initialize(object, response = nil)
36 | @object = object
37 |
38 | @created_at = object['created_at']
39 | @currency = object['currency']
40 | @id = object['id']
41 | @links = object['links']
42 | @metadata = object['metadata']
43 | @name = object['name']
44 | @payment_errors = object['payment_errors']
45 | @status = object['status']
46 | @total_amount = object['total_amount']
47 | @response = response
48 | end
49 |
50 | def api_response
51 | ApiResponse.new(@response)
52 | end
53 |
54 | # Return the links that the resource has
55 | def links
56 | @instalment_schedule_links ||= Links.new(@links)
57 | end
58 |
59 | # Provides the instalment_schedule resource as a hash of all its readable attributes
60 | def to_h
61 | @object
62 | end
63 |
64 | class Links
65 | def initialize(links)
66 | @links = links || {}
67 | end
68 |
69 | def customer
70 | @links['customer']
71 | end
72 |
73 | def mandate
74 | @links['mandate']
75 | end
76 |
77 | def payments
78 | @links['payments']
79 | end
80 | end
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/resources/payment.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 |
8 | module GoCardlessPro
9 | # A module containing classes for each of the resources in the GC Api
10 | module Resources
11 | # Represents an instance of a payment resource returned from the API
12 |
13 | # Payment objects represent payments from a
14 | # [customer](#core-endpoints-customers) to a
15 | # [creditor](#core-endpoints-creditors), taken against a Direct Debit
16 | # [mandate](#core-endpoints-mandates).
17 | #
18 | # GoCardless will notify you via a [webhook](#appendix-webhooks) whenever
19 | # the state of a payment changes.
20 | class Payment
21 | attr_reader :amount, :amount_refunded, :charge_date, :created_at, :currency, :description, :faster_ach, :fx, :id,
22 | :metadata, :reference, :retry_if_possible, :status
23 |
24 | # Initialize a payment resource instance
25 | # @param object [Hash] an object returned from the API
26 | def initialize(object, response = nil)
27 | @object = object
28 |
29 | @amount = object['amount']
30 | @amount_refunded = object['amount_refunded']
31 | @charge_date = object['charge_date']
32 | @created_at = object['created_at']
33 | @currency = object['currency']
34 | @description = object['description']
35 | @faster_ach = object['faster_ach']
36 | @fx = object['fx']
37 | @id = object['id']
38 | @links = object['links']
39 | @metadata = object['metadata']
40 | @reference = object['reference']
41 | @retry_if_possible = object['retry_if_possible']
42 | @status = object['status']
43 | @response = response
44 | end
45 |
46 | def api_response
47 | ApiResponse.new(@response)
48 | end
49 |
50 | # Return the links that the resource has
51 | def links
52 | @payment_links ||= Links.new(@links)
53 | end
54 |
55 | # Provides the payment resource as a hash of all its readable attributes
56 | def to_h
57 | @object
58 | end
59 |
60 | class Links
61 | def initialize(links)
62 | @links = links || {}
63 | end
64 |
65 | def creditor
66 | @links['creditor']
67 | end
68 |
69 | def instalment_schedule
70 | @links['instalment_schedule']
71 | end
72 |
73 | def mandate
74 | @links['mandate']
75 | end
76 |
77 | def payout
78 | @links['payout']
79 | end
80 |
81 | def subscription
82 | @links['subscription']
83 | end
84 | end
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/lib/gocardless_pro/resources/customer_notification.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This client is automatically generated from a template and JSON schema definition.
3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
4 | #
5 |
6 | require 'uri'
7 |
8 | module GoCardlessPro
9 | # A module containing classes for each of the resources in the GC Api
10 | module Resources
11 | # Represents an instance of a customer_notification resource returned from the API
12 |
13 | # Customer Notifications represent the notification which is due to be sent
14 | # to a customer
15 | # after an event has happened. The event, the resource and the customer to
16 | # be notified
17 | # are all identified in the `links` property.
18 | #
19 | # Note that these are ephemeral records - once the notification has been
20 | # actioned in some
21 | # way, it is no longer visible using this API.
22 | #
23 | # Restricted: This API is 24 | # currently only available for approved integrators - please get in touch if you would like to 26 | # use this API.
27 | class CustomerNotification 28 | attr_reader :action_taken, :action_taken_at, :action_taken_by, :id, :type 29 | 30 | # Initialize a customer_notification resource instance 31 | # @param object [Hash] an object returned from the API 32 | def initialize(object, response = nil) 33 | @object = object 34 | 35 | @action_taken = object['action_taken'] 36 | @action_taken_at = object['action_taken_at'] 37 | @action_taken_by = object['action_taken_by'] 38 | @id = object['id'] 39 | @links = object['links'] 40 | @type = object['type'] 41 | @response = response 42 | end 43 | 44 | def api_response 45 | ApiResponse.new(@response) 46 | end 47 | 48 | # Return the links that the resource has 49 | def links 50 | @customer_notification_links ||= Links.new(@links) 51 | end 52 | 53 | # Provides the customer_notification resource as a hash of all its readable attributes 54 | def to_h 55 | @object 56 | end 57 | 58 | class Links 59 | def initialize(links) 60 | @links = links || {} 61 | end 62 | 63 | def customer 64 | @links['customer'] 65 | end 66 | 67 | def event 68 | @links['event'] 69 | end 70 | 71 | def mandate 72 | @links['mandate'] 73 | end 74 | 75 | def payment 76 | @links['payment'] 77 | end 78 | 79 | def refund 80 | @links['refund'] 81 | end 82 | 83 | def subscription 84 | @links['subscription'] 85 | end 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/institutions_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the Institution endpoints 12 | class InstitutionsService < BaseService 13 | # Returns a list of supported institutions. 14 | # Example URL: /institutions 15 | # @param options [Hash] parameters as a hash, under a params key. 16 | def list(options = {}) 17 | path = '/institutions' 18 | 19 | options[:retry_failures] = true 20 | 21 | response = make_request(:get, path, options) 22 | 23 | ListResponse.new( 24 | response: response, 25 | unenveloped_body: unenvelope_body(response.body), 26 | resource_class: Resources::Institution 27 | ) 28 | end 29 | 30 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 31 | # 32 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 33 | # Otherwise they will be the body of the request. 34 | def all(options = {}) 35 | Paginator.new( 36 | service: self, 37 | options: options 38 | ).enumerator 39 | end 40 | 41 | # Returns all institutions valid for a Billing Request. 42 | # 43 | # This endpoint is currently supported only for FasterPayments. 44 | # Example URL: /billing_requests/:identity/institutions 45 | # 46 | # @param identity # Unique identifier, beginning with "BRQ". 47 | # @param options [Hash] parameters as a hash, under a params key. 48 | def list_for_billing_request(identity, options = {}) 49 | path = sub_url('/billing_requests/:identity/institutions', { 50 | 'identity' => identity 51 | }) 52 | 53 | options[:retry_failures] = false 54 | 55 | response = make_request(:get, path, options) 56 | 57 | ListResponse.new( 58 | response: response, 59 | unenveloped_body: unenvelope_body(response.body), 60 | resource_class: Resources::Institution 61 | ) 62 | end 63 | 64 | private 65 | 66 | # Unenvelope the response of the body using the service's `envelope_key` 67 | # 68 | # @param body [Hash] 69 | def unenvelope_body(body) 70 | body[envelope_key] || body['data'] 71 | end 72 | 73 | # return the key which API responses will envelope data under 74 | def envelope_key 75 | 'institutions' 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/creditor_bank_account.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a creditor_bank_account resource returned from the API 12 | 13 | # Creditor Bank Accounts hold the bank details of a 14 | # [creditor](#core-endpoints-creditors). These are the bank accounts which 15 | # your [payouts](#core-endpoints-payouts) will be sent to. 16 | # 17 | # Note that creditor bank accounts must be unique, and so you will encounter 18 | # a `bank_account_exists` error if you try to create a duplicate bank 19 | # account. You may wish to handle this by updating the existing record 20 | # instead, the ID of which will be provided as 21 | # `links[creditor_bank_account]` in the error response. 22 | # 23 | #Restricted: This API is not 24 | # available for partner integrations.
25 | class CreditorBankAccount 26 | attr_reader :account_holder_name, :account_number_ending, :account_type, :bank_name, :country_code, :created_at, 27 | :currency, :enabled, :id, :metadata, :verification_status 28 | 29 | # Initialize a creditor_bank_account resource instance 30 | # @param object [Hash] an object returned from the API 31 | def initialize(object, response = nil) 32 | @object = object 33 | 34 | @account_holder_name = object['account_holder_name'] 35 | @account_number_ending = object['account_number_ending'] 36 | @account_type = object['account_type'] 37 | @bank_name = object['bank_name'] 38 | @country_code = object['country_code'] 39 | @created_at = object['created_at'] 40 | @currency = object['currency'] 41 | @enabled = object['enabled'] 42 | @id = object['id'] 43 | @links = object['links'] 44 | @metadata = object['metadata'] 45 | @verification_status = object['verification_status'] 46 | @response = response 47 | end 48 | 49 | def api_response 50 | ApiResponse.new(@response) 51 | end 52 | 53 | # Return the links that the resource has 54 | def links 55 | @creditor_bank_account_links ||= Links.new(@links) 56 | end 57 | 58 | # Provides the creditor_bank_account resource as a hash of all its readable attributes 59 | def to_h 60 | @object 61 | end 62 | 63 | class Links 64 | def initialize(links) 65 | @links = links || {} 66 | end 67 | 68 | def creditor 69 | @links['creditor'] 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/mandate.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a mandate resource returned from the API 12 | 13 | # Mandates represent the Direct Debit mandate with a 14 | # [customer](#core-endpoints-customers). 15 | # 16 | # GoCardless will notify you via a [webhook](#appendix-webhooks) whenever 17 | # the status of a mandate changes. 18 | class Mandate 19 | attr_reader :authorisation_source, :consent_parameters, :consent_type, :created_at, :funds_settlement, :id, 20 | :metadata, :next_possible_charge_date, :next_possible_standard_ach_charge_date, :payments_require_approval, :reference, :scheme, :status, :verified_at 21 | 22 | # Initialize a mandate resource instance 23 | # @param object [Hash] an object returned from the API 24 | def initialize(object, response = nil) 25 | @object = object 26 | 27 | @authorisation_source = object['authorisation_source'] 28 | @consent_parameters = object['consent_parameters'] 29 | @consent_type = object['consent_type'] 30 | @created_at = object['created_at'] 31 | @funds_settlement = object['funds_settlement'] 32 | @id = object['id'] 33 | @links = object['links'] 34 | @metadata = object['metadata'] 35 | @next_possible_charge_date = object['next_possible_charge_date'] 36 | @next_possible_standard_ach_charge_date = object['next_possible_standard_ach_charge_date'] 37 | @payments_require_approval = object['payments_require_approval'] 38 | @reference = object['reference'] 39 | @scheme = object['scheme'] 40 | @status = object['status'] 41 | @verified_at = object['verified_at'] 42 | @response = response 43 | end 44 | 45 | def api_response 46 | ApiResponse.new(@response) 47 | end 48 | 49 | # Return the links that the resource has 50 | def links 51 | @mandate_links ||= Links.new(@links) 52 | end 53 | 54 | # Provides the mandate resource as a hash of all its readable attributes 55 | def to_h 56 | @object 57 | end 58 | 59 | class Links 60 | def initialize(links) 61 | @links = links || {} 62 | end 63 | 64 | def creditor 65 | @links['creditor'] 66 | end 67 | 68 | def customer 69 | @links['customer'] 70 | end 71 | 72 | def customer_bank_account 73 | @links['customer_bank_account'] 74 | end 75 | 76 | def new_mandate 77 | @links['new_mandate'] 78 | end 79 | end 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/services/transferred_mandates_service_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Services::TransferredMandatesService do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#transferred_mandates' do 13 | subject(:get_response) { client.transferred_mandates.transferred_mandates(resource_id) } 14 | 15 | let(:resource_id) { 'ABC123' } 16 | 17 | let!(:stub) do 18 | # /transferred_mandates/%v 19 | stub_url = '/transferred_mandates/:identity'.gsub(':identity', resource_id) 20 | stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return( 21 | body: { 22 | 'transferred_mandates' => { 23 | 24 | 'encrypted_customer_bank_details' => 'encrypted_customer_bank_details-input', 25 | 'encrypted_decryption_key' => 'encrypted_decryption_key-input', 26 | 'links' => 'links-input', 27 | 'public_key_id' => 'public_key_id-input' 28 | } 29 | }.to_json, 30 | 31 | headers: response_headers 32 | ) 33 | end 34 | 35 | it 'wraps the response and calls the right endpoint' do 36 | expect(get_response).to be_a(GoCardlessPro::Resources::TransferredMandate) 37 | 38 | expect(stub).to have_been_requested 39 | end 40 | 41 | describe 'retry behaviour' do 42 | it "doesn't retry errors" do 43 | stub_url = '/transferred_mandates/:identity'.gsub(':identity', resource_id) 44 | stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/) 45 | .to_timeout 46 | 47 | expect { get_response }.to raise_error(Faraday::ConnectionFailed) 48 | expect(stub).to have_been_requested 49 | end 50 | end 51 | 52 | context 'when the request needs a body and custom header' do 53 | let(:body) { { foo: 'bar' } } 54 | let(:headers) { { 'Foo' => 'Bar' } } 55 | subject(:get_response) { client.transferred_mandates.transferred_mandates(resource_id, body, headers) } 56 | 57 | let(:resource_id) { 'ABC123' } 58 | 59 | let!(:stub) do 60 | # /transferred_mandates/%v 61 | stub_url = '/transferred_mandates/:identity'.gsub(':identity', resource_id) 62 | stub_request(:get, /.*api.gocardless.com#{stub_url}/) 63 | .with( 64 | body: { foo: 'bar' }, 65 | headers: { 'Foo' => 'Bar' } 66 | ).to_return( 67 | body: { 68 | 'transferred_mandates' => { 69 | 70 | 'encrypted_customer_bank_details' => 'encrypted_customer_bank_details-input', 71 | 'encrypted_decryption_key' => 'encrypted_decryption_key-input', 72 | 'links' => 'links-input', 73 | 'public_key_id' => 'public_key_id-input' 74 | } 75 | }.to_json, 76 | headers: response_headers 77 | ) 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/billing_request_flow.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a billing_request_flow resource returned from the API 12 | 13 | # Billing Request Flows can be created to enable a payer to authorise a 14 | # payment created for a scheme with strong payer 15 | # authorisation (such as open banking single payments). 16 | class BillingRequestFlow 17 | attr_reader :authorisation_url, :auto_fulfil, :created_at, :customer_details_captured, :exit_uri, :expires_at, 18 | :id, :language, :lock_bank_account, :lock_currency, :lock_customer_details, :prefilled_bank_account, :prefilled_customer, :redirect_uri, :session_token, :show_redirect_buttons, :show_success_redirect_button, :skip_success_screen 19 | 20 | # Initialize a billing_request_flow resource instance 21 | # @param object [Hash] an object returned from the API 22 | def initialize(object, response = nil) 23 | @object = object 24 | 25 | @authorisation_url = object['authorisation_url'] 26 | @auto_fulfil = object['auto_fulfil'] 27 | @created_at = object['created_at'] 28 | @customer_details_captured = object['customer_details_captured'] 29 | @exit_uri = object['exit_uri'] 30 | @expires_at = object['expires_at'] 31 | @id = object['id'] 32 | @language = object['language'] 33 | @links = object['links'] 34 | @lock_bank_account = object['lock_bank_account'] 35 | @lock_currency = object['lock_currency'] 36 | @lock_customer_details = object['lock_customer_details'] 37 | @prefilled_bank_account = object['prefilled_bank_account'] 38 | @prefilled_customer = object['prefilled_customer'] 39 | @redirect_uri = object['redirect_uri'] 40 | @session_token = object['session_token'] 41 | @show_redirect_buttons = object['show_redirect_buttons'] 42 | @show_success_redirect_button = object['show_success_redirect_button'] 43 | @skip_success_screen = object['skip_success_screen'] 44 | @response = response 45 | end 46 | 47 | def api_response 48 | ApiResponse.new(@response) 49 | end 50 | 51 | # Return the links that the resource has 52 | def links 53 | @billing_request_flow_links ||= Links.new(@links) 54 | end 55 | 56 | # Provides the billing_request_flow resource as a hash of all its readable attributes 57 | def to_h 58 | @object 59 | end 60 | 61 | class Links 62 | def initialize(links) 63 | @links = links || {} 64 | end 65 | 66 | def billing_request 67 | @links['billing_request'] 68 | end 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/outbound_payment.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a outbound_payment resource returned from the API 12 | 13 | # Outbound Payments represent payments sent from 14 | # [creditors](#core-endpoints-creditors). 15 | # 16 | # GoCardless will notify you via a [webhook](#appendix-webhooks) when the 17 | # status of the outbound payment [changes](#event-actions-outbound-payment). 18 | # 19 | #Restricted: Outbound 20 | # Payments are currently in Early Access and available only to a limited 21 | # list of organisations. If you are interested in using this feature, please 22 | # stay tuned for our public launch announcement. We are actively testing and 23 | # refining our API to ensure it meets your needs and provides the best 24 | # experience.
25 | class OutboundPayment 26 | attr_reader :amount, :created_at, :currency, :description, :execution_date, :id, :is_withdrawal, :metadata, 27 | :reference, :scheme, :status, :verifications 28 | 29 | # Initialize a outbound_payment resource instance 30 | # @param object [Hash] an object returned from the API 31 | def initialize(object, response = nil) 32 | @object = object 33 | 34 | @amount = object['amount'] 35 | @created_at = object['created_at'] 36 | @currency = object['currency'] 37 | @description = object['description'] 38 | @execution_date = object['execution_date'] 39 | @id = object['id'] 40 | @is_withdrawal = object['is_withdrawal'] 41 | @links = object['links'] 42 | @metadata = object['metadata'] 43 | @reference = object['reference'] 44 | @scheme = object['scheme'] 45 | @status = object['status'] 46 | @verifications = object['verifications'] 47 | @response = response 48 | end 49 | 50 | def api_response 51 | ApiResponse.new(@response) 52 | end 53 | 54 | # Return the links that the resource has 55 | def links 56 | @outbound_payment_links ||= Links.new(@links) 57 | end 58 | 59 | # Provides the outbound_payment resource as a hash of all its readable attributes 60 | def to_h 61 | @object 62 | end 63 | 64 | class Links 65 | def initialize(links) 66 | @links = links || {} 67 | end 68 | 69 | def creditor 70 | @links['creditor'] 71 | end 72 | 73 | def customer 74 | @links['customer'] 75 | end 76 | 77 | def recipient_bank_account 78 | @links['recipient_bank_account'] 79 | end 80 | end 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/customer_bank_account.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a customer_bank_account resource returned from the API 12 | 13 | # Customer Bank Accounts hold the bank details of a 14 | # [customer](#core-endpoints-customers). They always belong to a 15 | # [customer](#core-endpoints-customers), and may be linked to several Direct 16 | # Debit [mandates](#core-endpoints-mandates). 17 | # 18 | # Note that customer bank accounts must be unique, and so you will encounter 19 | # a `bank_account_exists` error if you try to create a duplicate bank 20 | # account. You may wish to handle this by updating the existing record 21 | # instead, the ID of which will be provided as 22 | # `links[customer_bank_account]` in the error response. 23 | # 24 | # _Note:_ To ensure the customer's bank accounts are valid, verify them 25 | # first 26 | # using 27 | # 28 | # [bank_details_lookups](#bank-details-lookups-perform-a-bank-details-lookup), 29 | # before proceeding with creating the accounts 30 | class CustomerBankAccount 31 | attr_reader :account_holder_name, :account_number_ending, :account_type, :bank_account_token, :bank_name, 32 | :country_code, :created_at, :currency, :enabled, :id, :metadata 33 | 34 | # Initialize a customer_bank_account resource instance 35 | # @param object [Hash] an object returned from the API 36 | def initialize(object, response = nil) 37 | @object = object 38 | 39 | @account_holder_name = object['account_holder_name'] 40 | @account_number_ending = object['account_number_ending'] 41 | @account_type = object['account_type'] 42 | @bank_account_token = object['bank_account_token'] 43 | @bank_name = object['bank_name'] 44 | @country_code = object['country_code'] 45 | @created_at = object['created_at'] 46 | @currency = object['currency'] 47 | @enabled = object['enabled'] 48 | @id = object['id'] 49 | @links = object['links'] 50 | @metadata = object['metadata'] 51 | @response = response 52 | end 53 | 54 | def api_response 55 | ApiResponse.new(@response) 56 | end 57 | 58 | # Return the links that the resource has 59 | def links 60 | @customer_bank_account_links ||= Links.new(@links) 61 | end 62 | 63 | # Provides the customer_bank_account resource as a hash of all its readable attributes 64 | def to_h 65 | @object 66 | end 67 | 68 | class Links 69 | def initialize(links) 70 | @links = links || {} 71 | end 72 | 73 | def customer 74 | @links['customer'] 75 | end 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /spec/resources/bank_account_detail_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::BankAccountDetail do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#get' do 13 | let(:id) { 'ID123' } 14 | 15 | subject(:get_response) { client.bank_account_details.get(id) } 16 | 17 | context 'passing in a custom header' do 18 | let!(:stub) do 19 | stub_url = '/bank_account_details/:identity'.gsub(':identity', id) 20 | stub_request(:get, /.*api.gocardless.com#{stub_url}/) 21 | .with(headers: { 'Foo' => 'Bar' }) 22 | .to_return( 23 | body: { 24 | 'bank_account_details' => { 25 | 26 | 'ciphertext' => 'ciphertext-input', 27 | 'encrypted_key' => 'encrypted_key-input', 28 | 'iv' => 'iv-input', 29 | 'protected' => 'protected-input', 30 | 'tag' => 'tag-input' 31 | } 32 | }.to_json, 33 | headers: response_headers 34 | ) 35 | end 36 | 37 | subject(:get_response) do 38 | client.bank_account_details.get(id, headers: { 39 | 'Foo' => 'Bar' 40 | }) 41 | end 42 | 43 | it 'includes the header' do 44 | get_response 45 | expect(stub).to have_been_requested 46 | end 47 | end 48 | 49 | context 'when there is a bank_account_detail to return' do 50 | before do 51 | stub_url = '/bank_account_details/:identity'.gsub(':identity', id) 52 | stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return( 53 | body: { 54 | 'bank_account_details' => { 55 | 56 | 'ciphertext' => 'ciphertext-input', 57 | 'encrypted_key' => 'encrypted_key-input', 58 | 'iv' => 'iv-input', 59 | 'protected' => 'protected-input', 60 | 'tag' => 'tag-input' 61 | } 62 | }.to_json, 63 | headers: response_headers 64 | ) 65 | end 66 | 67 | it 'wraps the response in a resource' do 68 | expect(get_response).to be_a(GoCardlessPro::Resources::BankAccountDetail) 69 | end 70 | end 71 | 72 | context 'when nothing is returned' do 73 | before do 74 | stub_url = '/bank_account_details/:identity'.gsub(':identity', id) 75 | stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return( 76 | body: '', 77 | headers: response_headers 78 | ) 79 | end 80 | 81 | it 'returns nil' do 82 | expect(get_response).to be_nil 83 | end 84 | end 85 | 86 | context "when an ID is specified which can't be included in a valid URI" do 87 | let(:id) { '`' } 88 | 89 | it "doesn't raise an error" do 90 | expect { get_response }.to_not raise_error(/bad URI/) 91 | end 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/bank_details_lookups_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the BankDetailsLookup endpoints 12 | class BankDetailsLookupsService < BaseService 13 | # Performs a bank details lookup. As part of the lookup, a modulus check and 14 | # reachability check are performed. 15 | # 16 | # For UK-based bank accounts, where an account holder name is provided (and an 17 | # account number, a sort code or an iban 18 | # are already present), we verify that the account holder name and bank account 19 | # number match the details held by 20 | # the relevant bank. 21 | # 22 | # If your request returns an [error](#api-usage-errors) or the 23 | # `available_debit_schemes` 24 | # attribute is an empty array, you will not be able to collect payments from the 25 | # specified bank account. GoCardless may be able to collect payments from an 26 | # account 27 | # even if no `bic` is returned. 28 | # 29 | # Bank account details may be supplied using [local 30 | # details](#appendix-local-bank-details) or an IBAN. 31 | # 32 | # _ACH scheme_ For compliance reasons, an extra validation step is done using 33 | # a third-party provider to make sure the customer's bank account can accept 34 | # Direct Debit. If a bank account is discovered to be closed or invalid, the 35 | # customer is requested to adjust the account number/routing number and 36 | # succeed in this check to continue with the flow. 37 | # 38 | # _Note:_ Usage of this endpoint is monitored. If your organisation relies on 39 | # GoCardless for 40 | # modulus or reachability checking but not for payment collection, please get in 41 | # touch. 42 | # Example URL: /bank_details_lookups 43 | # @param options [Hash] parameters as a hash, under a params key. 44 | def create(options = {}) 45 | path = '/bank_details_lookups' 46 | 47 | params = options.delete(:params) || {} 48 | options[:params] = {} 49 | options[:params][envelope_key] = params 50 | 51 | options[:retry_failures] = true 52 | 53 | response = make_request(:post, path, options) 54 | 55 | return if response.body.nil? 56 | 57 | Resources::BankDetailsLookup.new(unenvelope_body(response.body), response) 58 | end 59 | 60 | private 61 | 62 | # Unenvelope the response of the body using the service's `envelope_key` 63 | # 64 | # @param body [Hash] 65 | def unenvelope_body(body) 66 | body[envelope_key] || body['data'] 67 | end 68 | 69 | # return the key which API responses will envelope data under 70 | def envelope_key 71 | 'bank_details_lookups' 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/services/customer_notifications_service_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Services::CustomerNotificationsService do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#handle' do 13 | subject(:post_response) { client.customer_notifications.handle(resource_id) } 14 | 15 | let(:resource_id) { 'ABC123' } 16 | 17 | let!(:stub) do 18 | # /customer_notifications/%v/actions/handle 19 | stub_url = '/customer_notifications/:identity/actions/handle'.gsub(':identity', resource_id) 20 | stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return( 21 | body: { 22 | 'customer_notifications' => { 23 | 24 | 'action_taken' => 'action_taken-input', 25 | 'action_taken_at' => 'action_taken_at-input', 26 | 'action_taken_by' => 'action_taken_by-input', 27 | 'id' => 'id-input', 28 | 'links' => 'links-input', 29 | 'type' => 'type-input' 30 | } 31 | }.to_json, 32 | 33 | headers: response_headers 34 | ) 35 | end 36 | 37 | it 'wraps the response and calls the right endpoint' do 38 | expect(post_response).to be_a(GoCardlessPro::Resources::CustomerNotification) 39 | 40 | expect(stub).to have_been_requested 41 | end 42 | 43 | describe 'retry behaviour' do 44 | it "doesn't retry errors" do 45 | stub_url = '/customer_notifications/:identity/actions/handle'.gsub(':identity', resource_id) 46 | stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/) 47 | .to_timeout 48 | 49 | expect { post_response }.to raise_error(Faraday::ConnectionFailed) 50 | expect(stub).to have_been_requested 51 | end 52 | end 53 | 54 | context 'when the request needs a body and custom header' do 55 | let(:body) { { foo: 'bar' } } 56 | let(:headers) { { 'Foo' => 'Bar' } } 57 | subject(:post_response) { client.customer_notifications.handle(resource_id, body, headers) } 58 | 59 | let(:resource_id) { 'ABC123' } 60 | 61 | let!(:stub) do 62 | # /customer_notifications/%v/actions/handle 63 | stub_url = '/customer_notifications/:identity/actions/handle'.gsub(':identity', resource_id) 64 | stub_request(:post, /.*api.gocardless.com#{stub_url}/) 65 | .with( 66 | body: { foo: 'bar' }, 67 | headers: { 'Foo' => 'Bar' } 68 | ).to_return( 69 | body: { 70 | 'customer_notifications' => { 71 | 72 | 'action_taken' => 'action_taken-input', 73 | 'action_taken_at' => 'action_taken_at-input', 74 | 'action_taken_by' => 'action_taken_by-input', 75 | 'id' => 'id-input', 76 | 'links' => 'links-input', 77 | 'type' => 'type-input' 78 | } 79 | }.to_json, 80 | headers: response_headers 81 | ) 82 | end 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/block.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a block resource returned from the API 12 | 13 | # Blocks are created to prevent certain customer details from being used 14 | # when creating 15 | # mandates. 16 | # 17 | # The details used to create blocks can be exact matches, like a bank 18 | # account or an email, 19 | # or a more generic match such as an email domain or bank name. Please be 20 | # careful when creating 21 | # blocks for more generic matches as this may block legitimate payers from 22 | # using your service. 23 | # 24 | # New block types may be added over time. 25 | # 26 | # A block is in essence a simple rule that is used to match against details 27 | # in a newly 28 | # created mandate. If there is a successful match then the mandate is 29 | # transitioned to a 30 | # "blocked" state. 31 | # 32 | # Please note: 33 | # 34 | # - Payments and subscriptions cannot be created against a mandate in 35 | # blocked state. 36 | # - A mandate can never be transitioned out of the blocked state. 37 | # 38 | # The one exception to this is when blocking a 'bank_name'. This block will 39 | # prevent bank 40 | # accounts from being created for banks that match the given name. To ensure 41 | # we match 42 | # bank names correctly an existing bank account must be used when creating 43 | # this block. Please 44 | # be aware that we cannot always match a bank account to a given bank name. 45 | # 46 | #47 | # This API is currently only available for GoCardless Protect+ integrators 48 | # - please get in touch if you 49 | # would like to use this API. 50 | #
51 | class Block 52 | attr_reader :active, :block_type, :created_at, :id, :reason_description, :reason_type, :resource_reference, 53 | :updated_at 54 | 55 | # Initialize a block resource instance 56 | # @param object [Hash] an object returned from the API 57 | def initialize(object, response = nil) 58 | @object = object 59 | 60 | @active = object['active'] 61 | @block_type = object['block_type'] 62 | @created_at = object['created_at'] 63 | @id = object['id'] 64 | @reason_description = object['reason_description'] 65 | @reason_type = object['reason_type'] 66 | @resource_reference = object['resource_reference'] 67 | @updated_at = object['updated_at'] 68 | @response = response 69 | end 70 | 71 | def api_response 72 | ApiResponse.new(@response) 73 | end 74 | 75 | # Provides the block resource as a hash of all its readable attributes 76 | def to_h 77 | @object 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/mandate_pdfs_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the MandatePdf endpoints 12 | class MandatePdfsService < BaseService 13 | # Generates a PDF mandate and returns its temporary URL. 14 | # 15 | # Customer and bank account details can be left blank (for a blank mandate), 16 | # provided manually, or inferred from the ID of an existing 17 | # [mandate](#core-endpoints-mandates). 18 | # 19 | # By default, we'll generate PDF mandates in English. 20 | # 21 | # To generate a PDF mandate in another language, set the `Accept-Language` 22 | # header when creating the PDF mandate to the relevant [ISO 23 | # 639-1](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code 24 | # supported for the scheme. 25 | # 26 | # | Scheme | Supported languages 27 | # 28 | # | 29 | # | :--------------- | 30 | # :------------------------------------------------------------------------------------------------------------------------------------------- 31 | # | 32 | # | ACH | English (`en`) 33 | # 34 | # | 35 | # | Autogiro | English (`en`), Swedish (`sv`) 36 | # 37 | # | 38 | # | Bacs | English (`en`) 39 | # 40 | # | 41 | # | BECS | English (`en`) 42 | # 43 | # | 44 | # | BECS NZ | English (`en`) 45 | # 46 | # | 47 | # | Betalingsservice | Danish (`da`), English (`en`) 48 | # 49 | # | 50 | # | PAD | English (`en`) 51 | # 52 | # | 53 | # | SEPA Core | Danish (`da`), Dutch (`nl`), English (`en`), French 54 | # (`fr`), German (`de`), Italian (`it`), Portuguese (`pt`), Spanish (`es`), 55 | # Swedish (`sv`) | 56 | # Example URL: /mandate_pdfs 57 | # @param options [Hash] parameters as a hash, under a params key. 58 | def create(options = {}) 59 | path = '/mandate_pdfs' 60 | 61 | params = options.delete(:params) || {} 62 | options[:params] = {} 63 | options[:params][envelope_key] = params 64 | 65 | options[:retry_failures] = true 66 | 67 | response = make_request(:post, path, options) 68 | 69 | return if response.body.nil? 70 | 71 | Resources::MandatePdf.new(unenvelope_body(response.body), response) 72 | end 73 | 74 | private 75 | 76 | # Unenvelope the response of the body using the service's `envelope_key` 77 | # 78 | # @param body [Hash] 79 | def unenvelope_body(body) 80 | body[envelope_key] || body['data'] 81 | end 82 | 83 | # return the key which API responses will envelope data under 84 | def envelope_key 85 | 'mandate_pdfs' 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/gocardless_pro/request.rb: -------------------------------------------------------------------------------- 1 | require 'securerandom' 2 | 3 | module GoCardlessPro 4 | # A class that wraps an API request 5 | class Request 6 | MAX_RETRIES = 3 7 | RETRY_DELAY = 0.5 8 | RETRYABLE_EXCEPTIONS = [Faraday::TimeoutError, 9 | Faraday::ConnectionFailed, 10 | GoCardlessPro::ApiError, 11 | GoCardlessPro::GoCardlessError].freeze 12 | 13 | # Initialize a request class, which makes calls to the API 14 | # @param connection 15 | # @param method [Symbol] the method to make the request with 16 | # @param path [String] the path to make the request to 17 | # @param options [hash] options for the request 18 | # @param headers [hash] headers to send with the request 19 | def initialize(connection, method, path, options) 20 | @connection = connection 21 | @method = method 22 | @path = path 23 | @headers = (options.delete(:headers) || {}).each_with_object({}) do |(k, v), hsh| 24 | hsh[k.to_s] = v 25 | end 26 | @envelope_name = options.delete(:envelope_key) 27 | @retry_failures = options.delete(:retry_failures) { true } 28 | @given_options = options 29 | 30 | @request_body = request_body 31 | 32 | if @request_body.is_a?(Hash) 33 | @request_body = @request_body.to_json 34 | @headers['Content-Type'] ||= 'application/json' 35 | end 36 | 37 | @headers['Idempotency-Key'] ||= SecureRandom.uuid if @method == :post 38 | end 39 | 40 | # Make the request and wrap it in a Response object 41 | def request 42 | if @retry_failures 43 | with_retries { Response.new(make_request) } 44 | else 45 | Response.new(make_request) 46 | end 47 | end 48 | 49 | def with_retries 50 | requests_attempted = 0 51 | total_requests_allowed = MAX_RETRIES 52 | 53 | begin 54 | yield 55 | rescue StandardError => e 56 | requests_attempted += 1 57 | 58 | raise e unless requests_attempted < total_requests_allowed && should_retry?(e) 59 | 60 | sleep(RETRY_DELAY) 61 | retry 62 | end 63 | end 64 | 65 | # Make the API request 66 | def make_request 67 | @connection.send(@method) do |request| 68 | request.url @path 69 | request.body = @request_body 70 | request.params = request_query 71 | request.headers.merge!(@headers) 72 | end 73 | end 74 | 75 | # Fetch the body to send with the request 76 | def request_body 77 | if @method == :get 78 | nil 79 | elsif %i[post put delete].include?(@method) 80 | @given_options.fetch(:params, {}) 81 | else 82 | raise "Unknown request method #{@method}" 83 | end 84 | end 85 | 86 | # Get the query params to send with the request 87 | def request_query 88 | if @method == :get 89 | @given_options.fetch(:params, {}) 90 | else 91 | {} 92 | end 93 | end 94 | 95 | private 96 | 97 | def should_retry?(exception) 98 | RETRYABLE_EXCEPTIONS.include?(exception.class) 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/mandate_import_entries_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the MandateImportEntry endpoints 12 | class MandateImportEntriesService < BaseService 13 | # For an existing [mandate import](#core-endpoints-mandate-imports), this 14 | # endpoint can 15 | # be used to add individual mandates to be imported into GoCardless. 16 | # 17 | # You can add no more than 30,000 rows to a single mandate import. 18 | # If you attempt to go over this limit, the API will return a 19 | # `record_limit_exceeded` error. 20 | # Example URL: /mandate_import_entries 21 | # @param options [Hash] parameters as a hash, under a params key. 22 | def create(options = {}) 23 | path = '/mandate_import_entries' 24 | 25 | params = options.delete(:params) || {} 26 | options[:params] = {} 27 | options[:params][envelope_key] = params 28 | 29 | options[:retry_failures] = true 30 | 31 | response = make_request(:post, path, options) 32 | 33 | return if response.body.nil? 34 | 35 | Resources::MandateImportEntry.new(unenvelope_body(response.body), response) 36 | end 37 | 38 | # For an existing mandate import, this endpoint lists all of the entries 39 | # attached. 40 | # 41 | # After a mandate import has been submitted, you can use this endpoint to 42 | # associate records 43 | # in your system (using the `record_identifier` that you provided when creating 44 | # the 45 | # mandate import). 46 | # 47 | # Example URL: /mandate_import_entries 48 | # @param options [Hash] parameters as a hash, under a params key. 49 | def list(options = {}) 50 | path = '/mandate_import_entries' 51 | 52 | options[:retry_failures] = true 53 | 54 | response = make_request(:get, path, options) 55 | 56 | ListResponse.new( 57 | response: response, 58 | unenveloped_body: unenvelope_body(response.body), 59 | resource_class: Resources::MandateImportEntry 60 | ) 61 | end 62 | 63 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 64 | # 65 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 66 | # Otherwise they will be the body of the request. 67 | def all(options = {}) 68 | Paginator.new( 69 | service: self, 70 | options: options 71 | ).enumerator 72 | end 73 | 74 | private 75 | 76 | # Unenvelope the response of the body using the service's `envelope_key` 77 | # 78 | # @param body [Hash] 79 | def unenvelope_body(body) 80 | body[envelope_key] || body['data'] 81 | end 82 | 83 | # return the key which API responses will envelope data under 84 | def envelope_key 85 | 'mandate_import_entries' 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/resources/payout_item_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::PayoutItem do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#list' do 13 | describe 'with no filters' do 14 | subject(:get_list_response) { client.payout_items.list } 15 | 16 | before do 17 | stub_request(:get, %r{.*api.gocardless.com/payout_items}).to_return( 18 | body: { 19 | 'payout_items' => [{ 20 | 21 | 'amount' => 'amount-input', 22 | 'links' => 'links-input', 23 | 'taxes' => 'taxes-input', 24 | 'type' => 'type-input' 25 | }], 26 | meta: { 27 | cursors: { 28 | before: nil, 29 | after: 'ABC123' 30 | } 31 | } 32 | }.to_json, 33 | headers: response_headers 34 | ) 35 | end 36 | 37 | it 'wraps each item in the resource class' do 38 | expect(get_list_response.records.map { |x| x.class }.uniq.first).to eq(GoCardlessPro::Resources::PayoutItem) 39 | 40 | expect(get_list_response.records.first.amount).to eq('amount-input') 41 | 42 | expect(get_list_response.records.first.taxes).to eq('taxes-input') 43 | 44 | expect(get_list_response.records.first.type).to eq('type-input') 45 | end 46 | 47 | it 'exposes the cursors for before and after' do 48 | expect(get_list_response.before).to eq(nil) 49 | expect(get_list_response.after).to eq('ABC123') 50 | end 51 | 52 | specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') } 53 | end 54 | end 55 | 56 | describe '#all' do 57 | let!(:first_response_stub) do 58 | stub_request(:get, %r{.*api.gocardless.com/payout_items$}).to_return( 59 | body: { 60 | 'payout_items' => [{ 61 | 62 | 'amount' => 'amount-input', 63 | 'links' => 'links-input', 64 | 'taxes' => 'taxes-input', 65 | 'type' => 'type-input' 66 | }], 67 | meta: { 68 | cursors: { after: 'AB345' }, 69 | limit: 1 70 | } 71 | }.to_json, 72 | headers: response_headers 73 | ) 74 | end 75 | 76 | let!(:second_response_stub) do 77 | stub_request(:get, %r{.*api.gocardless.com/payout_items\?after=AB345}).to_return( 78 | body: { 79 | 'payout_items' => [{ 80 | 81 | 'amount' => 'amount-input', 82 | 'links' => 'links-input', 83 | 'taxes' => 'taxes-input', 84 | 'type' => 'type-input' 85 | }], 86 | meta: { 87 | limit: 2, 88 | cursors: {} 89 | } 90 | }.to_json, 91 | headers: response_headers 92 | ) 93 | end 94 | 95 | it 'automatically makes the extra requests' do 96 | expect(client.payout_items.all.to_a.length).to eq(2) 97 | expect(first_response_stub).to have_been_requested 98 | expect(second_response_stub).to have_been_requested 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/billing_request_template.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a billing_request_template resource returned from the API 12 | 13 | # Billing Request Templates are reusable templates that result in 14 | # numerous Billing Requests with similar attributes. They provide 15 | # a no-code solution for generating various types of multi-user payment 16 | # links. 17 | # 18 | # Each template includes a reusable URL that can be embedded in a website 19 | # or shared with customers via email. Every time the URL is opened, 20 | # it generates a new Billing Request. 21 | # 22 | # Billing Request Templates overcome the key limitation of the Billing 23 | # Request: 24 | # a Billing Request cannot be shared among multiple users because it is 25 | # intended 26 | # for single-use and is designed to cater to the unique needs of individual 27 | # customers. 28 | class BillingRequestTemplate 29 | attr_reader :authorisation_url, :created_at, :id, :mandate_request_constraints, :mandate_request_currency, 30 | :mandate_request_description, :mandate_request_metadata, :mandate_request_scheme, :mandate_request_verify, :metadata, :name, :payment_request_amount, :payment_request_currency, :payment_request_description, :payment_request_metadata, :payment_request_scheme, :redirect_uri, :updated_at 31 | 32 | # Initialize a billing_request_template resource instance 33 | # @param object [Hash] an object returned from the API 34 | def initialize(object, response = nil) 35 | @object = object 36 | 37 | @authorisation_url = object['authorisation_url'] 38 | @created_at = object['created_at'] 39 | @id = object['id'] 40 | @mandate_request_constraints = object['mandate_request_constraints'] 41 | @mandate_request_currency = object['mandate_request_currency'] 42 | @mandate_request_description = object['mandate_request_description'] 43 | @mandate_request_metadata = object['mandate_request_metadata'] 44 | @mandate_request_scheme = object['mandate_request_scheme'] 45 | @mandate_request_verify = object['mandate_request_verify'] 46 | @metadata = object['metadata'] 47 | @name = object['name'] 48 | @payment_request_amount = object['payment_request_amount'] 49 | @payment_request_currency = object['payment_request_currency'] 50 | @payment_request_description = object['payment_request_description'] 51 | @payment_request_metadata = object['payment_request_metadata'] 52 | @payment_request_scheme = object['payment_request_scheme'] 53 | @redirect_uri = object['redirect_uri'] 54 | @updated_at = object['updated_at'] 55 | @response = response 56 | end 57 | 58 | def api_response 59 | ApiResponse.new(@response) 60 | end 61 | 62 | # Provides the billing_request_template resource as a hash of all its readable attributes 63 | def to_h 64 | @object 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/resources/logo_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::Logo do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#create' do 13 | subject(:post_create_response) { client.logos.create_for_creditor(params: new_resource) } 14 | context 'with a valid request' do 15 | let(:new_resource) do 16 | { 17 | 18 | 'id' => 'id-input' 19 | } 20 | end 21 | 22 | before do 23 | stub_request(:post, %r{.*api.gocardless.com/branding/logos}) 24 | .with( 25 | body: { 26 | 'logos' => { 27 | 28 | 'id' => 'id-input' 29 | } 30 | } 31 | ) 32 | .to_return( 33 | body: { 34 | 'logos' => 35 | 36 | { 37 | 38 | 'id' => 'id-input' 39 | } 40 | 41 | }.to_json, 42 | headers: response_headers 43 | ) 44 | end 45 | 46 | it 'creates and returns the resource' do 47 | expect(post_create_response).to be_a(GoCardlessPro::Resources::Logo) 48 | end 49 | end 50 | 51 | context 'with a request that returns a validation error' do 52 | let(:new_resource) { {} } 53 | 54 | before do 55 | stub_request(:post, %r{.*api.gocardless.com/branding/logos}).to_return( 56 | body: { 57 | error: { 58 | type: 'validation_failed', 59 | code: 422, 60 | errors: [ 61 | { message: 'test error message', field: 'test_field' } 62 | ] 63 | } 64 | }.to_json, 65 | headers: response_headers, 66 | status: 422 67 | ) 68 | end 69 | 70 | it 'throws the correct error' do 71 | expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError) 72 | end 73 | end 74 | 75 | context 'with a request that returns an idempotent creation conflict error' do 76 | let(:id) { 'ID123' } 77 | 78 | let(:new_resource) do 79 | { 80 | 81 | 'id' => 'id-input' 82 | } 83 | end 84 | 85 | let!(:post_stub) do 86 | stub_request(:post, %r{.*api.gocardless.com/branding/logos}).to_return( 87 | body: { 88 | error: { 89 | type: 'invalid_state', 90 | code: 409, 91 | errors: [ 92 | { 93 | message: 'A resource has already been created with this idempotency key', 94 | reason: 'idempotent_creation_conflict', 95 | links: { 96 | conflicting_resource_id: id 97 | } 98 | } 99 | ] 100 | } 101 | }.to_json, 102 | headers: response_headers, 103 | status: 409 104 | ) 105 | end 106 | 107 | it 'raises an InvalidStateError' do 108 | expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError) 109 | expect(post_stub).to have_been_requested 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/mandate_import_entry.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a mandate_import_entry resource returned from the API 12 | 13 | # Mandate Import Entries are added to a [Mandate 14 | # Import](#core-endpoints-mandate-imports). 15 | # Each entry corresponds to one mandate to be imported into GoCardless. 16 | # 17 | # To import a mandate you will need: 18 | #Restricted: This API is 40 | # currently only available for approved integrators - please get in touch if you would like to 42 | # use this API.
43 | class MandateImportEntry 44 | attr_reader :created_at, :processing_errors, :record_identifier 45 | 46 | # Initialize a mandate_import_entry resource instance 47 | # @param object [Hash] an object returned from the API 48 | def initialize(object, response = nil) 49 | @object = object 50 | 51 | @created_at = object['created_at'] 52 | @links = object['links'] 53 | @processing_errors = object['processing_errors'] 54 | @record_identifier = object['record_identifier'] 55 | @response = response 56 | end 57 | 58 | def api_response 59 | ApiResponse.new(@response) 60 | end 61 | 62 | # Return the links that the resource has 63 | def links 64 | @mandate_import_entry_links ||= Links.new(@links) 65 | end 66 | 67 | # Provides the mandate_import_entry resource as a hash of all its readable attributes 68 | def to_h 69 | @object 70 | end 71 | 72 | class Links 73 | def initialize(links) 74 | @links = links || {} 75 | end 76 | 77 | def customer 78 | @links['customer'] 79 | end 80 | 81 | def customer_bank_account 82 | @links['customer_bank_account'] 83 | end 84 | 85 | def mandate 86 | @links['mandate'] 87 | end 88 | 89 | def mandate_import 90 | @links['mandate_import'] 91 | end 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/resources/payer_theme_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::PayerTheme do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#create' do 13 | subject(:post_create_response) { client.payer_themes.create_for_creditor(params: new_resource) } 14 | context 'with a valid request' do 15 | let(:new_resource) do 16 | { 17 | 18 | 'id' => 'id-input' 19 | } 20 | end 21 | 22 | before do 23 | stub_request(:post, %r{.*api.gocardless.com/branding/payer_themes}) 24 | .with( 25 | body: { 26 | 'payer_themes' => { 27 | 28 | 'id' => 'id-input' 29 | } 30 | } 31 | ) 32 | .to_return( 33 | body: { 34 | 'payer_themes' => 35 | 36 | { 37 | 38 | 'id' => 'id-input' 39 | } 40 | 41 | }.to_json, 42 | headers: response_headers 43 | ) 44 | end 45 | 46 | it 'creates and returns the resource' do 47 | expect(post_create_response).to be_a(GoCardlessPro::Resources::PayerTheme) 48 | end 49 | end 50 | 51 | context 'with a request that returns a validation error' do 52 | let(:new_resource) { {} } 53 | 54 | before do 55 | stub_request(:post, %r{.*api.gocardless.com/branding/payer_themes}).to_return( 56 | body: { 57 | error: { 58 | type: 'validation_failed', 59 | code: 422, 60 | errors: [ 61 | { message: 'test error message', field: 'test_field' } 62 | ] 63 | } 64 | }.to_json, 65 | headers: response_headers, 66 | status: 422 67 | ) 68 | end 69 | 70 | it 'throws the correct error' do 71 | expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError) 72 | end 73 | end 74 | 75 | context 'with a request that returns an idempotent creation conflict error' do 76 | let(:id) { 'ID123' } 77 | 78 | let(:new_resource) do 79 | { 80 | 81 | 'id' => 'id-input' 82 | } 83 | end 84 | 85 | let!(:post_stub) do 86 | stub_request(:post, %r{.*api.gocardless.com/branding/payer_themes}).to_return( 87 | body: { 88 | error: { 89 | type: 'invalid_state', 90 | code: 409, 91 | errors: [ 92 | { 93 | message: 'A resource has already been created with this idempotency key', 94 | reason: 'idempotent_creation_conflict', 95 | links: { 96 | conflicting_resource_id: id 97 | } 98 | } 99 | ] 100 | } 101 | }.to_json, 102 | headers: response_headers, 103 | status: 409 104 | ) 105 | end 106 | 107 | it 'raises an InvalidStateError' do 108 | expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError) 109 | expect(post_stub).to have_been_requested 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /spec/resources/currency_exchange_rate_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::CurrencyExchangeRate do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#list' do 13 | describe 'with no filters' do 14 | subject(:get_list_response) { client.currency_exchange_rates.list } 15 | 16 | before do 17 | stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates}).to_return( 18 | body: { 19 | 'currency_exchange_rates' => [{ 20 | 21 | 'rate' => 'rate-input', 22 | 'source' => 'source-input', 23 | 'target' => 'target-input', 24 | 'time' => 'time-input' 25 | }], 26 | meta: { 27 | cursors: { 28 | before: nil, 29 | after: 'ABC123' 30 | } 31 | } 32 | }.to_json, 33 | headers: response_headers 34 | ) 35 | end 36 | 37 | it 'wraps each item in the resource class' do 38 | expect(get_list_response.records.map do |x| 39 | x.class 40 | end.uniq.first).to eq(GoCardlessPro::Resources::CurrencyExchangeRate) 41 | 42 | expect(get_list_response.records.first.rate).to eq('rate-input') 43 | 44 | expect(get_list_response.records.first.source).to eq('source-input') 45 | 46 | expect(get_list_response.records.first.target).to eq('target-input') 47 | 48 | expect(get_list_response.records.first.time).to eq('time-input') 49 | end 50 | 51 | it 'exposes the cursors for before and after' do 52 | expect(get_list_response.before).to eq(nil) 53 | expect(get_list_response.after).to eq('ABC123') 54 | end 55 | 56 | specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') } 57 | end 58 | end 59 | 60 | describe '#all' do 61 | let!(:first_response_stub) do 62 | stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates$}).to_return( 63 | body: { 64 | 'currency_exchange_rates' => [{ 65 | 66 | 'rate' => 'rate-input', 67 | 'source' => 'source-input', 68 | 'target' => 'target-input', 69 | 'time' => 'time-input' 70 | }], 71 | meta: { 72 | cursors: { after: 'AB345' }, 73 | limit: 1 74 | } 75 | }.to_json, 76 | headers: response_headers 77 | ) 78 | end 79 | 80 | let!(:second_response_stub) do 81 | stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates\?after=AB345}).to_return( 82 | body: { 83 | 'currency_exchange_rates' => [{ 84 | 85 | 'rate' => 'rate-input', 86 | 'source' => 'source-input', 87 | 'target' => 'target-input', 88 | 'time' => 'time-input' 89 | }], 90 | meta: { 91 | limit: 2, 92 | cursors: {} 93 | } 94 | }.to_json, 95 | headers: response_headers 96 | ) 97 | end 98 | 99 | it 'automatically makes the extra requests' do 100 | expect(client.currency_exchange_rates.all.to_a.length).to eq(2) 101 | expect(first_response_stub).to have_been_requested 102 | expect(second_response_stub).to have_been_requested 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /spec/resources/mandate_pdf_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::MandatePdf do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#create' do 13 | subject(:post_create_response) { client.mandate_pdfs.create(params: new_resource) } 14 | context 'with a valid request' do 15 | let(:new_resource) do 16 | { 17 | 18 | 'expires_at' => 'expires_at-input', 19 | 'url' => 'url-input' 20 | } 21 | end 22 | 23 | before do 24 | stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs}) 25 | .with( 26 | body: { 27 | 'mandate_pdfs' => { 28 | 29 | 'expires_at' => 'expires_at-input', 30 | 'url' => 'url-input' 31 | } 32 | } 33 | ) 34 | .to_return( 35 | body: { 36 | 'mandate_pdfs' => 37 | 38 | { 39 | 40 | 'expires_at' => 'expires_at-input', 41 | 'url' => 'url-input' 42 | } 43 | 44 | }.to_json, 45 | headers: response_headers 46 | ) 47 | end 48 | 49 | it 'creates and returns the resource' do 50 | expect(post_create_response).to be_a(GoCardlessPro::Resources::MandatePdf) 51 | end 52 | end 53 | 54 | context 'with a request that returns a validation error' do 55 | let(:new_resource) { {} } 56 | 57 | before do 58 | stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs}).to_return( 59 | body: { 60 | error: { 61 | type: 'validation_failed', 62 | code: 422, 63 | errors: [ 64 | { message: 'test error message', field: 'test_field' } 65 | ] 66 | } 67 | }.to_json, 68 | headers: response_headers, 69 | status: 422 70 | ) 71 | end 72 | 73 | it 'throws the correct error' do 74 | expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError) 75 | end 76 | end 77 | 78 | context 'with a request that returns an idempotent creation conflict error' do 79 | let(:id) { 'ID123' } 80 | 81 | let(:new_resource) do 82 | { 83 | 84 | 'expires_at' => 'expires_at-input', 85 | 'url' => 'url-input' 86 | } 87 | end 88 | 89 | let!(:post_stub) do 90 | stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs}).to_return( 91 | body: { 92 | error: { 93 | type: 'invalid_state', 94 | code: 409, 95 | errors: [ 96 | { 97 | message: 'A resource has already been created with this idempotency key', 98 | reason: 'idempotent_creation_conflict', 99 | links: { 100 | conflicting_resource_id: id 101 | } 102 | } 103 | ] 104 | } 105 | }.to_json, 106 | headers: response_headers, 107 | status: 409 108 | ) 109 | end 110 | 111 | it 'raises an InvalidStateError' do 112 | expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError) 113 | expect(post_stub).to have_been_requested 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/resources/balance_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::Balance do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#list' do 13 | describe 'with no filters' do 14 | subject(:get_list_response) { client.balances.list } 15 | 16 | before do 17 | stub_request(:get, %r{.*api.gocardless.com/balances}).to_return( 18 | body: { 19 | 'balances' => [{ 20 | 21 | 'amount' => 'amount-input', 22 | 'balance_type' => 'balance_type-input', 23 | 'currency' => 'currency-input', 24 | 'last_updated_at' => 'last_updated_at-input', 25 | 'links' => 'links-input' 26 | }], 27 | meta: { 28 | cursors: { 29 | before: nil, 30 | after: 'ABC123' 31 | } 32 | } 33 | }.to_json, 34 | headers: response_headers 35 | ) 36 | end 37 | 38 | it 'wraps each item in the resource class' do 39 | expect(get_list_response.records.map { |x| x.class }.uniq.first).to eq(GoCardlessPro::Resources::Balance) 40 | 41 | expect(get_list_response.records.first.amount).to eq('amount-input') 42 | 43 | expect(get_list_response.records.first.balance_type).to eq('balance_type-input') 44 | 45 | expect(get_list_response.records.first.currency).to eq('currency-input') 46 | 47 | expect(get_list_response.records.first.last_updated_at).to eq('last_updated_at-input') 48 | end 49 | 50 | it 'exposes the cursors for before and after' do 51 | expect(get_list_response.before).to eq(nil) 52 | expect(get_list_response.after).to eq('ABC123') 53 | end 54 | 55 | specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') } 56 | end 57 | end 58 | 59 | describe '#all' do 60 | let!(:first_response_stub) do 61 | stub_request(:get, %r{.*api.gocardless.com/balances$}).to_return( 62 | body: { 63 | 'balances' => [{ 64 | 65 | 'amount' => 'amount-input', 66 | 'balance_type' => 'balance_type-input', 67 | 'currency' => 'currency-input', 68 | 'last_updated_at' => 'last_updated_at-input', 69 | 'links' => 'links-input' 70 | }], 71 | meta: { 72 | cursors: { after: 'AB345' }, 73 | limit: 1 74 | } 75 | }.to_json, 76 | headers: response_headers 77 | ) 78 | end 79 | 80 | let!(:second_response_stub) do 81 | stub_request(:get, %r{.*api.gocardless.com/balances\?after=AB345}).to_return( 82 | body: { 83 | 'balances' => [{ 84 | 85 | 'amount' => 'amount-input', 86 | 'balance_type' => 'balance_type-input', 87 | 'currency' => 'currency-input', 88 | 'last_updated_at' => 'last_updated_at-input', 89 | 'links' => 'links-input' 90 | }], 91 | meta: { 92 | limit: 2, 93 | cursors: {} 94 | } 95 | }.to_json, 96 | headers: response_headers 97 | ) 98 | end 99 | 100 | it 'automatically makes the extra requests' do 101 | expect(client.balances.all.to_a.length).to eq(2) 102 | expect(first_response_stub).to have_been_requested 103 | expect(second_response_stub).to have_been_requested 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/mandate_import.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a mandate_import resource returned from the API 12 | 13 | # Mandate Imports allow you to migrate existing mandates from other 14 | # providers into the 15 | # GoCardless platform. 16 | # 17 | # The process is as follows: 18 | # 19 | # 1. [Create a mandate 20 | # import](#mandate-imports-create-a-new-mandate-import) 21 | # 2. [Add entries](#mandate-import-entries-add-a-mandate-import-entry) to 22 | # the import 23 | # 3. [Submit](#mandate-imports-submit-a-mandate-import) the import 24 | # 4. Wait until a member of the GoCardless team approves the import, at 25 | # which point the mandates will be created 26 | # 5. [Link up the 27 | # mandates](#mandate-import-entries-list-all-mandate-import-entries) in your 28 | # system 29 | # 30 | # When you add entries to your mandate import, they are not turned into 31 | # actual mandates 32 | # until the mandate import is submitted by you via the API, and then 33 | # processed by a member 34 | # of the GoCardless team. When that happens, a mandate will be created for 35 | # each entry in the import. 36 | # 37 | # We will issue a `mandate_created` webhook for each entry, which will be 38 | # the same as the webhooks 39 | # triggered when [ creating a mandate ](#mandates-create-a-mandate) using 40 | # the mandates API. Once these 41 | # webhooks start arriving, any reconciliation can now be accomplished by 42 | # [checking the current status](#mandate-imports-get-a-mandate-import) of 43 | # the mandate import and 44 | # [linking up the mandates to your 45 | # system](#mandate-import-entries-list-all-mandate-import-entries). 46 | # 47 | #Note that all Mandate Imports have an upper limit of 48 | # 30,000 entries, so we recommend you split your import into several smaller 49 | # imports if you're planning to exceed this threshold.
50 | # 51 | #Restricted: This API is 52 | # currently only available for approved integrators - please get in touch if you would like to 54 | # use this API.
55 | class MandateImport 56 | attr_reader :created_at, :id, :scheme, :status 57 | 58 | # Initialize a mandate_import resource instance 59 | # @param object [Hash] an object returned from the API 60 | def initialize(object, response = nil) 61 | @object = object 62 | 63 | @created_at = object['created_at'] 64 | @id = object['id'] 65 | @links = object['links'] 66 | @scheme = object['scheme'] 67 | @status = object['status'] 68 | @response = response 69 | end 70 | 71 | def api_response 72 | ApiResponse.new(@response) 73 | end 74 | 75 | # Return the links that the resource has 76 | def links 77 | @mandate_import_links ||= Links.new(@links) 78 | end 79 | 80 | # Provides the mandate_import resource as a hash of all its readable attributes 81 | def to_h 82 | @object 83 | end 84 | 85 | class Links 86 | def initialize(links) 87 | @links = links || {} 88 | end 89 | 90 | def creditor 91 | @links['creditor'] 92 | end 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/payouts_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the Payout endpoints 12 | class PayoutsService < BaseService 13 | # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your 14 | # payouts. 15 | # Example URL: /payouts 16 | # @param options [Hash] parameters as a hash, under a params key. 17 | def list(options = {}) 18 | path = '/payouts' 19 | 20 | options[:retry_failures] = true 21 | 22 | response = make_request(:get, path, options) 23 | 24 | ListResponse.new( 25 | response: response, 26 | unenveloped_body: unenvelope_body(response.body), 27 | resource_class: Resources::Payout 28 | ) 29 | end 30 | 31 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 32 | # 33 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 34 | # Otherwise they will be the body of the request. 35 | def all(options = {}) 36 | Paginator.new( 37 | service: self, 38 | options: options 39 | ).enumerator 40 | end 41 | 42 | # Retrieves the details of a single payout. For an example of how to reconcile 43 | # the transactions in a payout, see [this 44 | # guide](#events-reconciling-payouts-with-events). 45 | # Example URL: /payouts/:identity 46 | # 47 | # @param identity # Unique identifier, beginning with "PO". 48 | # @param options [Hash] parameters as a hash, under a params key. 49 | def get(identity, options = {}) 50 | path = sub_url('/payouts/:identity', { 51 | 'identity' => identity 52 | }) 53 | 54 | options[:retry_failures] = true 55 | 56 | response = make_request(:get, path, options) 57 | 58 | return if response.body.nil? 59 | 60 | Resources::Payout.new(unenvelope_body(response.body), response) 61 | end 62 | 63 | # Updates a payout object. This accepts only the metadata parameter. 64 | # Example URL: /payouts/:identity 65 | # 66 | # @param identity # Unique identifier, beginning with "PO". 67 | # @param options [Hash] parameters as a hash, under a params key. 68 | def update(identity, options = {}) 69 | path = sub_url('/payouts/:identity', { 70 | 'identity' => identity 71 | }) 72 | 73 | params = options.delete(:params) || {} 74 | options[:params] = {} 75 | options[:params][envelope_key] = params 76 | 77 | options[:retry_failures] = true 78 | 79 | response = make_request(:put, path, options) 80 | 81 | return if response.body.nil? 82 | 83 | Resources::Payout.new(unenvelope_body(response.body), response) 84 | end 85 | 86 | private 87 | 88 | # Unenvelope the response of the body using the service's `envelope_key` 89 | # 90 | # @param body [Hash] 91 | def unenvelope_body(body) 92 | body[envelope_key] || body['data'] 93 | end 94 | 95 | # return the key which API responses will envelope data under 96 | def envelope_key 97 | 'payouts' 98 | end 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /spec/resources/negative_balance_limit_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::NegativeBalanceLimit do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#list' do 13 | describe 'with no filters' do 14 | subject(:get_list_response) { client.negative_balance_limits.list } 15 | 16 | before do 17 | stub_request(:get, %r{.*api.gocardless.com/negative_balance_limits}).to_return( 18 | body: { 19 | 'negative_balance_limits' => [{ 20 | 21 | 'balance_limit' => 'balance_limit-input', 22 | 'created_at' => 'created_at-input', 23 | 'currency' => 'currency-input', 24 | 'id' => 'id-input', 25 | 'links' => 'links-input' 26 | }], 27 | meta: { 28 | cursors: { 29 | before: nil, 30 | after: 'ABC123' 31 | } 32 | } 33 | }.to_json, 34 | headers: response_headers 35 | ) 36 | end 37 | 38 | it 'wraps each item in the resource class' do 39 | expect(get_list_response.records.map do |x| 40 | x.class 41 | end.uniq.first).to eq(GoCardlessPro::Resources::NegativeBalanceLimit) 42 | 43 | expect(get_list_response.records.first.balance_limit).to eq('balance_limit-input') 44 | 45 | expect(get_list_response.records.first.created_at).to eq('created_at-input') 46 | 47 | expect(get_list_response.records.first.currency).to eq('currency-input') 48 | 49 | expect(get_list_response.records.first.id).to eq('id-input') 50 | end 51 | 52 | it 'exposes the cursors for before and after' do 53 | expect(get_list_response.before).to eq(nil) 54 | expect(get_list_response.after).to eq('ABC123') 55 | end 56 | 57 | specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') } 58 | end 59 | end 60 | 61 | describe '#all' do 62 | let!(:first_response_stub) do 63 | stub_request(:get, %r{.*api.gocardless.com/negative_balance_limits$}).to_return( 64 | body: { 65 | 'negative_balance_limits' => [{ 66 | 67 | 'balance_limit' => 'balance_limit-input', 68 | 'created_at' => 'created_at-input', 69 | 'currency' => 'currency-input', 70 | 'id' => 'id-input', 71 | 'links' => 'links-input' 72 | }], 73 | meta: { 74 | cursors: { after: 'AB345' }, 75 | limit: 1 76 | } 77 | }.to_json, 78 | headers: response_headers 79 | ) 80 | end 81 | 82 | let!(:second_response_stub) do 83 | stub_request(:get, %r{.*api.gocardless.com/negative_balance_limits\?after=AB345}).to_return( 84 | body: { 85 | 'negative_balance_limits' => [{ 86 | 87 | 'balance_limit' => 'balance_limit-input', 88 | 'created_at' => 'created_at-input', 89 | 'currency' => 'currency-input', 90 | 'id' => 'id-input', 91 | 'links' => 'links-input' 92 | }], 93 | meta: { 94 | limit: 2, 95 | cursors: {} 96 | } 97 | }.to_json, 98 | headers: response_headers 99 | ) 100 | end 101 | 102 | it 'automatically makes the extra requests' do 103 | expect(client.negative_balance_limits.all.to_a.length).to eq(2) 104 | expect(first_response_stub).to have_been_requested 105 | expect(second_response_stub).to have_been_requested 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /spec/resources/billing_request_with_action_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::BillingRequestWithAction do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#create' do 13 | subject(:post_create_response) { client.billing_request_with_actions.create_with_actions(params: new_resource) } 14 | context 'with a valid request' do 15 | let(:new_resource) do 16 | { 17 | 18 | 'bank_authorisations' => 'bank_authorisations-input', 19 | 'billing_requests' => 'billing_requests-input' 20 | } 21 | end 22 | 23 | before do 24 | stub_request(:post, %r{.*api.gocardless.com/billing_requests/create_with_actions}) 25 | .with( 26 | body: { 27 | 'billing_request_with_actions' => { 28 | 29 | 'bank_authorisations' => 'bank_authorisations-input', 30 | 'billing_requests' => 'billing_requests-input' 31 | } 32 | } 33 | ) 34 | .to_return( 35 | body: { 36 | 'billing_request_with_actions' => 37 | 38 | { 39 | 40 | 'bank_authorisations' => 'bank_authorisations-input', 41 | 'billing_requests' => 'billing_requests-input' 42 | } 43 | 44 | }.to_json, 45 | headers: response_headers 46 | ) 47 | end 48 | 49 | it 'creates and returns the resource' do 50 | expect(post_create_response).to be_a(GoCardlessPro::Resources::BillingRequestWithAction) 51 | end 52 | end 53 | 54 | context 'with a request that returns a validation error' do 55 | let(:new_resource) { {} } 56 | 57 | before do 58 | stub_request(:post, %r{.*api.gocardless.com/billing_requests/create_with_actions}).to_return( 59 | body: { 60 | error: { 61 | type: 'validation_failed', 62 | code: 422, 63 | errors: [ 64 | { message: 'test error message', field: 'test_field' } 65 | ] 66 | } 67 | }.to_json, 68 | headers: response_headers, 69 | status: 422 70 | ) 71 | end 72 | 73 | it 'throws the correct error' do 74 | expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError) 75 | end 76 | end 77 | 78 | context 'with a request that returns an idempotent creation conflict error' do 79 | let(:id) { 'ID123' } 80 | 81 | let(:new_resource) do 82 | { 83 | 84 | 'bank_authorisations' => 'bank_authorisations-input', 85 | 'billing_requests' => 'billing_requests-input' 86 | } 87 | end 88 | 89 | let!(:post_stub) do 90 | stub_request(:post, %r{.*api.gocardless.com/billing_requests/create_with_actions}).to_return( 91 | body: { 92 | error: { 93 | type: 'invalid_state', 94 | code: 409, 95 | errors: [ 96 | { 97 | message: 'A resource has already been created with this idempotency key', 98 | reason: 'idempotent_creation_conflict', 99 | links: { 100 | conflicting_resource_id: id 101 | } 102 | } 103 | ] 104 | } 105 | }.to_json, 106 | headers: response_headers, 107 | status: 409 108 | ) 109 | end 110 | 111 | it 'raises an InvalidStateError' do 112 | expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError) 113 | expect(post_stub).to have_been_requested 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/resources/bank_details_lookup_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe GoCardlessPro::Resources::BankDetailsLookup do 4 | let(:client) do 5 | GoCardlessPro::Client.new( 6 | access_token: 'SECRET_TOKEN' 7 | ) 8 | end 9 | 10 | let(:response_headers) { { 'Content-Type' => 'application/json' } } 11 | 12 | describe '#create' do 13 | subject(:post_create_response) { client.bank_details_lookups.create(params: new_resource) } 14 | context 'with a valid request' do 15 | let(:new_resource) do 16 | { 17 | 18 | 'available_debit_schemes' => 'available_debit_schemes-input', 19 | 'bank_name' => 'bank_name-input', 20 | 'bic' => 'bic-input' 21 | } 22 | end 23 | 24 | before do 25 | stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups}) 26 | .with( 27 | body: { 28 | 'bank_details_lookups' => { 29 | 30 | 'available_debit_schemes' => 'available_debit_schemes-input', 31 | 'bank_name' => 'bank_name-input', 32 | 'bic' => 'bic-input' 33 | } 34 | } 35 | ) 36 | .to_return( 37 | body: { 38 | 'bank_details_lookups' => 39 | 40 | { 41 | 42 | 'available_debit_schemes' => 'available_debit_schemes-input', 43 | 'bank_name' => 'bank_name-input', 44 | 'bic' => 'bic-input' 45 | } 46 | 47 | }.to_json, 48 | headers: response_headers 49 | ) 50 | end 51 | 52 | it 'creates and returns the resource' do 53 | expect(post_create_response).to be_a(GoCardlessPro::Resources::BankDetailsLookup) 54 | end 55 | end 56 | 57 | context 'with a request that returns a validation error' do 58 | let(:new_resource) { {} } 59 | 60 | before do 61 | stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups}).to_return( 62 | body: { 63 | error: { 64 | type: 'validation_failed', 65 | code: 422, 66 | errors: [ 67 | { message: 'test error message', field: 'test_field' } 68 | ] 69 | } 70 | }.to_json, 71 | headers: response_headers, 72 | status: 422 73 | ) 74 | end 75 | 76 | it 'throws the correct error' do 77 | expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError) 78 | end 79 | end 80 | 81 | context 'with a request that returns an idempotent creation conflict error' do 82 | let(:id) { 'ID123' } 83 | 84 | let(:new_resource) do 85 | { 86 | 87 | 'available_debit_schemes' => 'available_debit_schemes-input', 88 | 'bank_name' => 'bank_name-input', 89 | 'bic' => 'bic-input' 90 | } 91 | end 92 | 93 | let!(:post_stub) do 94 | stub_request(:post, %r{.*api.gocardless.com/bank_details_lookups}).to_return( 95 | body: { 96 | error: { 97 | type: 'invalid_state', 98 | code: 409, 99 | errors: [ 100 | { 101 | message: 'A resource has already been created with this idempotency key', 102 | reason: 'idempotent_creation_conflict', 103 | links: { 104 | conflicting_resource_id: id 105 | } 106 | } 107 | ] 108 | } 109 | }.to_json, 110 | headers: response_headers, 111 | status: 409 112 | ) 113 | end 114 | 115 | it 'raises an InvalidStateError' do 116 | expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError) 117 | expect(post_stub).to have_been_requested 118 | end 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /lib/gocardless_pro/services/webhooks_service.rb: -------------------------------------------------------------------------------- 1 | require_relative './base_service' 2 | 3 | # encoding: utf-8 4 | # 5 | # This client is automatically generated from a template and JSON schema definition. 6 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 7 | # 8 | 9 | module GoCardlessPro 10 | module Services 11 | # Service for making requests to the Webhook endpoints 12 | class WebhooksService < BaseService 13 | # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your 14 | # webhooks. 15 | # Example URL: /webhooks 16 | # @param options [Hash] parameters as a hash, under a params key. 17 | def list(options = {}) 18 | path = '/webhooks' 19 | 20 | options[:retry_failures] = true 21 | 22 | response = make_request(:get, path, options) 23 | 24 | ListResponse.new( 25 | response: response, 26 | unenveloped_body: unenvelope_body(response.body), 27 | resource_class: Resources::Webhook 28 | ) 29 | end 30 | 31 | # Get a lazily enumerated list of all the items returned. This is similar to the `list` method but will paginate for you automatically. 32 | # 33 | # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters. 34 | # Otherwise they will be the body of the request. 35 | def all(options = {}) 36 | Paginator.new( 37 | service: self, 38 | options: options 39 | ).enumerator 40 | end 41 | 42 | # Retrieves the details of an existing webhook. 43 | # Example URL: /webhooks/:identity 44 | # 45 | # @param identity # Unique identifier, beginning with "WB". 46 | # @param options [Hash] parameters as a hash, under a params key. 47 | def get(identity, options = {}) 48 | path = sub_url('/webhooks/:identity', { 49 | 'identity' => identity 50 | }) 51 | 52 | options[:retry_failures] = true 53 | 54 | response = make_request(:get, path, options) 55 | 56 | return if response.body.nil? 57 | 58 | Resources::Webhook.new(unenvelope_body(response.body), response) 59 | end 60 | 61 | # Requests for a previous webhook to be sent again 62 | # Example URL: /webhooks/:identity/actions/retry 63 | # 64 | # @param identity # Unique identifier, beginning with "WB". 65 | # @param options [Hash] parameters as a hash, under a params key. 66 | def retry(identity, options = {}) 67 | path = sub_url('/webhooks/:identity/actions/retry', { 68 | 'identity' => identity 69 | }) 70 | 71 | params = options.delete(:params) || {} 72 | options[:params] = {} 73 | options[:params]['data'] = params 74 | 75 | options[:retry_failures] = false 76 | 77 | begin 78 | response = make_request(:post, path, options) 79 | 80 | # Response doesn't raise any errors until #body is called 81 | response.tap(&:body) 82 | rescue InvalidStateError => e 83 | if e.idempotent_creation_conflict? 84 | case @api_service.on_idempotency_conflict 85 | when :raise 86 | raise IdempotencyConflict, e.error 87 | when :fetch 88 | return get(e.conflicting_resource_id) 89 | end 90 | end 91 | 92 | raise e 93 | end 94 | 95 | return if response.body.nil? 96 | 97 | Resources::Webhook.new(unenvelope_body(response.body), response) 98 | end 99 | 100 | private 101 | 102 | # Unenvelope the response of the body using the service's `envelope_key` 103 | # 104 | # @param body [Hash] 105 | def unenvelope_body(body) 106 | body[envelope_key] || body['data'] 107 | end 108 | 109 | # return the key which API responses will envelope data under 110 | def envelope_key 111 | 'webhooks' 112 | end 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/creditor.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a creditor resource returned from the API 12 | 13 | # Each [payment](#core-endpoints-payments) taken through the API is linked 14 | # to a "creditor", to whom the payment is then paid out. In most cases your 15 | # organisation will have a single "creditor", but the API also supports 16 | # collecting payments on behalf of others. 17 | # 18 | # Currently, for Anti Money Laundering reasons, any creditors you add must 19 | # be directly related to your organisation. 20 | class Creditor 21 | attr_reader :address_line1, :address_line2, :address_line3, :bank_reference_prefix, :can_create_refunds, :city, 22 | :country_code, :created_at, :creditor_type, :custom_payment_pages_enabled, :fx_payout_currency, :id, :logo_url, :mandate_imports_enabled, :merchant_responsible_for_notifications, :name, :postal_code, :region, :scheme_identifiers, :verification_status 23 | 24 | # Initialize a creditor resource instance 25 | # @param object [Hash] an object returned from the API 26 | def initialize(object, response = nil) 27 | @object = object 28 | 29 | @address_line1 = object['address_line1'] 30 | @address_line2 = object['address_line2'] 31 | @address_line3 = object['address_line3'] 32 | @bank_reference_prefix = object['bank_reference_prefix'] 33 | @can_create_refunds = object['can_create_refunds'] 34 | @city = object['city'] 35 | @country_code = object['country_code'] 36 | @created_at = object['created_at'] 37 | @creditor_type = object['creditor_type'] 38 | @custom_payment_pages_enabled = object['custom_payment_pages_enabled'] 39 | @fx_payout_currency = object['fx_payout_currency'] 40 | @id = object['id'] 41 | @links = object['links'] 42 | @logo_url = object['logo_url'] 43 | @mandate_imports_enabled = object['mandate_imports_enabled'] 44 | @merchant_responsible_for_notifications = object['merchant_responsible_for_notifications'] 45 | @name = object['name'] 46 | @postal_code = object['postal_code'] 47 | @region = object['region'] 48 | @scheme_identifiers = object['scheme_identifiers'] 49 | @verification_status = object['verification_status'] 50 | @response = response 51 | end 52 | 53 | def api_response 54 | ApiResponse.new(@response) 55 | end 56 | 57 | # Return the links that the resource has 58 | def links 59 | @creditor_links ||= Links.new(@links) 60 | end 61 | 62 | # Provides the creditor resource as a hash of all its readable attributes 63 | def to_h 64 | @object 65 | end 66 | 67 | class Links 68 | def initialize(links) 69 | @links = links || {} 70 | end 71 | 72 | def default_aud_payout_account 73 | @links['default_aud_payout_account'] 74 | end 75 | 76 | def default_cad_payout_account 77 | @links['default_cad_payout_account'] 78 | end 79 | 80 | def default_dkk_payout_account 81 | @links['default_dkk_payout_account'] 82 | end 83 | 84 | def default_eur_payout_account 85 | @links['default_eur_payout_account'] 86 | end 87 | 88 | def default_gbp_payout_account 89 | @links['default_gbp_payout_account'] 90 | end 91 | 92 | def default_nzd_payout_account 93 | @links['default_nzd_payout_account'] 94 | end 95 | 96 | def default_sek_payout_account 97 | @links['default_sek_payout_account'] 98 | end 99 | 100 | def default_usd_payout_account 101 | @links['default_usd_payout_account'] 102 | end 103 | end 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/gocardless_pro/resources/event.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This client is automatically generated from a template and JSON schema definition. 3 | # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing. 4 | # 5 | 6 | require 'uri' 7 | 8 | module GoCardlessPro 9 | # A module containing classes for each of the resources in the GC Api 10 | module Resources 11 | # Represents an instance of a event resource returned from the API 12 | 13 | # Events are stored for all webhooks. An event refers to a resource which 14 | # has been updated, for example a payment which has been collected, or a 15 | # mandate which has been transferred. Event creation is an asynchronous 16 | # process, so it can take some time between an action occurring and its 17 | # corresponding event getting included in API responses. See 18 | # [here](#event-actions) for a complete list of event types. 19 | class Event 20 | attr_reader :action, :created_at, :customer_notifications, :details, :id, :metadata, :resource_metadata, 21 | :resource_type 22 | 23 | # Initialize a event resource instance 24 | # @param object [Hash] an object returned from the API 25 | def initialize(object, response = nil) 26 | @object = object 27 | 28 | @action = object['action'] 29 | @created_at = object['created_at'] 30 | @customer_notifications = object['customer_notifications'] 31 | @details = object['details'] 32 | @id = object['id'] 33 | @links = object['links'] 34 | @metadata = object['metadata'] 35 | @resource_metadata = object['resource_metadata'] 36 | @resource_type = object['resource_type'] 37 | @response = response 38 | end 39 | 40 | def api_response 41 | ApiResponse.new(@response) 42 | end 43 | 44 | # Return the links that the resource has 45 | def links 46 | @event_links ||= Links.new(@links) 47 | end 48 | 49 | # Provides the event resource as a hash of all its readable attributes 50 | def to_h 51 | @object 52 | end 53 | 54 | class Links 55 | def initialize(links) 56 | @links = links || {} 57 | end 58 | 59 | def bank_authorisation 60 | @links['bank_authorisation'] 61 | end 62 | 63 | def billing_request 64 | @links['billing_request'] 65 | end 66 | 67 | def billing_request_flow 68 | @links['billing_request_flow'] 69 | end 70 | 71 | def creditor 72 | @links['creditor'] 73 | end 74 | 75 | def customer 76 | @links['customer'] 77 | end 78 | 79 | def customer_bank_account 80 | @links['customer_bank_account'] 81 | end 82 | 83 | def instalment_schedule 84 | @links['instalment_schedule'] 85 | end 86 | 87 | def mandate 88 | @links['mandate'] 89 | end 90 | 91 | def mandate_request_mandate 92 | @links['mandate_request_mandate'] 93 | end 94 | 95 | def new_customer_bank_account 96 | @links['new_customer_bank_account'] 97 | end 98 | 99 | def new_mandate 100 | @links['new_mandate'] 101 | end 102 | 103 | def organisation 104 | @links['organisation'] 105 | end 106 | 107 | def parent_event 108 | @links['parent_event'] 109 | end 110 | 111 | def payer_authorisation 112 | @links['payer_authorisation'] 113 | end 114 | 115 | def payment 116 | @links['payment'] 117 | end 118 | 119 | def payment_request_payment 120 | @links['payment_request_payment'] 121 | end 122 | 123 | def payout 124 | @links['payout'] 125 | end 126 | 127 | def previous_customer_bank_account 128 | @links['previous_customer_bank_account'] 129 | end 130 | 131 | def refund 132 | @links['refund'] 133 | end 134 | 135 | def scheme_identifier 136 | @links['scheme_identifier'] 137 | end 138 | 139 | def subscription 140 | @links['subscription'] 141 | end 142 | end 143 | end 144 | end 145 | end 146 | --------------------------------------------------------------------------------