justifi 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|