starling-ruby 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +8 -0
- data/.gitignore +1 -0
- data/.reek +27 -0
- data/.rubocop.yml +6 -4
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +37 -2
- data/README.md +102 -17
- data/bin/console +2 -6
- data/lib/starling.rb +40 -7
- data/lib/starling/api_service.rb +45 -37
- data/lib/starling/client.rb +165 -6
- data/lib/starling/errors/api_error.rb +35 -2
- data/lib/starling/errors/base_error.rb +6 -24
- data/lib/starling/middlewares/raise_starling_errors.rb +11 -10
- data/lib/starling/request.rb +17 -19
- data/lib/starling/resources/account_balance_resource.rb +14 -6
- data/lib/starling/resources/account_resource.rb +10 -0
- data/lib/starling/resources/address_resource.rb +26 -0
- data/lib/starling/resources/addresses_resource.rb +18 -0
- data/lib/starling/resources/base_resource.rb +34 -9
- data/lib/starling/resources/card_resource.rb +46 -0
- data/lib/starling/resources/contact_account_resource.rb +31 -0
- data/lib/starling/resources/contact_resource.rb +16 -0
- data/lib/starling/resources/customer_resource.rb +36 -0
- data/lib/starling/resources/direct_debit_mandate_resource.rb +43 -0
- data/lib/starling/resources/direct_debit_transaction_resource.rb +54 -0
- data/lib/starling/resources/inbound_faster_payments_transaction_resource.rb +56 -0
- data/lib/starling/resources/mastercard_transaction_resource.rb +73 -0
- data/lib/starling/resources/me_resource.rb +26 -0
- data/lib/starling/resources/merchant_location_resource.rb +33 -0
- data/lib/starling/resources/merchant_resource.rb +34 -0
- data/lib/starling/resources/outbound_faster_payments_transaction_resource.rb +56 -0
- data/lib/starling/resources/payment_resource.rb +78 -0
- data/lib/starling/resources/transaction_resource.rb +42 -0
- data/lib/starling/services/account_balance_service.rb +11 -2
- data/lib/starling/services/account_service.rb +16 -3
- data/lib/starling/services/addresses_service.rb +26 -0
- data/lib/starling/services/base_service.rb +22 -1
- data/lib/starling/services/card_service.rb +26 -0
- data/lib/starling/services/contact_accounts_service.rb +54 -0
- data/lib/starling/services/contacts_service.rb +73 -0
- data/lib/starling/services/customer_service.rb +25 -0
- data/lib/starling/services/direct_debit_mandates_service.rb +61 -0
- data/lib/starling/services/direct_debit_transactions_service.rb +46 -0
- data/lib/starling/services/inbound_faster_payments_transactions_service.rb +46 -0
- data/lib/starling/services/mastercard_transactions_service.rb +30 -0
- data/lib/starling/services/me_service.rb +26 -0
- data/lib/starling/services/merchant_locations_service.rb +34 -0
- data/lib/starling/services/merchants_service.rb +26 -0
- data/lib/starling/services/outbound_faster_payments_transactions_service.rb +46 -0
- data/lib/starling/services/payments_service.rb +30 -0
- data/lib/starling/services/transactions_service.rb +44 -0
- data/lib/starling/utils.rb +30 -0
- data/lib/starling/version.rb +1 -1
- data/starling-ruby.gemspec +2 -0
- metadata +63 -2
@@ -0,0 +1,26 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a response returned from the Who Am I (Me) API
|
4
|
+
class MeResource < BaseResource
|
5
|
+
# @return [String] the Starling internal ID of the user
|
6
|
+
def customer_uid
|
7
|
+
parsed_data['customerUid']
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [true, false] whether the user is authenticated
|
11
|
+
def authenticated
|
12
|
+
parsed_data['authenticated']
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Integer, Fixnum] the time until the user's access token expires
|
16
|
+
def expires_in_seconds
|
17
|
+
parsed_data['expiresInSeconds']
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array<String>] the scopes of the user's access token
|
21
|
+
def scopes
|
22
|
+
parsed_data['scopes']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a Merchant Location returned from the Merchant Locations API
|
4
|
+
class MerchantLocationResource < BaseResource
|
5
|
+
# @return [String] the Starling internal ID of the merchant
|
6
|
+
def merchant_uid
|
7
|
+
parsed_data['merchantUid']
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String] the Starling internal ID of the merchant location
|
11
|
+
def merchant_location_uid
|
12
|
+
parsed_data['merchantLocationUid']
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String] the name of the merchant
|
16
|
+
def merchant_name
|
17
|
+
parsed_data['merchantName']
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String] the name of the merchant location
|
21
|
+
def location_name
|
22
|
+
parsed_data['locationName']
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Integer, Fixnum] the MasterCard merchant category code - see
|
26
|
+
# {https://www.mastercard.us/content/dam/mccom/en-us/docments/rules/quick-reference-booklet-me-nov_2015.pdf here}
|
27
|
+
# for details
|
28
|
+
def mastercard_merchant_category_code
|
29
|
+
parsed_data['mastercardMerchantCategoryCode']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a Merchant returned from the Merchants API
|
4
|
+
class MerchantResource < BaseResource
|
5
|
+
# @return [String] the Starling internal ID of the merchant
|
6
|
+
def merchant_uid
|
7
|
+
parsed_data['merchantUid']
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String] the name of the merchant
|
11
|
+
def name
|
12
|
+
parsed_data['name']
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String, nil] the website address of the merchant, or nil if this is not
|
16
|
+
# known
|
17
|
+
def website
|
18
|
+
parsed_data['website']
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String, nil] the phone number of the merchant, or nil if this is not
|
22
|
+
# known
|
23
|
+
def phone_number
|
24
|
+
parsed_data['phoneNumber']
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String, nil] the Twitter username of the merchant, prefixed with "@", or
|
28
|
+
# nil if this is not known
|
29
|
+
def twitter_username
|
30
|
+
parsed_data['twitterUsername']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a Transaction returned from the Transactions Faster
|
4
|
+
# Payments Out API
|
5
|
+
class OutboundFasterPaymentsTransactionResource < BaseResource
|
6
|
+
# @return [String] the Starling internal ID of the transaction
|
7
|
+
def id
|
8
|
+
parsed_data['id']
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String] the currency of the transaction (e.g. "GBP" or "UAH")
|
12
|
+
def currency
|
13
|
+
parsed_data['currency']
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Float] the amount of the transaction
|
17
|
+
def amount
|
18
|
+
present_float(parsed_data['amount'])
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Symbol] the direction of the transaction (e.g. `:outbound`)
|
22
|
+
def direction
|
23
|
+
present_enum(parsed_data['direction'])
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Time] the date and time when the transaction was recorded
|
27
|
+
def created
|
28
|
+
present_datetime(parsed_data['created'])
|
29
|
+
end
|
30
|
+
alias created_at created
|
31
|
+
|
32
|
+
# @return [String] the narrative of the transaction
|
33
|
+
def narrative
|
34
|
+
parsed_data['narrative']
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Symbol] the source of the transaction (e.g. `:master_card`)
|
38
|
+
def source
|
39
|
+
present_enum(parsed_data['source'])
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String, nil] the Starling internal ID of the contact who the payment was
|
43
|
+
# sent to, or nil if they are not one of the user's contacts
|
44
|
+
def receiving_contact_id
|
45
|
+
parsed_data['receivingContactId']
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String, nil] the Starling internal ID of the contact account the payment
|
49
|
+
# was sent to, or nil if they are not one of the user's
|
50
|
+
# contacts
|
51
|
+
def receiving_contact_account_id
|
52
|
+
parsed_data['receivingContactAccountId']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a Payment returned from the Payment API
|
4
|
+
class PaymentResource < BaseResource
|
5
|
+
# @return [String] the Starling internal ID of the payment
|
6
|
+
def payment_order_id
|
7
|
+
parsed_data['paymentOrderId']
|
8
|
+
end
|
9
|
+
alias id payment_order_id
|
10
|
+
|
11
|
+
# @return [String] the currency of the payment
|
12
|
+
def currency
|
13
|
+
parsed_data['currency']
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Float] the amount of the payment
|
17
|
+
def amount
|
18
|
+
present_float(parsed_data['amount'])
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String] the reference of the payment
|
22
|
+
def reference
|
23
|
+
parsed_data['reference']
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [String] the Starling internal ID of the contact account the payment
|
27
|
+
# is/was sent to
|
28
|
+
def receiving_contact_account_id
|
29
|
+
parsed_data['receivingContactAccountId']
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] the name of the recipient of the payment
|
33
|
+
def recipient_name
|
34
|
+
parsed_data['recipientName']
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [true, false] where the payment is immediate or scheduled for the future
|
38
|
+
def immediate
|
39
|
+
parsed_data['immediate']
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a Hash describing the recurrence behaviour of the payment, or nil if the
|
43
|
+
# payment is not recurring. The values in the Hash will be parsed directly from
|
44
|
+
# JSON (e.g. dates will appear as strings).
|
45
|
+
#
|
46
|
+
# TODO: Consider replacing this with its own resource
|
47
|
+
#
|
48
|
+
# @return [Hash, nil] a Hash describing the recurrence behaviour of the payment,
|
49
|
+
# with values parsed directly from JSON, or nil if the payment
|
50
|
+
# is not recurring
|
51
|
+
def recurrence_rule
|
52
|
+
parsed_data['recurrenceRule']
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Date] the start date of the payment
|
56
|
+
def start_date
|
57
|
+
present_date(parsed_data['startDate'])
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Date] the date of the next payment in the series
|
61
|
+
def next_date
|
62
|
+
present_date(parsed_data['nextDate'])
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Time, nil] the time when the payment was cancelled, or nil if it has not
|
66
|
+
# been cancelled
|
67
|
+
def cancelled_at
|
68
|
+
present_datetime(parsed_data['cancelledAt'])
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Symbol] the type of the payment (e.g. `:standing_order`) (these values
|
72
|
+
# do not seem to be accurate!)
|
73
|
+
def payment_type
|
74
|
+
present_enum(parsed_data['paymentType'])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Starling
|
2
|
+
module Resources
|
3
|
+
# A resource representing a Transaction returned from the Transactions API
|
4
|
+
class TransactionResource < BaseResource
|
5
|
+
# @return [String] the Starling internal ID of the transaction
|
6
|
+
def id
|
7
|
+
parsed_data['id']
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String] the currency of the transaction (e.g. "GBP" or "UAH")
|
11
|
+
def currency
|
12
|
+
parsed_data['currency']
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Float] the amount of the transaction
|
16
|
+
def amount
|
17
|
+
present_float(parsed_data['amount'])
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Symbol] the direction of the transaction (e.g. `:outbound`)
|
21
|
+
def direction
|
22
|
+
present_enum(parsed_data['direction'])
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Time] the date and time when the transaction was recorded
|
26
|
+
def created
|
27
|
+
present_datetime(parsed_data['created'])
|
28
|
+
end
|
29
|
+
alias created_at created
|
30
|
+
|
31
|
+
# @return [String] the narrative of the transaction
|
32
|
+
def narrative
|
33
|
+
parsed_data['narrative']
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Symbol] the source of the transaction (e.g. `:master_card`)
|
37
|
+
def source
|
38
|
+
present_enum(parsed_data['source'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module Starling
|
2
2
|
module Services
|
3
|
+
# A service for accessing the Account API's Get Balance endpoint
|
3
4
|
class AccountBalanceService < BaseService
|
4
|
-
|
5
|
-
|
5
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
6
|
+
# included in the URL as a query string
|
7
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
8
|
+
# top of the headers set at the {Client} level
|
9
|
+
# @return [Resources::AccountBalanceResource]
|
10
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
11
|
+
# was unsuccessful
|
12
|
+
def get(params: {}, headers: {})
|
13
|
+
response = api_service.make_request(:get, '/accounts/balance', params: params,
|
14
|
+
headers: headers)
|
6
15
|
resource.new(response: response)
|
7
16
|
end
|
8
17
|
|
@@ -1,12 +1,25 @@
|
|
1
1
|
module Starling
|
2
2
|
module Services
|
3
|
+
# A service for accessing the Account API's Get Account endpoint
|
3
4
|
class AccountService < BaseService
|
4
|
-
|
5
|
-
|
5
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
6
|
+
# included in the URL as a query string
|
7
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
8
|
+
# top of the headers set at the {Client} level
|
9
|
+
# @return [Resources::AccountResource]
|
10
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
11
|
+
# was unsuccessful
|
12
|
+
def get(params: {}, headers: {})
|
13
|
+
response = api_service.make_request(:get, '/accounts', params: params,
|
14
|
+
headers: headers)
|
15
|
+
|
16
|
+
resource.new(response: response)
|
6
17
|
end
|
7
18
|
|
19
|
+
# @return [Services::AccountBalanceService] a configured service for accessing the
|
20
|
+
# Account Balance API
|
8
21
|
def balance
|
9
|
-
Services::AccountBalanceService.new(
|
22
|
+
Services::AccountBalanceService.new(api_service)
|
10
23
|
end
|
11
24
|
|
12
25
|
private
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Starling
|
2
|
+
module Services
|
3
|
+
# A service for accessing the Address API
|
4
|
+
class AddressesService < BaseService
|
5
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
6
|
+
# included in the URL as a query string
|
7
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
8
|
+
# top of the headers set at the {Client} level
|
9
|
+
# @return [Resources::AddressesResource]
|
10
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
11
|
+
# was unsuccessful
|
12
|
+
def get(params: {}, headers: {})
|
13
|
+
response = api_service.make_request(:get, '/addresses', params: params,
|
14
|
+
headers: headers)
|
15
|
+
|
16
|
+
resource.new(response: response)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resource
|
22
|
+
Resources::AddressesResource
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -2,20 +2,41 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Starling
|
4
4
|
module Services
|
5
|
+
# A basic implementation of a service for interacting with the
|
6
|
+
# Starling Bank API, mapping HTTP request to endpoints to Ruby methods
|
5
7
|
class BaseService
|
8
|
+
# @param api_service [ApiService]
|
6
9
|
def initialize(api_service)
|
7
10
|
@api_service = api_service
|
8
11
|
end
|
9
12
|
|
10
13
|
private
|
11
14
|
|
12
|
-
|
15
|
+
attr_reader :api_service
|
16
|
+
|
17
|
+
def build_collection_from_key(response, key:, resource:)
|
18
|
+
JSON.parse(response.body)
|
19
|
+
.fetch(key)
|
20
|
+
.map do |parsed_data|
|
21
|
+
resource.new(parsed_data: parsed_data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_collection_from_embedded_key(response, key:, resource:)
|
13
26
|
JSON.parse(response.body)
|
14
27
|
.fetch('_embedded', {})
|
15
28
|
.fetch(key, []).map do |parsed_data|
|
16
29
|
resource.new(parsed_data: parsed_data)
|
17
30
|
end
|
18
31
|
end
|
32
|
+
|
33
|
+
def options_without_params(options)
|
34
|
+
options.reject { |key, _| key == :params }
|
35
|
+
end
|
36
|
+
|
37
|
+
def convert_location_header_to_relative_path(location)
|
38
|
+
location.gsub(%r{^/api/v1}, '')
|
39
|
+
end
|
19
40
|
end
|
20
41
|
end
|
21
42
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Starling
|
2
|
+
module Services
|
3
|
+
# A service for accessing the Card API
|
4
|
+
class CardService < BaseService
|
5
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
6
|
+
# included in the URL as a query string
|
7
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
8
|
+
# top of the headers set at the {Client} level
|
9
|
+
# @return [Resources::CardResource]
|
10
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
11
|
+
# was unsuccessful
|
12
|
+
def get(params: {}, headers: {})
|
13
|
+
response = api_service.make_request(:get, '/cards', params: params,
|
14
|
+
headers: headers)
|
15
|
+
|
16
|
+
resource.new(response: response)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resource
|
22
|
+
Resources::CardResource
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Starling
|
2
|
+
module Services
|
3
|
+
# A service for accessing the Contact API's Get Contact Accounts and Get Contact
|
4
|
+
# endpoints
|
5
|
+
class ContactAccountsService < BaseService
|
6
|
+
# @param contact_id [String] The Starling internal ID of the contact the contact
|
7
|
+
# account belongs to
|
8
|
+
# @param contact_account_id [String] The Starling internal ID of the contact
|
9
|
+
# account
|
10
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
11
|
+
# included in the URL as a query string
|
12
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
13
|
+
# top of the headers set at the {Client} level
|
14
|
+
# @return [Resources::ContactAccountResource]
|
15
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
16
|
+
# was unsuccessful
|
17
|
+
def get(contact_id, contact_account_id, params: {}, headers: {})
|
18
|
+
response = api_service.make_request(
|
19
|
+
:get,
|
20
|
+
"/contacts/#{contact_id}/accounts/#{contact_account_id}",
|
21
|
+
params: params,
|
22
|
+
headers: headers
|
23
|
+
)
|
24
|
+
|
25
|
+
resource.new(response: response)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param contact_id [String] The Starling internal ID of the contact
|
29
|
+
# @param params [Hash] Parameters which will be included in the HTTP request,
|
30
|
+
# included in the URL as a query string
|
31
|
+
# @param headers [Hash] Headers which be included in the HTTP request, merged on
|
32
|
+
# top of the headers set at the {Client} level
|
33
|
+
# @return [Array<Resources::ContactAccountResource>]
|
34
|
+
# @raise [Errors::ApiError] if the HTTP request returns a status indicating that it
|
35
|
+
# was unsuccessful
|
36
|
+
def list(contact_id, params: {}, headers: {})
|
37
|
+
response = api_service.make_request(
|
38
|
+
:get,
|
39
|
+
"/contacts/#{contact_id}/accounts",
|
40
|
+
params: params,
|
41
|
+
headers: headers
|
42
|
+
)
|
43
|
+
|
44
|
+
build_collection_from_key(response, key: 'contactAccounts', resource: resource)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def resource
|
50
|
+
Resources::ContactAccountResource
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|