justifi 0.5.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 +7 -0
- data/.env.template +2 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +48 -0
- data/.github/workflows/build_and_release.yml +92 -0
- data/.github/workflows/publish_coverage.yml +46 -0
- data/.github/workflows/verify.yml +51 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +92 -0
- data/README.md +227 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/justifi.gemspec +40 -0
- data/lib/justifi/api_operations.rb +104 -0
- data/lib/justifi/configuration.rb +62 -0
- data/lib/justifi/dispute.rb +25 -0
- data/lib/justifi/in_memory_cache.rb +54 -0
- data/lib/justifi/justifi_error.rb +18 -0
- data/lib/justifi/justifi_object.rb +34 -0
- data/lib/justifi/justifi_operations.rb +37 -0
- data/lib/justifi/justifi_response.rb +86 -0
- data/lib/justifi/list_object.rb +78 -0
- data/lib/justifi/oauth.rb +27 -0
- data/lib/justifi/payment.rb +49 -0
- data/lib/justifi/payment_intent.rb +48 -0
- data/lib/justifi/payment_method.rb +34 -0
- data/lib/justifi/payout.rb +25 -0
- data/lib/justifi/refund.rb +25 -0
- data/lib/justifi/util.rb +82 -0
- data/lib/justifi/version.rb +5 -0
- data/lib/justifi.rb +72 -0
- metadata +206 -0
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "justifi"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/justifi.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/justifi/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "justifi"
|
7
|
+
spec.version = Justifi::VERSION
|
8
|
+
spec.authors = ["JustiFi"]
|
9
|
+
spec.email = ["support@justifi.ai"]
|
10
|
+
|
11
|
+
spec.summary = "JustiFi API wrapper gem"
|
12
|
+
spec.description = "Used to communicate with JustiFi APIs"
|
13
|
+
spec.homepage = "https://justifi.ai"
|
14
|
+
spec.required_ruby_version = ">= 2.4"
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = "https://github.com/justifi-tech/justifi-ruby"
|
18
|
+
spec.metadata["github_repo"] = "ssh://github.com/justifi-tech/justifi-ruby"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/justifi-tech/justifi-ruby/changelog"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features|gem)/}) }
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_development_dependency "byebug"
|
32
|
+
spec.add_development_dependency "dotenv"
|
33
|
+
spec.add_development_dependency "rubocop"
|
34
|
+
spec.add_development_dependency "standard"
|
35
|
+
spec.add_development_dependency "webmock", ">= 3.8.0"
|
36
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
38
|
+
spec.add_development_dependency "simplecov"
|
39
|
+
spec.add_development_dependency "simplecov-small-badge"
|
40
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
|
5
|
+
module Justifi
|
6
|
+
module APIOperations
|
7
|
+
module ClassMethods
|
8
|
+
def execute_post_request(path, body, headers)
|
9
|
+
raise ArgumentError, "body should be a string" if body && !body.is_a?(String)
|
10
|
+
raise ArgumentError, "headers should be a hash" if headers && !headers.is_a?(Hash)
|
11
|
+
|
12
|
+
response = execute_request(:post, path, body, headers)
|
13
|
+
|
14
|
+
JustifiObject.construct_from(path, response, headers)
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_get_request(path, query, headers)
|
18
|
+
raise ArgumentError, "query should be a string" if query && !query.is_a?(String)
|
19
|
+
raise ArgumentError, "headers should be a hash" if headers && !headers.is_a?(Hash)
|
20
|
+
|
21
|
+
path = "#{path}?#{query}"
|
22
|
+
response = execute_request(:get, path, nil, headers)
|
23
|
+
|
24
|
+
JustifiObject.construct_from(path, response, headers)
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_patch_request(path, body, headers)
|
28
|
+
raise ArgumentError, "body should be a string" if body && !body.is_a?(String)
|
29
|
+
raise ArgumentError, "headers should be a hash" if headers && !headers.is_a?(Hash)
|
30
|
+
|
31
|
+
response = execute_request(:patch, path, body, headers)
|
32
|
+
|
33
|
+
JustifiObject.construct_from(path, response, headers)
|
34
|
+
end
|
35
|
+
|
36
|
+
def idempotently_request(path, method:, params:, headers:, idempotency_key: nil)
|
37
|
+
idempotency_key ||= Justifi.get_idempotency_key
|
38
|
+
headers[:idempotency_key] = idempotency_key
|
39
|
+
|
40
|
+
retryable_request do
|
41
|
+
send("execute_#{method}_request", path, params, headers)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private def execute_request(method_name, path, body, headers)
|
46
|
+
headers["Content-Type"] = "application/json"
|
47
|
+
headers["User-Agent"] = "justifi-ruby-#{Justifi::VERSION}"
|
48
|
+
|
49
|
+
connection = http_connection(path)
|
50
|
+
|
51
|
+
method_name = method_name.to_s.upcase
|
52
|
+
has_response_body = method_name != "HEAD"
|
53
|
+
request = Net::HTTPGenericRequest.new(
|
54
|
+
method_name,
|
55
|
+
(body ? true : false),
|
56
|
+
has_response_body,
|
57
|
+
path,
|
58
|
+
headers
|
59
|
+
)
|
60
|
+
|
61
|
+
response = JustifiResponse.from_net_http(connection.request(request, body))
|
62
|
+
raise InvalidHttpResponseError.new(response: response) unless response.success
|
63
|
+
response
|
64
|
+
end
|
65
|
+
|
66
|
+
private def retryable_request
|
67
|
+
attempt = 1
|
68
|
+
|
69
|
+
begin
|
70
|
+
response = yield
|
71
|
+
rescue => e
|
72
|
+
if should_retry?(e, attempt: attempt)
|
73
|
+
attempt += 1
|
74
|
+
retry
|
75
|
+
end
|
76
|
+
|
77
|
+
raise
|
78
|
+
end
|
79
|
+
|
80
|
+
response
|
81
|
+
end
|
82
|
+
|
83
|
+
private def should_retry?(error, attempt:)
|
84
|
+
return false if attempt >= Justifi.max_attempts
|
85
|
+
|
86
|
+
case error
|
87
|
+
when Net::OpenTimeout, Net::ReadTimeout
|
88
|
+
true
|
89
|
+
when Justifi::Error
|
90
|
+
# 409 Conflict
|
91
|
+
return true if error.response_code == 409
|
92
|
+
# Add more cases
|
93
|
+
else
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def http_connection(path)
|
99
|
+
uri = URI("#{Justifi.api_url}#{path}")
|
100
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Justifi
|
6
|
+
class Configuration
|
7
|
+
API_BASE_URL = "https://api.justifi.ai"
|
8
|
+
|
9
|
+
attr_accessor :client_id
|
10
|
+
attr_accessor :client_secret
|
11
|
+
attr_accessor :access_token
|
12
|
+
attr_accessor :environment
|
13
|
+
attr_accessor :max_attempts
|
14
|
+
attr_accessor :cache
|
15
|
+
|
16
|
+
def self.setup
|
17
|
+
new.tap do |instance|
|
18
|
+
yield(instance) if block_given?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@max_attempts = 3
|
24
|
+
end
|
25
|
+
|
26
|
+
def credentials
|
27
|
+
raise Justifi::BadCredentialsError, "credentials not set" if bad_credentials?
|
28
|
+
|
29
|
+
{
|
30
|
+
client_id: client_id,
|
31
|
+
client_secret: client_secret
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def bad_credentials?
|
36
|
+
# TODO: improve this
|
37
|
+
return true if client_id.nil? || client_secret.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def clear_credentials
|
41
|
+
@client_id = nil
|
42
|
+
@client_secret = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def api_url
|
46
|
+
case environment
|
47
|
+
when "staging"
|
48
|
+
ENV["API_STAGING_BASE_URL"]
|
49
|
+
else
|
50
|
+
API_BASE_URL
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def use_production
|
55
|
+
@environment = "production"
|
56
|
+
end
|
57
|
+
|
58
|
+
def use_staging
|
59
|
+
@environment = "staging"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
module Dispute
|
5
|
+
class << self
|
6
|
+
def list(params: {}, headers: {}, seller_account_id: nil)
|
7
|
+
headers[:seller_account] = seller_account_id if seller_account_id
|
8
|
+
JustifiOperations.execute_get_request("/v1/disputes", params, headers)
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(dispute_id:, headers: {})
|
12
|
+
JustifiOperations.execute_get_request("/v1/disputes/#{dispute_id}",
|
13
|
+
{},
|
14
|
+
headers)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(dispute_id:, params: {}, headers: {}, idempotency_key: nil)
|
18
|
+
JustifiOperations.idempotently_request("/v1/disputes/#{dispute_id}",
|
19
|
+
method: :patch,
|
20
|
+
params: params,
|
21
|
+
headers: {})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Justifi
|
2
|
+
class InMemoryCache
|
3
|
+
attr_reader :data
|
4
|
+
|
5
|
+
HALF_DAY_IN_SECONDS = 43200
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@data = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# preload data into the cache
|
12
|
+
def init(data)
|
13
|
+
data.map do |key, value|
|
14
|
+
set(key, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def set(key, value, expiration: nil)
|
19
|
+
expiration ||= Time.now + HALF_DAY_IN_SECONDS
|
20
|
+
@data[key.to_s] = expirable_value(value, expiration)
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_and_return(key, value, expiration: nil)
|
24
|
+
set(key, value, expiration: expiration)
|
25
|
+
value
|
26
|
+
end
|
27
|
+
|
28
|
+
def expirable_value(value, expiration)
|
29
|
+
{value: value, expiration: expiration}
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(key)
|
33
|
+
expire_key!(key) if expired?(@data[key.to_s]&.fetch(:expiration))
|
34
|
+
@data[key.to_s]&.fetch(:value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_expiration(key)
|
38
|
+
expire_key!(key) if expired?(@data[key.to_s]&.fetch(:expiration))
|
39
|
+
@data[key.to_s]&.fetch(:expiration)
|
40
|
+
end
|
41
|
+
|
42
|
+
def expired?(expiration)
|
43
|
+
!expiration.nil? && Time.now > expiration
|
44
|
+
end
|
45
|
+
|
46
|
+
def expire_key!(key)
|
47
|
+
@data.delete(key.to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
def clear_cache
|
51
|
+
@data = {}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
class Error < StandardError
|
5
|
+
attr_reader :response_code
|
6
|
+
|
7
|
+
def initialize(response_code, msg)
|
8
|
+
super(msg)
|
9
|
+
@response_code = response_code
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class InvalidHttpResponseError < Error
|
14
|
+
def initialize(response:)
|
15
|
+
super(response.http_status, response.error_message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
class JustifiObject
|
5
|
+
extend Justifi::JustifiOperations
|
6
|
+
|
7
|
+
attr_reader :raw_response, :id, :headers
|
8
|
+
|
9
|
+
def initialize(id: nil, headers: {}, raw_response: nil)
|
10
|
+
@id = id
|
11
|
+
@headers = Util.normalize_headers(headers)
|
12
|
+
@raw_response = raw_response
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.construct_from(path, response, headers = {})
|
16
|
+
values = response.is_a?(JustifiResponse) ? response.data : response
|
17
|
+
|
18
|
+
new(id: values[:id], raw_response: response)
|
19
|
+
.send(:initialize_from, values, headers)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected def initialize_from(values, headers)
|
23
|
+
values.each do |k, v|
|
24
|
+
instance_variable_set("@#{k}", v.is_a?(Hash) ? OpenStruct.new(v) : v)
|
25
|
+
self.class.send(:define_method, k, proc { instance_variable_get("@#{k}") })
|
26
|
+
self.class.send(:define_method, "#{k}=", proc { |v| instance_variable_set("@#{k}", v) })
|
27
|
+
end
|
28
|
+
|
29
|
+
@headers = Util.normalize_headers(headers)
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
module JustifiOperations
|
5
|
+
extend APIOperations::ClassMethods
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def execute_post_request(path, params, headers)
|
9
|
+
params = Util.normalize_params(params)
|
10
|
+
headers[:authorization] = "Bearer #{Justifi::OAuth.get_token}"
|
11
|
+
|
12
|
+
headers = Util.normalize_headers(headers)
|
13
|
+
super(path, params, headers)
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute_get_request(path, params, headers)
|
17
|
+
query = Util.encode_parameters(params)
|
18
|
+
headers[:authorization] = "Bearer #{Justifi::OAuth.get_token}"
|
19
|
+
headers = Util.normalize_headers(headers)
|
20
|
+
|
21
|
+
super(path, query, headers)
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute_patch_request(path, params, headers)
|
25
|
+
params = Util.normalize_params(params)
|
26
|
+
headers[:authorization] = "Bearer #{Justifi::OAuth.get_token}"
|
27
|
+
|
28
|
+
headers = Util.normalize_headers(headers)
|
29
|
+
super(path, params, headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
def list(path, params = {}, headers = {})
|
33
|
+
Justifi::ListObject.list(path, params, headers)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
# Headers provides an access wrapper to an API response's header data. It
|
5
|
+
# mainly exists so that we don't need to expose the entire
|
6
|
+
# `Net::HTTPResponse` object while still getting some of its benefits like
|
7
|
+
# case-insensitive access to header names and flattening of header values.
|
8
|
+
class JustifiResponseHeaders
|
9
|
+
# Initializes a Headers object from a Net::HTTP::HTTPResponse object.
|
10
|
+
def self.from_net_http(resp)
|
11
|
+
new(resp.to_hash)
|
12
|
+
end
|
13
|
+
|
14
|
+
# `hash` is expected to be a hash mapping header names to arrays of
|
15
|
+
# header values. This is the default format generated by calling
|
16
|
+
# `#to_hash` on a `Net::HTTPResponse` object because headers can be
|
17
|
+
# repeated multiple times. Using `#[]` will collapse values down to just
|
18
|
+
# the first.
|
19
|
+
def initialize(hash)
|
20
|
+
if !hash.is_a?(Hash)
|
21
|
+
raise ArgumentError,
|
22
|
+
"expect hash to be a map of string header names to arrays of " \
|
23
|
+
"header values"
|
24
|
+
end
|
25
|
+
|
26
|
+
@hash = {}
|
27
|
+
|
28
|
+
# This shouldn't be strictly necessary because `Net::HTTPResponse` will
|
29
|
+
# produce a hash with all headers downcased, but do it anyway just in
|
30
|
+
# case an object of this class was constructed manually.
|
31
|
+
#
|
32
|
+
# Also has the effect of duplicating the hash, which is desirable for a
|
33
|
+
# little extra object safety.
|
34
|
+
hash.each do |k, v|
|
35
|
+
@hash[k.downcase] = v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module JustifiResponseBase
|
41
|
+
# A Hash of the HTTP headers of the response.
|
42
|
+
attr_accessor :http_headers
|
43
|
+
|
44
|
+
# The integer HTTP status code of the response.
|
45
|
+
attr_accessor :http_status
|
46
|
+
|
47
|
+
# The JustiFi request ID of the response.
|
48
|
+
attr_accessor :request_id
|
49
|
+
|
50
|
+
def self.populate_for_net_http(resp, http_resp)
|
51
|
+
resp.http_headers = JustifiResponseHeaders.from_net_http(http_resp)
|
52
|
+
resp.http_status = http_resp.code.to_i
|
53
|
+
resp.request_id = http_resp["request-id"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# JustifiResponse encapsulates some vitals of a response that came back from
|
58
|
+
# the Justifi API.
|
59
|
+
class JustifiResponse
|
60
|
+
include JustifiResponseBase
|
61
|
+
# The data contained by the HTTP body of the response deserialized from
|
62
|
+
# JSON.
|
63
|
+
attr_accessor :data
|
64
|
+
|
65
|
+
# The raw HTTP body of the response.
|
66
|
+
attr_accessor :http_body
|
67
|
+
|
68
|
+
# The error error_message from JustiFi API
|
69
|
+
attr_accessor :error_message
|
70
|
+
|
71
|
+
# The boolean flag based on Net::HTTPSuccess
|
72
|
+
attr_accessor :success
|
73
|
+
|
74
|
+
# Initializes a JustifiResponse object from a Net::HTTP::HTTPResponse
|
75
|
+
# object.
|
76
|
+
def self.from_net_http(http_resp)
|
77
|
+
resp = JustifiResponse.new
|
78
|
+
resp.data = JSON.parse(http_resp.body, symbolize_names: true)
|
79
|
+
resp.http_body = http_resp.body
|
80
|
+
resp.success = http_resp.is_a? Net::HTTPSuccess
|
81
|
+
resp.error_message = resp.data.dig(:error, :message)
|
82
|
+
JustifiResponseBase.populate_for_net_http(resp, http_resp)
|
83
|
+
resp
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
class ListObject
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :justifi_object
|
8
|
+
attr_accessor :request_params, :request_headers, :path
|
9
|
+
|
10
|
+
def_delegators :@justifi_object, :data, :data
|
11
|
+
def_delegators :@justifi_object, :page_info, :page_info
|
12
|
+
def_delegators :@justifi_object, :http_status, :http_status
|
13
|
+
def_delegators :@justifi_object, :raw_response, :raw_response
|
14
|
+
|
15
|
+
# An empty list object to return when has_next or has_previous
|
16
|
+
# does not exist
|
17
|
+
def self.empty_list(headers = {})
|
18
|
+
JustifiObject.construct_from({data: []}, headers)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(justifi_object:, path:, params: {}, headers: {})
|
22
|
+
@justifi_object = justifi_object
|
23
|
+
@path = path
|
24
|
+
@request_params = params
|
25
|
+
@request_headers = headers
|
26
|
+
end
|
27
|
+
|
28
|
+
# Iterates through each resource in the page represented by the current
|
29
|
+
# `ListObject`.
|
30
|
+
def each(&block)
|
31
|
+
data.each(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if the page object contains no elements.
|
35
|
+
def empty?
|
36
|
+
data.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_previous
|
40
|
+
page_info.has_previous
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_next
|
44
|
+
page_info.has_next
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_cursor
|
48
|
+
page_info.start_cursor
|
49
|
+
end
|
50
|
+
|
51
|
+
def end_cursor
|
52
|
+
page_info.end_cursor
|
53
|
+
end
|
54
|
+
|
55
|
+
# Fetches the next page based on page_info[:end_cursor] paginaton
|
56
|
+
def next_page(params = {}, headers = {})
|
57
|
+
return self.class.empty_list(headers) unless has_next
|
58
|
+
|
59
|
+
params[:after_cursor] = end_cursor
|
60
|
+
|
61
|
+
Justifi::ListObject.list(path, @request_params.merge(params), @request_headers.merge(headers))
|
62
|
+
end
|
63
|
+
|
64
|
+
# Fetches the next page based on page_info[:start_cursor] paginaton
|
65
|
+
def previous_page(params = {}, headers = {})
|
66
|
+
return self.class.empty_list(headers) unless has_previous
|
67
|
+
|
68
|
+
params[:before_cursor] = start_cursor
|
69
|
+
|
70
|
+
Justifi::ListObject.list(path, @request_params.merge(params), @request_headers.merge(headers))
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.list(path, params = {}, headers = {})
|
74
|
+
justifi_object = JustifiOperations.execute_get_request(path, params, headers)
|
75
|
+
new(justifi_object: justifi_object, path: path, params: params, headers: headers)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
module OAuth
|
5
|
+
module OAuthOperations
|
6
|
+
extend APIOperations::ClassMethods
|
7
|
+
|
8
|
+
def self.execute_post_request(path, params, headers)
|
9
|
+
params = Util.normalize_params(params.merge(Justifi.credentials))
|
10
|
+
super(path, params, headers)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def get_token(params = {}, headers = {})
|
16
|
+
token = Justifi.cache.get(:access_token)
|
17
|
+
return token unless token.nil?
|
18
|
+
|
19
|
+
response = OAuthOperations.execute_post_request(
|
20
|
+
"/oauth/token", params, headers
|
21
|
+
)
|
22
|
+
|
23
|
+
Justifi.cache.set_and_return(:access_token, response.access_token)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Justifi
|
4
|
+
module Payment
|
5
|
+
class << self
|
6
|
+
def create(params: {}, headers: {}, idempotency_key: nil, seller_account_id: nil)
|
7
|
+
headers[:seller_account] = seller_account_id if seller_account_id
|
8
|
+
JustifiOperations.idempotently_request("/v1/payments",
|
9
|
+
method: :post,
|
10
|
+
params: params,
|
11
|
+
headers: headers)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_refund(amount:, payment_id:, reason: nil, description: nil)
|
15
|
+
refund_params = {amount: amount, description: description, reason: reason}
|
16
|
+
JustifiOperations.idempotently_request("/v1/payments/#{payment_id}/refunds",
|
17
|
+
method: :post,
|
18
|
+
params: refund_params,
|
19
|
+
headers: {})
|
20
|
+
end
|
21
|
+
|
22
|
+
def list(params: {}, headers: {}, seller_account_id: nil)
|
23
|
+
headers[:seller_account] = seller_account_id if seller_account_id
|
24
|
+
JustifiOperations.execute_get_request("/v1/payments", params, headers)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(payment_id:, headers: {})
|
28
|
+
JustifiOperations.execute_get_request("/v1/payments/#{payment_id}",
|
29
|
+
{},
|
30
|
+
headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
def update(payment_id:, params: {}, headers: {}, idempotency_key: nil)
|
34
|
+
JustifiOperations.idempotently_request("/v1/payments/#{payment_id}",
|
35
|
+
method: :patch,
|
36
|
+
params: params,
|
37
|
+
headers: {})
|
38
|
+
end
|
39
|
+
|
40
|
+
def capture(payment_id:, amount: nil, headers: {}, idempotency_key: nil)
|
41
|
+
params = amount.nil? ? {} : {amount: amount}
|
42
|
+
JustifiOperations.idempotently_request("/v1/payments/#{payment_id}/capture",
|
43
|
+
method: :post,
|
44
|
+
params: params,
|
45
|
+
headers: {})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|