webpay 2.0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +1 -0
- data/lib/data/ca-certificates.crt +3829 -0
- data/lib/webpay.rb +66 -0
- data/lib/webpay/account.rb +20 -0
- data/lib/webpay/card.rb +13 -0
- data/lib/webpay/charge.rb +33 -0
- data/lib/webpay/client.rb +62 -0
- data/lib/webpay/customer.rb +70 -0
- data/lib/webpay/entity.rb +63 -0
- data/lib/webpay/entity_list.rb +25 -0
- data/lib/webpay/event.rb +19 -0
- data/lib/webpay/operations.rb +49 -0
- data/lib/webpay/response_converter.rb +45 -0
- data/lib/webpay/token.rb +13 -0
- data/lib/webpay/version.rb +5 -0
- data/lib/webpay/webpay_error.rb +120 -0
- data/webpay.gemspec +27 -0
- metadata +149 -0
data/lib/webpay.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'webpay/version'
|
|
2
|
+
|
|
3
|
+
# Toplevel module of WebPay gem.
|
|
4
|
+
# This is the start point.
|
|
5
|
+
module WebPay
|
|
6
|
+
autoload(:Client, 'webpay/client')
|
|
7
|
+
autoload(:Operations, 'webpay/operations')
|
|
8
|
+
autoload(:WebPayError, 'webpay/webpay_error')
|
|
9
|
+
autoload(:APIConnectionError, 'webpay/webpay_error')
|
|
10
|
+
autoload(:APIError, 'webpay/webpay_error')
|
|
11
|
+
autoload(:AuthenticationError, 'webpay/webpay_error')
|
|
12
|
+
autoload(:CardError, 'webpay/webpay_error')
|
|
13
|
+
autoload(:InvalidRequestError, 'webpay/webpay_error')
|
|
14
|
+
autoload(:Entity, 'webpay/entity')
|
|
15
|
+
autoload(:EntityList, 'webpay/entity_list')
|
|
16
|
+
autoload(:Account, 'webpay/account')
|
|
17
|
+
autoload(:Card, 'webpay/card')
|
|
18
|
+
autoload(:Charge, 'webpay/charge')
|
|
19
|
+
autoload(:Customer, 'webpay/customer')
|
|
20
|
+
autoload(:Event, 'webpay/event')
|
|
21
|
+
autoload(:Token, 'webpay/token')
|
|
22
|
+
autoload(:ResponseConverter, 'webpay/response_converter')
|
|
23
|
+
|
|
24
|
+
@api_base = 'https://api.webpay.jp'
|
|
25
|
+
@api_version = '/v1'
|
|
26
|
+
@api_key = nil
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
# Absolute path to SSL CA file.
|
|
30
|
+
# This gem includes SSL CA file as lib/data/ca-certificates.crt.
|
|
31
|
+
def ssl_ca_file
|
|
32
|
+
File.join(File.dirname(File.expand_path(__FILE__)), 'data', 'ca-certificates.crt')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Current client object.
|
|
36
|
+
# client is memoized, and nullified when @api_base or @api_key is modified.
|
|
37
|
+
def client
|
|
38
|
+
@client ||= Client.new(@api_key, @api_base, @api_version)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Set api_base, the base URL of API.
|
|
42
|
+
# Configure this before sending any request.
|
|
43
|
+
# Take care when using unofficial WebPay API.
|
|
44
|
+
def api_base=(new_value)
|
|
45
|
+
@api_base = new_value
|
|
46
|
+
@client = nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Set api_key, your token for accessing API.
|
|
50
|
+
# Configure this before sending any request.
|
|
51
|
+
def api_key=(new_value)
|
|
52
|
+
@api_key = new_value
|
|
53
|
+
@client = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Get current api_base
|
|
57
|
+
def api_base
|
|
58
|
+
@api_base
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Get current api_key
|
|
62
|
+
def api_key
|
|
63
|
+
@api_key
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = account</code>
|
|
4
|
+
class Account < Entity
|
|
5
|
+
class << self
|
|
6
|
+
|
|
7
|
+
# Get the account of api_key's owner
|
|
8
|
+
# @return [Account] the account of api_key's owner
|
|
9
|
+
def retrieve
|
|
10
|
+
convert(WebPay.client.get(path))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @api private
|
|
14
|
+
# @return [String] Relative path to API root: <code>'/account'</code>
|
|
15
|
+
def path
|
|
16
|
+
'/account'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/webpay/card.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = card</code>.
|
|
4
|
+
# Card is not accessible as an API endpoint
|
|
5
|
+
class Card < Entity
|
|
6
|
+
|
|
7
|
+
# Check equality with rhs
|
|
8
|
+
# @return [Boolean] true if rhs is the same object, or it is a Card with the same fingerprint value
|
|
9
|
+
def ==(other)
|
|
10
|
+
other.equals?(self) || (other.instance_of?(self.class) && other.fingerprint == self.fingerprint)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = charge</code>
|
|
4
|
+
class Charge < Entity
|
|
5
|
+
install_class_operations :create, :retrieve, :all
|
|
6
|
+
|
|
7
|
+
# @return [String] Relative path to API root
|
|
8
|
+
# @api private
|
|
9
|
+
def self.path
|
|
10
|
+
'/charges'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Refund this charge
|
|
14
|
+
# @param [Hash] params request parameters
|
|
15
|
+
# @option params [Integer] :amount The amount to refund. Default is all amount.
|
|
16
|
+
def refund(params = {})
|
|
17
|
+
update_attributes(WebPay.client.post([path, 'refund'].join('/'), params))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Capture a not captured charge
|
|
21
|
+
# @param [Hash] params request parameters
|
|
22
|
+
# @option params [Integer] :amount The amount to capture. Default is all amount.
|
|
23
|
+
def capture(params = {})
|
|
24
|
+
update_attributes(WebPay.client.post([path, 'capture'].join('/'), params))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [String] Relative path of instance to API root
|
|
28
|
+
# @api private
|
|
29
|
+
def path
|
|
30
|
+
"/charges/#{id}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module WebPay
|
|
5
|
+
|
|
6
|
+
# API client wrapping of Faraday.
|
|
7
|
+
# Not intended to use directly.
|
|
8
|
+
class Client
|
|
9
|
+
|
|
10
|
+
# Initialize client
|
|
11
|
+
#
|
|
12
|
+
# @param api_key [String] User's secret API key
|
|
13
|
+
# @param api_base [String] the URL without trailing '/'.
|
|
14
|
+
# @param api_version [String] the path indicating API version. `/v1`.
|
|
15
|
+
#
|
|
16
|
+
# @example Client for the default endpoint
|
|
17
|
+
# Client.new('test_secret_XXXX', 'https://api.webpay.jp', '/v1')
|
|
18
|
+
def initialize(api_key, api_base, api_version)
|
|
19
|
+
ssl_options = {ca_file: WebPay.ssl_ca_file}
|
|
20
|
+
default_headers = {
|
|
21
|
+
'Authorization' => "Bearer #{api_key}",
|
|
22
|
+
'User-Agent' => "WebPay#{api_version} RubyBinding/#{WebPay::VERSION}"
|
|
23
|
+
}
|
|
24
|
+
@conn = Faraday.new(api_base, ssl: ssl_options, headers: default_headers) do |builder|
|
|
25
|
+
builder.request :url_encoded
|
|
26
|
+
builder.adapter Faraday.default_adapter
|
|
27
|
+
end
|
|
28
|
+
@api_version = api_version
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Convert faraday response to a hash by decoding JSON.
|
|
32
|
+
# This raises error if the response indicates error status.
|
|
33
|
+
#
|
|
34
|
+
# @api private
|
|
35
|
+
# @param response [Faraday::Response]
|
|
36
|
+
# @return [Hash] Raw object
|
|
37
|
+
# @raise [WebPay::WebPayError] For invalid requests (4xx) or internal server error (5xx)
|
|
38
|
+
def handle_response(response)
|
|
39
|
+
case response.status
|
|
40
|
+
when 200..299
|
|
41
|
+
begin
|
|
42
|
+
JSON.parse(response.body)
|
|
43
|
+
rescue JSON::ParserError => e
|
|
44
|
+
raise WebPay::APIConnectionError.new("Response JSON is broken. #{e.message}: #{response.body}", e)
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
raise WebPay::WebPayError.from_response(response.status, response.body)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Faraday::Connection::METHODS.each do |method|
|
|
52
|
+
define_method(method) do |url, *args|
|
|
53
|
+
begin
|
|
54
|
+
response = @conn.__send__(method, @api_version + url, *args)
|
|
55
|
+
rescue Faraday::Error::ClientError => e
|
|
56
|
+
raise WebPay::APIConnectionError.faraday_error(e)
|
|
57
|
+
end
|
|
58
|
+
handle_response(response)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = customer</code>
|
|
4
|
+
class Customer < Entity
|
|
5
|
+
install_class_operations :create, :retrieve, :all
|
|
6
|
+
|
|
7
|
+
# Attributes updated by assignment.
|
|
8
|
+
# These attributes are sent on save.
|
|
9
|
+
# Only description, card, and email are effective.
|
|
10
|
+
attr_accessor :updated_attributes
|
|
11
|
+
|
|
12
|
+
# @return [String] Relative path to API root
|
|
13
|
+
# @api private
|
|
14
|
+
def self.path
|
|
15
|
+
'/customers'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @api private
|
|
19
|
+
def initialize(attributes)
|
|
20
|
+
@updated_attributes = {}
|
|
21
|
+
super(attributes)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# <code>object['key']=</code> is wrapper for <code>object.key =</code>.
|
|
25
|
+
# Method call style is recommended.
|
|
26
|
+
# @return [Object] Given value
|
|
27
|
+
def []=(key, value)
|
|
28
|
+
send("#{key}=", value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# <code>object['key']</code> is wrapper for <code>object.key</code>.
|
|
32
|
+
# Method call style is recommended.
|
|
33
|
+
# @return [Object] The attribute's value
|
|
34
|
+
def [](key)
|
|
35
|
+
send(key)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
[:description, :card, :email].each do |attr|
|
|
39
|
+
define_method("#{attr}=") do |value|
|
|
40
|
+
@updated_attributes[attr.to_s] = value
|
|
41
|
+
end
|
|
42
|
+
define_method("#{attr}") do
|
|
43
|
+
@updated_attributes[attr.to_s] || @attributes[attr.to_s]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Send update request of modified attributes.
|
|
48
|
+
# description, card, and email are modifiable.
|
|
49
|
+
# @return [Customer] this object with attributes updated
|
|
50
|
+
def save
|
|
51
|
+
update_attributes(WebPay.client.post(path, @updated_attributes))
|
|
52
|
+
@updated_attributes = {}
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Delete this customer.
|
|
57
|
+
# This operation cannot be undone.
|
|
58
|
+
# @return [Boolean] true if operation succeeded
|
|
59
|
+
def delete
|
|
60
|
+
response = WebPay.client.delete(path)
|
|
61
|
+
response['deleted']
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @return [String] Relative path of instance to API root
|
|
65
|
+
# @api private
|
|
66
|
+
def path
|
|
67
|
+
"/customers/#{id}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# The base class for entity objects
|
|
4
|
+
# @abstract
|
|
5
|
+
class Entity
|
|
6
|
+
class << self
|
|
7
|
+
include Operations
|
|
8
|
+
|
|
9
|
+
# Convert hash API response into an entity object
|
|
10
|
+
# @param [Hash] hash Raw API response
|
|
11
|
+
# @return [Entity] An entity object corresponds to hash
|
|
12
|
+
def convert(hash)
|
|
13
|
+
converter = ResponseConverter.new
|
|
14
|
+
converter.convert(hash)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Attributes of this object.
|
|
19
|
+
# <code>method_missing</code> and <code>#[]</code> are provided to access attributes
|
|
20
|
+
attr_reader :attributes
|
|
21
|
+
|
|
22
|
+
# Initialized by ResponseConverter
|
|
23
|
+
# @api private
|
|
24
|
+
def initialize(attributes)
|
|
25
|
+
@attributes = attributes
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Boolean] true if rhs is the same object or has the same id
|
|
29
|
+
def ==(other)
|
|
30
|
+
other.equal?(self) || (other.instance_of?(self.class) && other.id == self.id)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Access attribute.
|
|
34
|
+
# Using the attribute name as a method is recommended.
|
|
35
|
+
# @return [Object] The attribute's value
|
|
36
|
+
def [](key)
|
|
37
|
+
send(key)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Provide access to attributes
|
|
41
|
+
# @return [Object] The attribute's value
|
|
42
|
+
def method_missing(method_name, *args, &block)
|
|
43
|
+
key = method_name.to_s
|
|
44
|
+
if @attributes.has_key?(key)
|
|
45
|
+
@attributes[key]
|
|
46
|
+
else
|
|
47
|
+
super
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
52
|
+
@attributes.has_key?(method_name.to_s) || super
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
def update_attributes(attributes)
|
|
57
|
+
raise "unexpected object" if attributes['object'] != @attributes['object']
|
|
58
|
+
new_object = ResponseConverter.new.convert(attributes)
|
|
59
|
+
@attributes = new_object.attributes
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = list</code>.
|
|
4
|
+
# This enumerates containing data.
|
|
5
|
+
class EntityList < Entity
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
# @return [Boolean] true if rhs is the same object or id lists of containing data are the same
|
|
9
|
+
def ==(other)
|
|
10
|
+
other.equal?(self) ||
|
|
11
|
+
(other.instance_of?(self.class) && other.data.map(&:id) == self.data.map(&:id))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Return the all entry count, not limited by <code>limit</code>.
|
|
15
|
+
# This overrides <code>Enumerable#count</code>. Not necessarily equal to the data size.
|
|
16
|
+
def count
|
|
17
|
+
@attributes['count']
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Enumerate containing data.
|
|
21
|
+
def each(&block)
|
|
22
|
+
self.data.each(&block)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/webpay/event.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Object for API response hash object with <code>hash['object'] = event</code>
|
|
4
|
+
class Event < Entity
|
|
5
|
+
install_class_operations :retrieve, :all
|
|
6
|
+
|
|
7
|
+
# @return [String] Relative path to API root
|
|
8
|
+
# @api private
|
|
9
|
+
def self.path
|
|
10
|
+
'/events'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Entity object for <code>event.data</code>
|
|
14
|
+
# This entity has <code>object</code> on which event occurred,
|
|
15
|
+
# and <code>previous_attributes</code> if some of attributes are modified on the event.
|
|
16
|
+
class Data < Entity
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# This module installs collection operations to entities.
|
|
4
|
+
# Some of <code>create</code>, <code>retrieve</code>, and <code>all</code> are defined as class methods.
|
|
5
|
+
module Operations
|
|
6
|
+
|
|
7
|
+
# Install selected operations
|
|
8
|
+
# @api private
|
|
9
|
+
def install_class_operations(*operations)
|
|
10
|
+
define_create if operations.include?(:create)
|
|
11
|
+
define_retrieve if operations.include?(:retrieve)
|
|
12
|
+
define_all if operations.include?(:all)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Define <code>create</code> method
|
|
16
|
+
# @api private
|
|
17
|
+
def define_create
|
|
18
|
+
instance_eval do
|
|
19
|
+
def create(params = {})
|
|
20
|
+
convert(WebPay.client.post(path, params))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Define <code>retrieve(id)</code> method
|
|
26
|
+
# @api private
|
|
27
|
+
def define_retrieve
|
|
28
|
+
instance_eval do
|
|
29
|
+
def retrieve(id)
|
|
30
|
+
id = id.to_s
|
|
31
|
+
if id.strip == ''
|
|
32
|
+
raise InvalidRequestError.invalid_id(id)
|
|
33
|
+
end
|
|
34
|
+
convert(WebPay.client.get([path, id].join('/')))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Define <code>all</code> method
|
|
40
|
+
# @api private
|
|
41
|
+
def define_all
|
|
42
|
+
instance_eval do
|
|
43
|
+
def all(params = {})
|
|
44
|
+
convert(WebPay.client.get(path, params))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module WebPay
|
|
2
|
+
|
|
3
|
+
# Converts raw Hash response to an entity
|
|
4
|
+
class ResponseConverter
|
|
5
|
+
|
|
6
|
+
# Converts raw Hash response to an entity.
|
|
7
|
+
# This recursively changes internal objects.
|
|
8
|
+
# @param [Hash] attributes Raw API response
|
|
9
|
+
# @return [Entity] Corresponding entity
|
|
10
|
+
def convert(attributes)
|
|
11
|
+
case attributes['object']
|
|
12
|
+
when 'card'
|
|
13
|
+
Card.new(attributes)
|
|
14
|
+
when 'charge'
|
|
15
|
+
if attributes['card']
|
|
16
|
+
attributes['card'] = convert(attributes['card'])
|
|
17
|
+
end
|
|
18
|
+
Charge.new(attributes)
|
|
19
|
+
when 'customer'
|
|
20
|
+
if attributes['active_card']
|
|
21
|
+
attributes['active_card'] = convert(attributes['active_card'])
|
|
22
|
+
end
|
|
23
|
+
Customer.new(attributes)
|
|
24
|
+
when 'token'
|
|
25
|
+
if attributes['card']
|
|
26
|
+
attributes['card'] = convert(attributes['card'])
|
|
27
|
+
end
|
|
28
|
+
Token.new(attributes)
|
|
29
|
+
when 'event'
|
|
30
|
+
if attributes['data']
|
|
31
|
+
attributes['data']['object'] = convert(attributes['data']['object'])
|
|
32
|
+
attributes['data'] = Event::Data.new(attributes['data'])
|
|
33
|
+
end
|
|
34
|
+
Event.new(attributes)
|
|
35
|
+
when 'account'
|
|
36
|
+
Account.new(attributes)
|
|
37
|
+
|
|
38
|
+
when 'list'
|
|
39
|
+
attributes['data'] ||= []
|
|
40
|
+
attributes['data'].map! { |line| convert(line) }
|
|
41
|
+
EntityList.new(attributes)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|