pin-payments 0.0.3 → 1.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/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
|