pin-payments 0.0.3 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +75 -24
- data/lib/pin-payments.rb +46 -1
- data/lib/pin-payments/base.rb +63 -27
- data/lib/pin-payments/card.rb +9 -13
- data/lib/pin-payments/charge.rb +23 -15
- data/lib/pin-payments/customer.rb +12 -18
- data/lib/pin-payments/refund.rb +40 -0
- data/lib/pin-payments/response.rb +36 -0
- data/pin-payments.gemspec +2 -2
- data/test/stub_responses/customers.json +1 -0
- data/test/stub_responses/{cards.json → new_card.json} +0 -0
- data/test/stub_responses/new_charge.json +26 -0
- data/test/stub_responses/new_customer.json +18 -0
- data/test/stub_responses/new_refund.json +12 -0
- data/test/stub_responses/refunds.json +19 -0
- data/test/test_helper.rb +9 -12
- data/test/unit/cards_test.rb +1 -1
- data/test/unit/charges_test.rb +1 -1
- data/test/unit/customers_test.rb +10 -1
- data/test/unit/refunds_test.rb +38 -0
- metadata +16 -4
data/README.md
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
## pin-payments
|
2
2
|
|
3
|
-
A wrapper for the [pin.net.au](https://pin.net.au/) [API](https://pin.net.au/docs/api).
|
4
|
-
|
5
|
-
gem install pin-payments
|
6
|
-
|
7
|
-
Extracted from [PayAus](http://www.payaus.com/). Still a bit rough around the edges.
|
8
|
-
|
9
|
-
MIT licensed, contributions are very welcome!
|
3
|
+
A wrapper for the [pin.net.au](https://pin.net.au/) [API](https://pin.net.au/docs/api). MIT licensed.
|
10
4
|
|
11
5
|
## Usage
|
12
6
|
|
@@ -16,47 +10,104 @@ You'll need to create an account at [pin.net.au](https://pin.net.au/) first.
|
|
16
10
|
|
17
11
|
### Setup
|
18
12
|
|
19
|
-
Create an initializer, eg. `pin.rb
|
13
|
+
Create an initializer, eg. `pin.rb`, using keys from Pin's [Your Account](https://dashboard.pin.net.au/account) page.
|
20
14
|
|
21
15
|
```ruby
|
22
|
-
Pin
|
16
|
+
Pin.setup secret_key: 'PIN_SECRET_KEY', publishable_key: 'PIN_PUBLISHABLE_KEY', mode: :test
|
23
17
|
```
|
24
18
|
|
25
|
-
|
19
|
+
The `mode` should be `:live` or `:test` depending on which API you want to access. The `publishable_key` is optional.
|
20
|
+
|
21
|
+
Alternatively, you could fetch keys from a YAML file, e.g. like this initializer:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
pin_config_path = Rails.root.join 'config', 'pin.yml'
|
25
|
+
if File.exists?(pin_config_path)
|
26
|
+
configuration = YAML.load_file(pin_config_path)
|
27
|
+
raise "No environment configured for Pin for RAILS_ENV=#{Rails.env}" unless configuration[Rails.env]
|
28
|
+
Pin.setup configuration[Rails.env].symbolize_keys
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
and then in `config/pin.yml`:
|
33
|
+
|
34
|
+
```yaml
|
35
|
+
test:
|
36
|
+
secret_key: "TEST_API_SECRET"
|
37
|
+
publishable_key: "TEST_PUBLISHABLE_KEY"
|
38
|
+
mode: "test"
|
39
|
+
|
40
|
+
development:
|
41
|
+
secret_key: "TEST_API_SECRET"
|
42
|
+
publishable_key: "TEST_PUBLISHABLE_KEY"
|
43
|
+
mode: "test"
|
44
|
+
|
45
|
+
production:
|
46
|
+
secret_key: "LIVE_API_SECRET"
|
47
|
+
publishable_key: "LIVE_PUBLISHABLE_KEY"
|
48
|
+
mode: "live"
|
49
|
+
```
|
50
|
+
|
51
|
+
This allows you to inject `pin.yml` at deployment time, so that the secret key can be kept separate from your codebase.
|
26
52
|
|
27
53
|
### Usage
|
28
54
|
|
29
|
-
You'll probably want to create a form through which users can enter their details. [Pin's guide](https://pin.net.au/docs/guides/payment-forms) will step you through this.
|
55
|
+
You'll probably want to create a form through which users can enter their details. [Pin's guide](https://pin.net.au/docs/guides/payment-forms) will step you through this. The publishable key will be necessary and, if set, can be obtained by calling `Pin.publishable_key`. You can also ask the module for the path to the javascript for the configured mode:
|
56
|
+
|
57
|
+
```erb
|
58
|
+
<%= javascript_include_tag Pin.js_url %>
|
59
|
+
```
|
30
60
|
|
31
|
-
|
61
|
+
Creating a charge is simple. In your controller:
|
32
62
|
|
33
63
|
```ruby
|
34
64
|
def create
|
35
|
-
Pin::Charge.create email: '
|
65
|
+
Pin::Charge.create email: 'user@example.com', description: '1 year of service', amount: 10000,
|
36
66
|
currency: 'AUD', ip_address: params[:ip_address], card_token: params[:card_token]
|
67
|
+
|
37
68
|
redirect_to new_payment_path, notice: "Your credit card has been charged"
|
38
69
|
end
|
39
70
|
```
|
40
71
|
|
41
|
-
This will issue a once-off charge ([API](https://pin.net.au/docs/api/charges)).
|
72
|
+
This will issue a once-off charge ([API](https://pin.net.au/docs/api/charges)).
|
73
|
+
|
74
|
+
For a recurring charge, you may wish to create a customer record at Pin. To do this, either create a `Card` object first, then a corresponding `Customer` via the [API](https://pin.net.au/docs/api/customers); or use a `card_token` returned from `Pin.js` to create a customer. Note that in either case you may activate additional compliance provisions in Pin's [Terms & Conditions](https://pin.net.au/terms).
|
42
75
|
|
43
76
|
```ruby
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
77
|
+
# this doesn't contact the API
|
78
|
+
card = Pin::Card.new number: '5520000000000000', expiry_month: '12', expiry_year: '2018', cvc: '123',
|
79
|
+
name: 'User Name', address_line1: 'GPO Box 1234', address_city: 'Melbourne', address_postcode: '3001', address_state: 'VIC', address_country: 'Australia'
|
80
|
+
|
81
|
+
# this contacts the API and returns a customer
|
82
|
+
customer = Pin::Customer.create 'user@example.com', card
|
83
|
+
|
84
|
+
# this contacts the API and returns a charge
|
85
|
+
Pin::Charge.create email: 'user@example.com', description: '1 year of service', amount: 10000,
|
86
|
+
currency: 'AUD', ip_address: '127.0.0.1', customer: customer # shorthand for customer_token: customer.token
|
49
87
|
```
|
50
88
|
|
51
89
|
You can view your customers in the [Pin dashboard](https://dashboard.pin.net.au/test/customers). This lets you charge customers regularly without asking for their credit card details each time.
|
52
90
|
|
53
91
|
```ruby
|
92
|
+
# get all customers from the API
|
54
93
|
customers = Pin::Customer.all
|
55
|
-
|
56
|
-
|
57
|
-
|
94
|
+
|
95
|
+
# find the customer you are trying to charge, assuming `current_user` is defined elsewhere
|
96
|
+
customer = customers.find {|c| c.email == current_user.email}
|
97
|
+
|
98
|
+
# create a charge for the customer
|
99
|
+
# note that using this method you will need to store the `ip_address` of the user
|
100
|
+
# generally you can store this from when you initially created the customer (via Pin.js)
|
101
|
+
Pin::Charge.create email: user.email, description: '1 month of service', amount: 19900,
|
102
|
+
currency: 'AUD', ip_address: user.ip_address, customer: customer
|
58
103
|
```
|
59
104
|
|
60
|
-
|
105
|
+
Errors from the API will result in a`Pin::APIError` exception being thrown:
|
61
106
|
|
62
|
-
|
107
|
+
```ruby
|
108
|
+
begin
|
109
|
+
response = Pin::Charge.create( ... )
|
110
|
+
rescue Pin::APIError => e
|
111
|
+
redirect_to new_payment_path, flash: { error: "Charge failed: #{e.message}" }
|
112
|
+
end
|
113
|
+
```
|
data/lib/pin-payments.rb
CHANGED
@@ -2,6 +2,51 @@ require 'httparty'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
require 'pin-payments/base'
|
5
|
+
require 'pin-payments/response'
|
5
6
|
require 'pin-payments/card'
|
6
7
|
require 'pin-payments/charge'
|
7
|
-
require 'pin-payments/customer'
|
8
|
+
require 'pin-payments/customer'
|
9
|
+
require 'pin-payments/refund'
|
10
|
+
|
11
|
+
module Pin
|
12
|
+
class Error < StandardError; end
|
13
|
+
class APIError < Error
|
14
|
+
attr_reader :code, :error, :description, :response
|
15
|
+
|
16
|
+
def initialize(response)
|
17
|
+
@code = response.code
|
18
|
+
@error = response['error']
|
19
|
+
@description = response['description']
|
20
|
+
@response = response
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#@code #@error #@description"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
attr_reader :publishable_key, :js_url, :auth
|
30
|
+
|
31
|
+
def setup(options)
|
32
|
+
raise ArgumentError, "Pin.setup wants an options hash" unless Hash === options
|
33
|
+
raise ArgumentError, "no secret key configured" unless options[:secret_key]
|
34
|
+
raise ArgumentError, "no mode configured" unless options[:mode]
|
35
|
+
|
36
|
+
@auth = {username: options[:secret_key], password: ''}
|
37
|
+
@publishable_key = options[:publishable_key]
|
38
|
+
|
39
|
+
mode = options[:mode].to_sym
|
40
|
+
uri = if mode == :live
|
41
|
+
"https://api.pin.net.au"
|
42
|
+
elsif mode == :test
|
43
|
+
"https://test-api.pin.net.au"
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Incorrect API mode! Must be :live or :test"
|
46
|
+
end
|
47
|
+
|
48
|
+
@js_url = "#{uri}/pin.js"
|
49
|
+
Pin::Base.base_uri "#{uri}/1"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/pin-payments/base.rb
CHANGED
@@ -12,39 +12,75 @@ module Pin
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def create(options, path = api_path)
|
18
|
+
response = authenticated_post(path, options)
|
19
|
+
if response.code == 201 # object created
|
20
|
+
build_instance_from_response(response)
|
21
|
+
else
|
22
|
+
raise Pin::APIError.new(response)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def all(options = {})
|
27
|
+
options = {path: api_path, page: 1}.merge(options)
|
28
|
+
paging = "page=#{options[:page]}" unless options[:page] == 1
|
29
|
+
build_collection_from_response(authenticated_get(options[:path], paging))
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_pages(options = {})
|
33
|
+
options = options.merge(path: api_path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def first(options = {})
|
37
|
+
all(options).first
|
38
|
+
end
|
39
|
+
def last(options = {})
|
40
|
+
all(options).last
|
41
|
+
end
|
27
42
|
|
43
|
+
def find(token, options = {})
|
44
|
+
options = options.merge(path: api_path)
|
45
|
+
build_instance_from_response(authenticated_get("#{options[:path]}/#{token}"))
|
46
|
+
end
|
47
|
+
|
28
48
|
protected
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
49
|
+
|
50
|
+
def auth
|
51
|
+
Pin.auth
|
52
|
+
end
|
53
|
+
|
54
|
+
def api_path
|
55
|
+
short = if i = name.rindex('::')
|
56
|
+
name[(i+2)..-1]
|
57
|
+
else
|
58
|
+
name
|
59
|
+
end
|
60
|
+
"/#{short}s".downcase
|
61
|
+
end
|
62
|
+
|
63
|
+
def authenticated_post(url, body)
|
64
|
+
post(url, body: body, basic_auth: auth)
|
65
|
+
end
|
66
|
+
def authenticated_get(url, query = nil)
|
67
|
+
get(url, query: query, basic_auth: auth)
|
68
|
+
end
|
35
69
|
|
36
|
-
|
37
|
-
|
38
|
-
|
70
|
+
def build_instance_from_response(response)
|
71
|
+
new(response.parsed_response['response'])
|
72
|
+
end
|
39
73
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
74
|
+
def build_collection_from_response(response)
|
75
|
+
models = []
|
76
|
+
if response.code == 200
|
77
|
+
response.parsed_response['response'].each do |model|
|
78
|
+
models << new(model)
|
79
|
+
end
|
45
80
|
end
|
81
|
+
pg = response.parsed_response['pagination']
|
82
|
+
CollectionResponse.new(models, pg['per_page'], pg['pages'], pg['current'])
|
46
83
|
end
|
47
|
-
models
|
48
84
|
end
|
49
85
|
end
|
50
86
|
end
|
data/lib/pin-payments/card.rb
CHANGED
@@ -15,19 +15,15 @@ module Pin
|
|
15
15
|
hash
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
build_instance_from_response(response)
|
28
|
-
else
|
29
|
-
# handle the error
|
30
|
-
false
|
18
|
+
class << self
|
19
|
+
# options should be a hash with the following keys:
|
20
|
+
# :number, :expiry_month, :expiry_year, :cvc, :name, :address_line1,
|
21
|
+
# :address_city, :address_postcode, :address_state, :address_country
|
22
|
+
#
|
23
|
+
# it can also have the following optional keys:
|
24
|
+
# :address_line2
|
25
|
+
def create(options = {})
|
26
|
+
super(options)
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
data/lib/pin-payments/charge.rb
CHANGED
@@ -6,25 +6,33 @@ module Pin
|
|
6
6
|
:amount_refunded, :total_fees, :merchant_entitlement, :refund_pending,
|
7
7
|
:success, :status_message, :error_message, :transfer, :created_at
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
attr_accessor :refunds
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# options should be a hash with the following params
|
13
|
+
# email, description, amount, currency, ip_address are mandatory
|
14
|
+
# identifier must be a hash, can take the forms
|
15
|
+
# {card: <Pin::Card>}
|
16
|
+
# {card_token: String<"...">}
|
17
|
+
# {customer_token: String<"...">}
|
18
|
+
# {customer: <Pin::Customer>}
|
19
|
+
# eg. {email: 'user@example.com', description: 'One month subscription', amount: 19900, currency: 'USD', ip_address: '192.0.0.1', customer_token: 'asdf'}
|
20
|
+
def create(options = {})
|
21
|
+
options[:customer_token] = options.delete(:customer).token unless options[:customer].nil?
|
22
|
+
super(options)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
|
-
|
23
|
-
|
26
|
+
# find all refunds for the current Charge object
|
27
|
+
# returns a list of Refunds
|
28
|
+
def refunds
|
29
|
+
Refund.all(token)
|
24
30
|
end
|
25
31
|
|
26
|
-
|
27
|
-
|
32
|
+
# creates a refund for this Charge
|
33
|
+
# refunds the full amount of the charge by default, provide an amount in cents to override
|
34
|
+
def refund!(amnt = nil)
|
35
|
+
Refund.create(token, amnt)
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
@@ -2,25 +2,19 @@ module Pin
|
|
2
2
|
class Customer < Base
|
3
3
|
attr_accessor :email, :created_at, :token, :card
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
class << self
|
6
|
+
# email should be a string
|
7
|
+
# card_or_token can be a Pin::Card object
|
8
|
+
# or a card_token (as a string)
|
9
|
+
def create(email, card_or_token)
|
10
|
+
options = if card_or_token.respond_to?(:to_hash) # card
|
11
|
+
{card: card_or_token.to_hash}
|
12
|
+
else # token
|
13
|
+
{card_token: card_or_token}
|
14
|
+
end.merge(email: email)
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def self.all # TODO: pagination
|
19
|
-
build_collection_from_response(authenticated_get('/customers'))
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.find(token)
|
23
|
-
build_instance_from_response(authenticated_get("/customers/#{token}"))
|
16
|
+
super(options)
|
17
|
+
end
|
24
18
|
end
|
25
19
|
end
|
26
20
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Pin
|
2
|
+
class Refund < Base
|
3
|
+
attr_accessor :token,
|
4
|
+
:amount, :currency, :charge,
|
5
|
+
:success, :error_message, :created_at
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# provide a charge object, or charge ID, and it will be refunded
|
9
|
+
# optionally provide an amount in cents, greater than equal to 100, to refund
|
10
|
+
# defaults to the full amount of the charge
|
11
|
+
def create(charge_or_charge_id, amount = nil)
|
12
|
+
raise "`amount` must be greater than or equal to 100" if !amount.nil? && amount < 100
|
13
|
+
|
14
|
+
super({amount: amount}, path_for(charge_or_charge_id))
|
15
|
+
end
|
16
|
+
|
17
|
+
def all(charge_or_charge_id)
|
18
|
+
super(path: path_for(charge_or_charge_id))
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
def api_path
|
23
|
+
"charges/%s/refunds"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def path_for(charge_or_charge_id)
|
28
|
+
api_path % parse_charge_id(charge_or_charge_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_charge_id(charge_or_charge_id)
|
32
|
+
if charge_or_charge_id.respond_to?(:token) # charge
|
33
|
+
charge_or_charge_id.token
|
34
|
+
else # already an ID
|
35
|
+
charge_or_charge_id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Pin
|
2
|
+
class CollectionResponse
|
3
|
+
attr_reader :collection, :page_count, :per_page, :page
|
4
|
+
|
5
|
+
def initialize(collection, per_page, page_count, current_page)
|
6
|
+
@collection = collection
|
7
|
+
@page_count = page_count
|
8
|
+
@per_page = per_page
|
9
|
+
@page = current_page
|
10
|
+
end
|
11
|
+
|
12
|
+
def first_page?
|
13
|
+
@page == 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def last_page?
|
17
|
+
@page == @page_count
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_page?
|
21
|
+
@page_count > 1 && !last_page?
|
22
|
+
end
|
23
|
+
|
24
|
+
def previous_page?
|
25
|
+
@page_count > 1 && !first_page?
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(meth, *args, &block)
|
29
|
+
if collection.respond_to?(meth)
|
30
|
+
collection.send(meth, *args, &block)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/pin-payments.gemspec
CHANGED
@@ -4,8 +4,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'pin-payments'
|
7
|
-
s.version = '
|
8
|
-
s.date = '2013-
|
7
|
+
s.version = '1.0'
|
8
|
+
s.date = '2013-08-06'
|
9
9
|
s.summary = "Pin Payments API wrapper"
|
10
10
|
s.description = "A wrapper for the Pin Payments (https://pin.net.au/) API"
|
11
11
|
s.authors = ["Alex Ghiculescu"]
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"token": "ch_lfUYEBK14zotCTykezJkfg",
|
4
|
+
"success": true,
|
5
|
+
"amount": 400,
|
6
|
+
"currency": null,
|
7
|
+
"description": "test charge",
|
8
|
+
"email": "roland@pin.net.au",
|
9
|
+
"ip_address": "203.192.1.172",
|
10
|
+
"created_at": "2012-06-20T03:10:49Z",
|
11
|
+
"status_message": "Success!",
|
12
|
+
"error_message": null,
|
13
|
+
"card": {
|
14
|
+
"token": "card_nytGw7koRg23EEp9NTmz9w",
|
15
|
+
"display_number": "XXXX-XXXX-XXXX-0000",
|
16
|
+
"scheme": "master",
|
17
|
+
"address_line1": "42 Sevenoaks St",
|
18
|
+
"address_line2": null,
|
19
|
+
"address_city": "Lathlain",
|
20
|
+
"address_postcode": "6454",
|
21
|
+
"address_state": "WA",
|
22
|
+
"address_country": "Australia"
|
23
|
+
},
|
24
|
+
"transfer": null
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"token": "cus_XZg1ULpWaROQCOT5PdwLkQ",
|
4
|
+
"email": "roland@pin.net.au",
|
5
|
+
"created_at": "2012-06-22T06:27:33Z",
|
6
|
+
"card": {
|
7
|
+
"token": "card_nytGw7koRg23EEp9NTmz9w",
|
8
|
+
"display_number": "XXXX-XXXX-XXXX-0000",
|
9
|
+
"scheme": "master",
|
10
|
+
"address_line1": "42 Sevenoaks St",
|
11
|
+
"address_line2": null,
|
12
|
+
"address_city": "Lathlain",
|
13
|
+
"address_postcode": "6454",
|
14
|
+
"address_state": "WA",
|
15
|
+
"address_country": "Australia"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
|
4
|
+
"success": null,
|
5
|
+
"amount": 400,
|
6
|
+
"currency": "AUD",
|
7
|
+
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
|
8
|
+
"created_at": "2012-10-27T13:00:00Z",
|
9
|
+
"error_message": null,
|
10
|
+
"status_message": "Pending"
|
11
|
+
}
|
12
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"response": [
|
3
|
+
{
|
4
|
+
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
|
5
|
+
"success": null,
|
6
|
+
"amount": 400,
|
7
|
+
"currency": "AUD",
|
8
|
+
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
|
9
|
+
"created_at": "2012-10-27T13:00:00Z",
|
10
|
+
"error_message": null,
|
11
|
+
"status_message": "Pending"
|
12
|
+
}
|
13
|
+
],
|
14
|
+
"pagination": {
|
15
|
+
"current": 1,
|
16
|
+
"per_page": 25,
|
17
|
+
"count": 1
|
18
|
+
}
|
19
|
+
}
|
data/test/test_helper.rb
CHANGED
@@ -11,13 +11,14 @@ module TestHelper
|
|
11
11
|
SECRET_KEY = ENV["PIN_SECRET_KEY"] || "fake_key"
|
12
12
|
PIN_ENV = ENV["PIN_ENV"] || :test
|
13
13
|
|
14
|
-
Pin
|
14
|
+
Pin.setup(secret_key: SECRET_KEY, mode: PIN_ENV)
|
15
15
|
|
16
16
|
def get_file(filename)
|
17
17
|
File.new(File.dirname(__FILE__) + "/stub_responses/" + filename)
|
18
18
|
end
|
19
19
|
|
20
|
-
def get_record_json(type, token = nil)
|
20
|
+
def get_record_json(type, new_record = false, token = nil)
|
21
|
+
type = "new_#{type.singularize}" if new_record
|
21
22
|
if token.nil?
|
22
23
|
get_file("#{type}.json")
|
23
24
|
else
|
@@ -27,24 +28,20 @@ module TestHelper
|
|
27
28
|
|
28
29
|
def mock_get(model_name, do_each = true)
|
29
30
|
stub_request(:get, /#{model_name.downcase}$/).to_return(body: get_record_json(model_name.downcase.pluralize), status: 200, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
31
|
+
stub_request(:get, /#{model_name.downcase}\?page=[0-9]$/).to_return(body: get_record_json(model_name.downcase.pluralize), status: 200, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
30
32
|
if do_each
|
31
33
|
Pin.const_get(model_name.singularize).all.each do |record|
|
32
|
-
stub_request(:get, /#{model_name.downcase}\/#{record.token}$/).to_return(body: get_record_json(model_name.downcase.singularize, record.token), status: 200, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
34
|
+
stub_request(:get, /#{model_name.downcase}\/#{record.token}$/).to_return(body: get_record_json(model_name.downcase.singularize, false, record.token), status: 200, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
def mock_post(model_name
|
38
|
-
stub_request(:post, /#{model_name.downcase}$/).to_return(body: get_record_json(model_name.downcase.pluralize), status: 201, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
39
|
-
if do_each
|
40
|
-
Pin.const_get(model_name.singularize).all.each do |record|
|
41
|
-
stub_request(:post, /#{model_name.downcase}\/#{record.token}$/).to_return(body: get_record_json(model_name.downcase.singularize, record.token), status: 201, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
42
|
-
end
|
43
|
-
end
|
39
|
+
def mock_post(model_name)
|
40
|
+
stub_request(:post, /#{model_name.downcase}$/).to_return(body: get_record_json(model_name.downcase.pluralize, true), status: 201, headers: {'Content-Type' => 'application/json; charset=utf-8'})
|
44
41
|
end
|
45
42
|
|
46
|
-
def mock_api(model_name)
|
47
|
-
mock_get(model_name)
|
43
|
+
def mock_api(model_name, do_each = true)
|
44
|
+
mock_get(model_name, do_each)
|
48
45
|
mock_post(model_name)
|
49
46
|
end
|
50
47
|
end
|
data/test/unit/cards_test.rb
CHANGED
data/test/unit/charges_test.rb
CHANGED
data/test/unit/customers_test.rb
CHANGED
@@ -5,7 +5,7 @@ class CustomersTest < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
mock_api('Customers')
|
8
|
-
mock_post('Cards'
|
8
|
+
mock_post('Cards')
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_get_all # for some reason `test "get all" do` wasn't working...
|
@@ -17,6 +17,15 @@ class CustomersTest < Test::Unit::TestCase
|
|
17
17
|
assert_not_nil customer
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_get_pages_of_customers
|
21
|
+
customers = Pin::Customer.all(page: 1)
|
22
|
+
assert_equal 1, customers.page
|
23
|
+
|
24
|
+
# TODO: mock this
|
25
|
+
#customers = Pin::Customer.all(page: 2)
|
26
|
+
#assert_equal 2, customers.page
|
27
|
+
end
|
28
|
+
|
20
29
|
def test_create_customer_with_card
|
21
30
|
card = Pin::Card.new number: '5520000000000000', expiry_month: '12', expiry_year: '2014', cvc: '123', name: 'Roland Robot', address_line1: '42 Sevenoaks St', address_city: 'Lathlain', address_postcode: '6454', address_state: 'WA', address_country: 'Australia'
|
22
31
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RefundsTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
mock_api('Charges')
|
8
|
+
mock_api('Refunds', false)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_get_all_with_charge
|
12
|
+
charge = Pin::Charge.first
|
13
|
+
|
14
|
+
refunds = Pin::Refund.all(charge)
|
15
|
+
assert_equal 1, refunds.length
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_get_all_with_charge_token
|
19
|
+
charge = Pin::Charge.first
|
20
|
+
|
21
|
+
refunds = Pin::Refund.all(charge.token)
|
22
|
+
assert_equal 1, refunds.length
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_get_refunds_as_charge_method
|
26
|
+
charge = Pin::Charge.first
|
27
|
+
|
28
|
+
refunds = charge.refunds
|
29
|
+
assert_equal 1, refunds.length
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_create_refund
|
33
|
+
charge = Pin::Charge.first
|
34
|
+
|
35
|
+
refund = charge.refund!
|
36
|
+
assert_not_nil refund
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pin-payments
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '1.0'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -75,16 +75,23 @@ files:
|
|
75
75
|
- lib/pin-payments/card.rb
|
76
76
|
- lib/pin-payments/charge.rb
|
77
77
|
- lib/pin-payments/customer.rb
|
78
|
+
- lib/pin-payments/refund.rb
|
79
|
+
- lib/pin-payments/response.rb
|
78
80
|
- pin-payments.gemspec
|
79
|
-
- test/stub_responses/cards.json
|
80
81
|
- test/stub_responses/charges.json
|
81
82
|
- test/stub_responses/customers.json
|
83
|
+
- test/stub_responses/new_card.json
|
84
|
+
- test/stub_responses/new_charge.json
|
85
|
+
- test/stub_responses/new_customer.json
|
86
|
+
- test/stub_responses/new_refund.json
|
82
87
|
- test/stub_responses/records/charge-ch_lfUYEBK14zotCTykezJkfg.json
|
83
88
|
- test/stub_responses/records/customer-cus_XZg1ULpWaROQCOT5PdwLkQ.json
|
89
|
+
- test/stub_responses/refunds.json
|
84
90
|
- test/test_helper.rb
|
85
91
|
- test/unit/cards_test.rb
|
86
92
|
- test/unit/charges_test.rb
|
87
93
|
- test/unit/customers_test.rb
|
94
|
+
- test/unit/refunds_test.rb
|
88
95
|
homepage: https://github.com/ghiculescu/pin-payments
|
89
96
|
licenses:
|
90
97
|
- MIT
|
@@ -111,12 +118,17 @@ signing_key:
|
|
111
118
|
specification_version: 3
|
112
119
|
summary: Pin Payments API wrapper
|
113
120
|
test_files:
|
114
|
-
- test/stub_responses/cards.json
|
115
121
|
- test/stub_responses/charges.json
|
116
122
|
- test/stub_responses/customers.json
|
123
|
+
- test/stub_responses/new_card.json
|
124
|
+
- test/stub_responses/new_charge.json
|
125
|
+
- test/stub_responses/new_customer.json
|
126
|
+
- test/stub_responses/new_refund.json
|
117
127
|
- test/stub_responses/records/charge-ch_lfUYEBK14zotCTykezJkfg.json
|
118
128
|
- test/stub_responses/records/customer-cus_XZg1ULpWaROQCOT5PdwLkQ.json
|
129
|
+
- test/stub_responses/refunds.json
|
119
130
|
- test/test_helper.rb
|
120
131
|
- test/unit/cards_test.rb
|
121
132
|
- test/unit/charges_test.rb
|
122
133
|
- test/unit/customers_test.rb
|
134
|
+
- test/unit/refunds_test.rb
|