unit-ruby 0.1.0 → 0.1.3
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/.github/workflows/ruby.yml +32 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/LICENSE.txt +1 -1
- data/bin/console +1 -1
- data/lib/unit-ruby/application_form.rb +8 -4
- data/lib/unit-ruby/atm_location.rb +2 -2
- data/lib/unit-ruby/deposit_account.rb +5 -5
- data/lib/unit-ruby/individual_application.rb +27 -27
- data/lib/unit-ruby/individual_customer.rb +5 -5
- data/lib/unit-ruby/individual_debit_card.rb +5 -5
- data/lib/unit-ruby/institution.rb +2 -2
- data/lib/unit-ruby/pin_status.rb +13 -0
- data/lib/unit-ruby/statement.rb +31 -0
- data/lib/unit-ruby/transaction.rb +13 -0
- data/lib/unit-ruby/types/application_form_settings_override.rb +1 -1
- data/lib/unit-ruby/types/date.rb +2 -0
- data/lib/unit-ruby/types/date_time.rb +1 -1
- data/lib/unit-ruby/util/api_resource.rb +127 -130
- data/lib/unit-ruby/util/connection.rb +50 -52
- data/lib/unit-ruby/util/error.rb +8 -10
- data/lib/unit-ruby/util/resource_operations.rb +56 -58
- data/lib/unit-ruby/util/schema.rb +12 -10
- data/lib/unit-ruby/version.rb +1 -1
- data/lib/unit-ruby.rb +4 -2
- data/unit-ruby.gemspec +2 -2
- metadata +9 -3
- data/lib/unit-ruby/types/decimal.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28b28032ddbe1492ec95f1d4c5cea1564d846a3f93896c777e2c6440b185a55a
|
4
|
+
data.tar.gz: 5bb4f8338d3fdef99579a9b5f197b3516ac775e817163925167d05359f490f5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b1cd24b58f9732e3f9ec0b9bc17f099d168dca9f05de60c8caa7082c387ef3d50a8363af85afe8cf0b39cfcd25af433058d2020eb38bcf586c21ea4bac23ef2
|
7
|
+
data.tar.gz: 13d02249eb4a6f90bf059861c2b3890d2b4b48294ce89557818633b148ea5da584a92cf6dffb5627400c063475d2877ea5e932ab2c78d03d92a70e95014249e4
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ main ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ main ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
31
|
+
- name: Run tests
|
32
|
+
run: bundle exec rake
|
data/Gemfile.lock
CHANGED
data/LICENSE.txt
CHANGED
data/bin/console
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
module Unit
|
2
|
-
class ApplicationForm <
|
2
|
+
class ApplicationForm < APIResource
|
3
3
|
path '/application-forms'
|
4
4
|
|
5
5
|
attribute :tags, Types::Hash # Optional
|
6
6
|
attribute :allowed_application_types, Types::Array # Optional. Array of Individual, Business or SoleProprietorship.
|
7
7
|
attribute :applicant_details, Types::ApplicationFormPrefill # Optional. Add data that is already known about the end-customer to be auto populated on the form.
|
8
8
|
attribute :settings_override, Types::ApplicationFormSettingsOverride # Optional. Override disclosure URLs that were defined in the application form settings.
|
9
|
-
attribute :stage, Types::String
|
10
|
-
attribute :url, Types::String
|
11
9
|
|
12
|
-
|
10
|
+
attribute :stage, Types::String, readonly: true
|
11
|
+
attribute :url, Types::String, readonly: true
|
12
|
+
|
13
|
+
belongs_to :application, class_name: 'Unit::IndividualApplication'
|
14
|
+
|
15
|
+
include ResourceOperations::Create
|
16
|
+
include ResourceOperations::Find
|
13
17
|
end
|
14
18
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Unit
|
2
|
-
class AtmLocation <
|
2
|
+
class AtmLocation < APIResource
|
3
3
|
path '/atm-locations'
|
4
4
|
attribute :network, Types::String
|
5
5
|
attribute :address, Types::Address
|
@@ -9,7 +9,7 @@ module Unit
|
|
9
9
|
attribute :accept_deposits, Types::Boolean
|
10
10
|
attribute :surcharge_free, Types::Boolean
|
11
11
|
|
12
|
-
include
|
12
|
+
include ResourceOperations::List
|
13
13
|
|
14
14
|
def self.list_by_coordinates(latitude:, longitude:, search_radius:)
|
15
15
|
list(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Unit
|
2
|
-
class DepositAccount <
|
2
|
+
class DepositAccount < APIResource
|
3
3
|
path '/accounts'
|
4
4
|
|
5
5
|
attribute :deposit_product, Types::String # The name of the deposit product
|
@@ -20,9 +20,9 @@ module Unit
|
|
20
20
|
|
21
21
|
belongs_to :customer, class_name: 'Unit::IndividualCustomer'
|
22
22
|
|
23
|
-
include
|
24
|
-
include
|
25
|
-
include
|
26
|
-
include
|
23
|
+
include ResourceOperations::List
|
24
|
+
include ResourceOperations::Create
|
25
|
+
include ResourceOperations::Save
|
26
|
+
include ResourceOperations::Find
|
27
27
|
end
|
28
28
|
end
|
@@ -1,33 +1,33 @@
|
|
1
1
|
module Unit
|
2
|
-
|
3
|
-
|
2
|
+
class IndividualApplication < APIResource
|
3
|
+
path '/applications'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
5
|
+
attribute :ssn, Types::String # SSN (or ITIN) of the individual (numbers only). Either an SSN or a passport number is required.
|
6
|
+
attribute :passport, Types::String # Passport number of the individual. Either an SSN or a passport number is required.
|
7
|
+
attribute :nationality, Types::String # Required on if a passport is used as the main ID. Two letters representing the individual nationality. (e.g. "US").
|
8
|
+
attribute :full_name, Types::FullName # Full name of the individual.
|
9
|
+
attribute :date_of_birth, Types::Date # RFC3339 Date only (e.g. "2001-08-15").
|
10
|
+
attribute :address, Types::Address # Address of the individual.
|
11
|
+
attribute :phone, Types::Phone # Phone number of the individual.
|
12
|
+
attribute :email, Types::String # Email address of the individual.
|
13
|
+
attribute :ip, Types::String # Optional. IP address of the end-customer creating the application. Both IPv4 and IPv6 formats are supported. Highly recommended as a fraud prevention measure, if the information is available when submitting the application.
|
14
|
+
attribute :sole_proprietorship, Types::Boolean # Optional. Default: false. Indicates whether the individual is a sole proprietor.
|
15
|
+
attribute :ein, Types::String # Optional. If the individual is a sole proprietor who has an Employer Identification Number, specify it here. Not all sole proprietors have an EIN, so this attribute is optional, even when soleProprietorship is set to true.
|
16
|
+
attribute :dba, Types::String # Optional. If the individual is a sole proprietor who is doing business under a different name, specify it here. This attribute is optional, even when soleProprietorship is set to true.
|
17
|
+
attribute :tags, Types::Hash # Optional. Tags that will be copied to the customer that this application creates
|
18
|
+
attribute :idempotency_key, Types::String # Optional
|
19
|
+
attribute :device_fingerprints, Types::Array # array of Device Fingerprint Optional. A list of device fingerprints for fraud and risk prevention
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
attribute :created_at, Types::DateTime, readonly: true
|
22
|
+
attribute :status, Types::String, readonly: true
|
23
|
+
attribute :message, Types::String, readonly: true
|
24
|
+
attribute :evaluation_id, Types::String, readonly: true
|
25
|
+
attribute :authorized_users, Types::Array, readonly: true
|
26
26
|
|
27
|
-
|
27
|
+
belongs_to :customer, class_name: 'Unit::IndividualCustomer'
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
include ResourceOperations::Find
|
30
|
+
include ResourceOperations::List
|
31
|
+
include ResourceOperations::Create
|
32
|
+
end
|
33
33
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Unit
|
2
|
-
class IndividualCustomer <
|
2
|
+
class IndividualCustomer < APIResource
|
3
3
|
path '/customers'
|
4
4
|
|
5
5
|
attribute :ssn, Types::String # SSN (or ITIN) of the individual (numbers only). Either an SSN or a passport number is required.
|
@@ -20,9 +20,9 @@ module Unit
|
|
20
20
|
|
21
21
|
belongs_to :application, class_name: 'Unit::IndividualApplication'
|
22
22
|
|
23
|
-
include
|
24
|
-
include
|
25
|
-
include
|
26
|
-
include
|
23
|
+
include ResourceOperations::List
|
24
|
+
include ResourceOperations::Create
|
25
|
+
include ResourceOperations::Save
|
26
|
+
include ResourceOperations::Find
|
27
27
|
end
|
28
28
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Unit
|
2
|
-
class IndividualDebitCard <
|
2
|
+
class IndividualDebitCard < APIResource
|
3
3
|
path '/cards'
|
4
4
|
|
5
5
|
attribute :shipping_address, Types::Address # Optional. Address to ship the card to. If not specified, the individual address is used.
|
@@ -17,9 +17,9 @@ module Unit
|
|
17
17
|
belongs_to :customer, class_name: 'Unit::IndividualCustomer'
|
18
18
|
belongs_to :account, class_name: 'Unit::DepositAccount'
|
19
19
|
|
20
|
-
include
|
21
|
-
include
|
22
|
-
include
|
23
|
-
include
|
20
|
+
include ResourceOperations::List
|
21
|
+
include ResourceOperations::Create
|
22
|
+
include ResourceOperations::Save
|
23
|
+
include ResourceOperations::Find
|
24
24
|
end
|
25
25
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Unit
|
2
|
-
class Institution <
|
2
|
+
class Institution < APIResource
|
3
3
|
attribute :routing_number, Types::String # Routing number of the institution. Valid 9-digit ABA routing transit number.
|
4
4
|
attribute :name, Types::String # Name of the institution.
|
5
5
|
attribute :address, Types::String # Optional. Address of the institution.
|
@@ -8,7 +8,7 @@ module Unit
|
|
8
8
|
|
9
9
|
path '/institutions'
|
10
10
|
|
11
|
-
include
|
11
|
+
include ResourceOperations::Find
|
12
12
|
|
13
13
|
def self.find_by(routing_number:)
|
14
14
|
find(routing_number)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unit
|
2
|
+
class Statement < APIResource
|
3
|
+
path '/statements'
|
4
|
+
|
5
|
+
attribute :period, Types::String
|
6
|
+
|
7
|
+
def self.pdf_for(statement_id:, customer_id:)
|
8
|
+
url = base_url(statement_id, :pdf, customer_id)
|
9
|
+
statement_connection(url).get.body
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.html_for(statement_id:, customer_id:)
|
13
|
+
url = base_url(statement_id, :html, customer_id)
|
14
|
+
statement_connection(url).get.body
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.base_url(statement_id, response_type, customer_id)
|
18
|
+
"#{Unit::Connection.base_url}statements/#{statement_id}/#{response_type}" \
|
19
|
+
"?filter[customerId]=#{customer_id}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.statement_connection(url)
|
23
|
+
# Establishing a new connection to avoid having to alter the existing connection to support pdf / html responses
|
24
|
+
Faraday.new(url) do |f|
|
25
|
+
f.headers['Authorization'] = "Bearer #{Unit::Connection.api_key}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
include ResourceOperations::List
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Unit
|
2
|
+
class Transaction < APIResource
|
3
|
+
path '/transactions'
|
4
|
+
|
5
|
+
attribute :direction, Types::String
|
6
|
+
attribute :amount, Types::Integer
|
7
|
+
attribute :balance, Types::Integer
|
8
|
+
attribute :summary, Types::String
|
9
|
+
attribute :created_at, Types::DateTime, readonly: true
|
10
|
+
|
11
|
+
include ResourceOperations::List
|
12
|
+
end
|
13
|
+
end
|
data/lib/unit-ruby/types/date.rb
CHANGED
@@ -1,179 +1,176 @@
|
|
1
1
|
module Unit
|
2
|
-
|
3
|
-
|
4
|
-
attr_accessor :id, :type
|
2
|
+
class APIResource
|
3
|
+
attr_accessor :id, :type, :raw_data
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def initialize(attributes = {})
|
6
|
+
clear_attributes!
|
7
|
+
mark_as_clean!
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
# Creates a base http connection to the API
|
16
|
-
#
|
17
|
-
def self.connection
|
18
|
-
@connection ||= Connection.new
|
9
|
+
attributes.each do |key, value|
|
10
|
+
send("#{key}=", value)
|
19
11
|
end
|
12
|
+
end
|
20
13
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
14
|
+
# Creates a base http connection to the API
|
15
|
+
#
|
16
|
+
def self.connection
|
17
|
+
@connection ||= Connection.new
|
18
|
+
end
|
26
19
|
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
# Defines the schema for a resource's attributes
|
21
|
+
#
|
22
|
+
def self.schema
|
23
|
+
@schema ||= Schema.new
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# @param type [Class] the object type
|
35
|
-
# @param readonly [Boolean] excludes the attribute from the request when creating a resource
|
36
|
-
def self.attribute(name, type = nil, readonly: false)
|
37
|
-
schema.add(name, type, readonly: readonly)
|
26
|
+
def schema
|
27
|
+
self.class.schema
|
28
|
+
end
|
38
29
|
|
39
|
-
|
30
|
+
# Declares a new attribute by name and adds it to the schema
|
31
|
+
#
|
32
|
+
# @param name [Symbol] the name of the attribute
|
33
|
+
# @param type [Class] the object type
|
34
|
+
# @param readonly [Boolean] excludes the attribute from the request when creating a resource
|
35
|
+
def self.attribute(name, type = nil, readonly: false)
|
36
|
+
schema.add(name, type, readonly: readonly)
|
40
37
|
|
41
|
-
|
42
|
-
previous_value = send(name)
|
43
|
-
new_value = type.cast(value)
|
38
|
+
attr_accessor name
|
44
39
|
|
45
|
-
|
40
|
+
define_method("#{name}=") do |value|
|
41
|
+
previous_value = send(name)
|
42
|
+
new_value = type.cast(value)
|
46
43
|
|
47
|
-
|
48
|
-
new_value
|
49
|
-
end
|
50
|
-
end
|
44
|
+
instance_variable_set("@#{name}", new_value)
|
51
45
|
|
52
|
-
|
53
|
-
|
46
|
+
mark_attribute_as_dirty(name) if new_value != previous_value
|
47
|
+
new_value
|
54
48
|
end
|
49
|
+
end
|
55
50
|
|
56
|
-
|
51
|
+
def relationships
|
52
|
+
@relationships ||= {}
|
53
|
+
end
|
57
54
|
|
58
|
-
|
59
|
-
#
|
60
|
-
# Usage:
|
61
|
-
# class Customer < Unit::Resource
|
62
|
-
# path '/customers'
|
63
|
-
# end
|
64
|
-
def self.path(route = nil)
|
65
|
-
return @path if route.nil?
|
55
|
+
attr_writer :relationships
|
66
56
|
|
67
|
-
|
68
|
-
|
57
|
+
# Sets the base path for this resource
|
58
|
+
#
|
59
|
+
# Usage:
|
60
|
+
# class Customer < Unit::Resource
|
61
|
+
# path '/customers'
|
62
|
+
# end
|
63
|
+
def self.path(route = nil)
|
64
|
+
return @path if route.nil?
|
69
65
|
|
70
|
-
|
71
|
-
|
72
|
-
end
|
66
|
+
@path = route
|
67
|
+
end
|
73
68
|
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
def self.resource_path(id)
|
70
|
+
"#{path}/#{id}"
|
71
|
+
end
|
77
72
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
73
|
+
def self.resources_path
|
74
|
+
path
|
75
|
+
end
|
82
76
|
|
83
|
-
|
84
|
-
|
85
|
-
|
77
|
+
# The JSON:API type for this resource
|
78
|
+
def resource_type
|
79
|
+
self.class.name.split('::').last.camelize(:lower)
|
80
|
+
end
|
86
81
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
82
|
+
# Creates an association to a related resource
|
83
|
+
# This will create a helper method to traverse into a resource's related resource(s)
|
84
|
+
def self.belongs_to(resource_name, class_name: nil)
|
85
|
+
class_name ||= resource_name.to_s.camelize
|
91
86
|
|
92
|
-
|
93
|
-
|
87
|
+
define_method(resource_name) do
|
88
|
+
relationship_id = relationships[resource_name][:data]&.fetch(:id)
|
94
89
|
|
95
|
-
|
90
|
+
return nil unless relationship_id
|
96
91
|
|
97
|
-
|
98
|
-
|
92
|
+
Kernel.const_get(class_name).find(relationship_id)
|
93
|
+
end
|
99
94
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
95
|
+
define_method("#{resource_name}=") do |resource|
|
96
|
+
relationships[resource_name] = {
|
97
|
+
data: { type: resource_name, id: resource.id }
|
98
|
+
}
|
105
99
|
end
|
100
|
+
end
|
106
101
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
102
|
+
# Hyrdates an instance of the resource from data returned from the API
|
103
|
+
def self.build_resource_from_json_api(data_item)
|
104
|
+
new.tap do |resource|
|
105
|
+
resource.mark_as_clean!
|
106
|
+
resource.update_resource_from_json_api(data_item)
|
113
107
|
end
|
108
|
+
end
|
114
109
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
110
|
+
def update_resource_from_json_api(data)
|
111
|
+
self.id = data[:id]
|
112
|
+
self.type = data[:type]
|
113
|
+
self.raw_data = data
|
114
|
+
self.relationships = data[:relationships]
|
119
115
|
|
120
|
-
|
116
|
+
clear_attributes!
|
121
117
|
|
122
|
-
|
118
|
+
data[:attributes].each { |key, value| update_attribute(key, value) }
|
123
119
|
|
124
|
-
|
125
|
-
|
120
|
+
mark_as_clean!
|
121
|
+
end
|
126
122
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
123
|
+
# Represents this resource's attributes
|
124
|
+
#
|
125
|
+
# @return [Hash] Representation of this resource's attributes as a hash
|
126
|
+
def attributes
|
127
|
+
self.class.schema.attributes.each_with_object({}) do |schema_attribute, h|
|
128
|
+
h[schema_attribute.name] = send(schema_attribute.name)
|
134
129
|
end
|
130
|
+
end
|
135
131
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
132
|
+
# Represents this resource for serialization (create/update)
|
133
|
+
#
|
134
|
+
# @return [Hash] Representation of this object as JSONAPI object
|
135
|
+
def as_json_api
|
136
|
+
self.class.schema.attributes.each_with_object({}) do |schema_attribute, h|
|
137
|
+
next if schema_attribute.readonly
|
142
138
|
|
143
|
-
|
139
|
+
val = send(schema_attribute.name)
|
144
140
|
|
145
|
-
|
146
|
-
|
141
|
+
# serialize the value if it is a complex type
|
142
|
+
val = val.as_json_api if val.respond_to? :as_json_api
|
147
143
|
|
148
|
-
|
149
|
-
end
|
144
|
+
h[schema_attribute.name] = val
|
150
145
|
end
|
146
|
+
end
|
151
147
|
|
152
|
-
|
153
|
-
|
154
|
-
|
148
|
+
def dirty?
|
149
|
+
dirty_attributes.any?
|
150
|
+
end
|
155
151
|
|
156
|
-
|
157
|
-
|
158
|
-
|
152
|
+
def dirty_attributes
|
153
|
+
@dirty_attributes ||= []
|
154
|
+
end
|
159
155
|
|
160
|
-
|
161
|
-
|
162
|
-
|
156
|
+
def mark_attribute_as_dirty(name)
|
157
|
+
dirty_attributes << name
|
158
|
+
end
|
163
159
|
|
164
|
-
|
165
|
-
|
166
|
-
|
160
|
+
def mark_as_clean!
|
161
|
+
@dirty_attributes = []
|
162
|
+
end
|
167
163
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
164
|
+
def clear_attributes!
|
165
|
+
schema.attributes.each do |attribute|
|
166
|
+
update_attribute(attribute.name, nil)
|
172
167
|
end
|
168
|
+
end
|
173
169
|
|
174
|
-
|
175
|
-
|
176
|
-
|
170
|
+
def update_attribute(name, value)
|
171
|
+
return unless schema.contains? name
|
172
|
+
|
173
|
+
send("#{name}=", value)
|
177
174
|
end
|
178
175
|
end
|
179
176
|
end
|
@@ -1,72 +1,70 @@
|
|
1
1
|
module Unit
|
2
|
-
|
3
|
-
class
|
4
|
-
|
5
|
-
|
6
|
-
end
|
2
|
+
class Connection
|
3
|
+
class << self
|
4
|
+
attr_accessor :api_key, :base_url
|
5
|
+
end
|
7
6
|
|
8
|
-
|
7
|
+
attr_reader :connection
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
9
|
+
def initialize
|
10
|
+
@connection = Faraday.new(self.class.base_url) do |f|
|
11
|
+
f.headers['Authorization'] = "Bearer #{self.class.api_key}"
|
12
|
+
f.request :json # encode req bodies as JSON
|
13
|
+
f.request :retry # retry transient failures
|
14
|
+
f.response :follow_redirects # follow redirects
|
15
|
+
f.response :json # decode response bodies as JSON
|
18
16
|
end
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
# Executes a GET request to the API
|
20
|
+
#
|
21
|
+
# @return the resource (or array of resources) returned from the API
|
22
|
+
def get(path, params = nil)
|
23
|
+
response = connection.get(path, params)
|
25
24
|
|
26
|
-
|
25
|
+
handle_errors(response)
|
27
26
|
|
28
|
-
|
27
|
+
from_json_api(response.body)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Executes a POST request to the API
|
31
|
+
#
|
32
|
+
# @return [Unit::APIResource] a new instance of the resource
|
33
|
+
def post(path, data = nil)
|
34
|
+
response = connection.post do |req|
|
35
|
+
req.url path
|
36
|
+
req.headers['Content-Type'] = 'application/vnd.api+json'
|
37
|
+
req.body = data.deep_transform_keys! { |key| key.to_s.camelize(:lower) } if data
|
29
38
|
end
|
30
39
|
|
31
|
-
|
32
|
-
#
|
33
|
-
# @return [Unit::APIResource] a new instance of the resource
|
34
|
-
def post(path, data = nil)
|
35
|
-
response = connection.post do |req|
|
36
|
-
req.url path
|
37
|
-
req.headers['Content-Type'] = 'application/vnd.api+json'
|
38
|
-
req.body = data.deep_transform_keys! { |key| key.to_s.camelize(:lower) } if data
|
39
|
-
end
|
40
|
+
handle_errors(response)
|
40
41
|
|
41
|
-
|
42
|
+
from_json_api(response.body)
|
43
|
+
end
|
42
44
|
|
43
|
-
|
45
|
+
# Executes a PATCH request to the API
|
46
|
+
def patch(path, data = nil)
|
47
|
+
response = connection.patch do |req|
|
48
|
+
req.url path
|
49
|
+
req.headers['Content-Type'] = 'application/vnd.api+json'
|
50
|
+
req.body = data.deep_transform_keys! { |key| key.to_s.camelize(:lower) } if data
|
44
51
|
end
|
45
52
|
|
46
|
-
|
47
|
-
def patch(path, data = nil)
|
48
|
-
response = connection.patch do |req|
|
49
|
-
req.url path
|
50
|
-
req.headers['Content-Type'] = 'application/vnd.api+json'
|
51
|
-
req.body = data.deep_transform_keys! { |key| key.to_s.camelize(:lower) } if data
|
52
|
-
end
|
53
|
+
handle_errors(response)
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
from_json_api(response.body)
|
57
|
-
end
|
55
|
+
from_json_api(response.body)
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
def from_json_api(response_body)
|
59
|
+
response_body.deep_transform_keys do |key|
|
60
|
+
key.to_s.underscore.to_sym
|
61
|
+
end.fetch(:data)
|
62
|
+
end
|
64
63
|
|
65
|
-
|
66
|
-
|
64
|
+
def handle_errors(response)
|
65
|
+
return if response.success?
|
67
66
|
|
68
|
-
|
69
|
-
end
|
67
|
+
raise(Error, response.body)
|
70
68
|
end
|
71
69
|
end
|
72
70
|
end
|
data/lib/unit-ruby/util/error.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
module Unit
|
2
|
-
|
3
|
-
|
4
|
-
attr_accessor :title, :status, :details, :detail
|
2
|
+
class Error < StandardError
|
3
|
+
attr_accessor :title, :status, :details, :detail
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
def initialize(api_response)
|
6
|
+
error = api_response['errors'].first
|
7
|
+
@title = error['title']
|
8
|
+
@status = error['status']
|
9
|
+
@details = error['details'] || error['detail']
|
11
10
|
|
12
|
-
|
13
|
-
end
|
11
|
+
super(@details)
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -1,81 +1,79 @@
|
|
1
1
|
module Unit
|
2
|
-
module
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
2
|
+
module ResourceOperations
|
3
|
+
module Find
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend(ClassMethods)
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
module ClassMethods
|
9
|
+
def find(id)
|
10
|
+
located_resource = connection.get(resource_path(id))
|
12
11
|
|
13
|
-
|
14
|
-
end
|
12
|
+
build_resource_from_json_api(located_resource)
|
15
13
|
end
|
16
14
|
end
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
module Create
|
18
|
+
def self.included(klass)
|
19
|
+
klass.extend(ClassMethods)
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
module ClassMethods
|
23
|
+
def create(attributes)
|
24
|
+
resource = new(attributes)
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
data = {
|
27
|
+
type: resource.resource_type,
|
28
|
+
attributes: resource.as_json_api.slice(*resource.dirty_attributes)
|
29
|
+
}
|
30
|
+
unless resource.relationships.empty?
|
31
|
+
data[:relationships] =
|
32
|
+
resource.relationships
|
33
|
+
end
|
35
34
|
|
36
|
-
|
35
|
+
created_resource = connection.post(resources_path, { data: data })
|
37
36
|
|
38
|
-
|
39
|
-
end
|
37
|
+
build_resource_from_json_api(created_resource)
|
40
38
|
end
|
41
39
|
end
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
module List
|
43
|
+
def self.included(klass)
|
44
|
+
klass.extend(ClassMethods)
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
47
|
+
module ClassMethods
|
48
|
+
# List resources
|
49
|
+
#
|
50
|
+
# @param where [Hash] Optional. Filters to apply to the list.
|
51
|
+
# @param limit [Integer] Optional. Maximum number of resources that will be returned. Maximum is 1000 resources.
|
52
|
+
# @param offset [Integer] Optional. Number of resources to skip
|
53
|
+
# @param sort [String] Optional. sort: 'createdAt' for ascending order or sort: '-createdAt' (leading minus sign) for descending order
|
54
|
+
def list(where: {}, limit: 100, offset: 0, sort: nil)
|
55
|
+
params = { filter: where, page: { offset: offset, limit: limit },
|
56
|
+
sort: sort }.compact
|
57
|
+
resources = connection.get(resources_path, params)
|
59
58
|
|
60
|
-
|
61
|
-
end
|
59
|
+
resources.map { |resource| build_resource_from_json_api(resource) }
|
62
60
|
end
|
63
61
|
end
|
62
|
+
end
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
}
|
64
|
+
module Save
|
65
|
+
def save
|
66
|
+
updated_resource = self.class.connection.patch(
|
67
|
+
resource_path,
|
68
|
+
{
|
69
|
+
data: {
|
70
|
+
type: resource_type,
|
71
|
+
attributes: as_json_api.slice(*dirty_attributes)
|
74
72
|
}
|
75
|
-
|
73
|
+
}
|
74
|
+
)
|
76
75
|
|
77
|
-
|
78
|
-
end
|
76
|
+
update_resource_from_json_api(updated_resource)
|
79
77
|
end
|
80
78
|
end
|
81
79
|
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
module Unit
|
2
|
-
|
3
|
-
|
4
|
-
Attribute = Struct.new(:name, :type, :readonly)
|
2
|
+
class Schema
|
3
|
+
Attribute = Struct.new(:name, :type, :readonly)
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def initialize
|
6
|
+
@attributes = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def contains?(name)
|
10
|
+
attributes.map(&:name).include? name
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
attr_reader :attributes
|
13
|
+
def add(name, type, readonly: false)
|
14
|
+
@attributes << Attribute.new(name, type, readonly)
|
14
15
|
end
|
16
|
+
attr_reader :attributes
|
15
17
|
end
|
16
18
|
end
|
data/lib/unit-ruby/version.rb
CHANGED
data/lib/unit-ruby.rb
CHANGED
@@ -12,7 +12,6 @@ require 'unit-ruby/types/boolean'
|
|
12
12
|
require 'unit-ruby/types/coordinates'
|
13
13
|
require 'unit-ruby/types/date_time'
|
14
14
|
require 'unit-ruby/types/date'
|
15
|
-
require 'unit-ruby/types/decimal'
|
16
15
|
require 'unit-ruby/types/float'
|
17
16
|
require 'unit-ruby/types/full_name'
|
18
17
|
require 'unit-ruby/types/hash'
|
@@ -27,6 +26,9 @@ require 'unit-ruby/individual_application'
|
|
27
26
|
require 'unit-ruby/individual_customer'
|
28
27
|
require 'unit-ruby/individual_debit_card'
|
29
28
|
require 'unit-ruby/institution'
|
29
|
+
require 'unit-ruby/pin_status'
|
30
|
+
require 'unit-ruby/statement'
|
31
|
+
require 'unit-ruby/transaction'
|
30
32
|
require 'unit-ruby/version'
|
31
33
|
|
32
34
|
module Unit
|
@@ -36,6 +38,6 @@ module Unit
|
|
36
38
|
# config.base_url = 'https://api.s.unit.sh'
|
37
39
|
# end
|
38
40
|
def self.configure
|
39
|
-
yield(
|
41
|
+
yield(Connection)
|
40
42
|
end
|
41
43
|
end
|
data/unit-ruby.gemspec
CHANGED
@@ -5,8 +5,8 @@ require 'unit-ruby/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'unit-ruby'
|
7
7
|
spec.version = Unit::VERSION
|
8
|
-
spec.authors = ['Chloe Isacke']
|
9
|
-
spec.email = ['chloe@retirable.com']
|
8
|
+
spec.authors = ['Chloe Isacke', 'Ian Yamey']
|
9
|
+
spec.email = ['chloe@retirable.com', 'ian@retirable.com']
|
10
10
|
|
11
11
|
spec.summary = 'A Ruby gem for communicating with the Unit API.'
|
12
12
|
spec.homepage = 'https://github.com/retirable/unit-ruby'
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unit-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chloe Isacke
|
8
|
+
- Ian Yamey
|
8
9
|
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date: 2022-
|
12
|
+
date: 2022-02-24 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: faraday
|
@@ -83,14 +84,17 @@ dependencies:
|
|
83
84
|
description:
|
84
85
|
email:
|
85
86
|
- chloe@retirable.com
|
87
|
+
- ian@retirable.com
|
86
88
|
executables: []
|
87
89
|
extensions: []
|
88
90
|
extra_rdoc_files: []
|
89
91
|
files:
|
92
|
+
- ".github/workflows/ruby.yml"
|
90
93
|
- ".gitignore"
|
91
94
|
- ".rspec"
|
92
95
|
- ".rubocop.yml"
|
93
96
|
- ".travis.yml"
|
97
|
+
- CHANGELOG.md
|
94
98
|
- CODE_OF_CONDUCT.md
|
95
99
|
- Gemfile
|
96
100
|
- Gemfile.lock
|
@@ -107,6 +111,9 @@ files:
|
|
107
111
|
- lib/unit-ruby/individual_customer.rb
|
108
112
|
- lib/unit-ruby/individual_debit_card.rb
|
109
113
|
- lib/unit-ruby/institution.rb
|
114
|
+
- lib/unit-ruby/pin_status.rb
|
115
|
+
- lib/unit-ruby/statement.rb
|
116
|
+
- lib/unit-ruby/transaction.rb
|
110
117
|
- lib/unit-ruby/types/address.rb
|
111
118
|
- lib/unit-ruby/types/application_form_prefill.rb
|
112
119
|
- lib/unit-ruby/types/application_form_settings_override.rb
|
@@ -115,7 +122,6 @@ files:
|
|
115
122
|
- lib/unit-ruby/types/coordinates.rb
|
116
123
|
- lib/unit-ruby/types/date.rb
|
117
124
|
- lib/unit-ruby/types/date_time.rb
|
118
|
-
- lib/unit-ruby/types/decimal.rb
|
119
125
|
- lib/unit-ruby/types/float.rb
|
120
126
|
- lib/unit-ruby/types/full_name.rb
|
121
127
|
- lib/unit-ruby/types/hash.rb
|