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 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). Available via [RubyGems](http://rubygems.org/gems/pin-payments):
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::Base.setup ENV['PIN_SECRET_KEY'], ENV['PIN_ENV']
16
+ Pin.setup secret_key: 'PIN_SECRET_KEY', publishable_key: 'PIN_PUBLISHABLE_KEY', mode: :test
23
17
  ```
24
18
 
25
- You can get your secret key from Pin's [Your Account](https://dashboard.pin.net.au/account) page. The second argument should be "live" or "test" depending on which API you want to access.
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
- Then, in your controller:
61
+ Creating a charge is simple. In your controller:
32
62
 
33
63
  ```ruby
34
64
  def create
35
- Pin::Charge.create email: 'alex@payaus.com', description: '1 month of service', amount: 19900,
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)). Alternatively, you may wish to create a customer. To do this, create a `Card` object first, then a corresponding `Customer` via the [API](https://pin.net.au/docs/api/customers).
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
- card = Pin::Card.new number: '5520000000000000', expiry_month: '12', expiry_year: '2014', cvc: '123',
45
- name: 'Roland Robot', address_line1: '42 Sevenoaks St', address_city: 'Lathlain', address_postcode: '6454', address_state: 'WA', address_country: 'Australia'
46
- customer = Pin::Customer.create 'alex@payaus.com', card # this contacts the API
47
- Pin::Charge.create email: 'alex@payaus.com', description: '1 month of service', amount: 19900,
48
- currency: 'AUD', ip_address: '203.192.1.172', customer: customer # shorthand for customer_token: customer.token
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
- customer = customers.find {|c| c.email == user.email} # assume user is the user you are trying to charge
56
- Pin::Charge.create email: user.email, description: '1 month of service', amount: 19900, currency: 'AUD',
57
- ip_address: user.ip_address, customer: customer
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
- ## Credits
105
+ Errors from the API will result in a`Pin::APIError` exception being thrown:
61
106
 
62
- https://github.com/ghiculescu/pin-payments/graphs/contributors
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
+ ```
@@ -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
@@ -12,39 +12,75 @@ module Pin
12
12
  end
13
13
  end
14
14
 
15
- def self.setup(key, mode = :live)
16
- @@auth = {username: key, password: ''}
17
- mode = mode.to_sym
18
- uri = if mode == :test
19
- "https://test-api.pin.net.au/1"
20
- elsif mode == :live
21
- "https://api.pin.net.au/1"
22
- else
23
- raise "Incorrect API mode! Must be :live or :test (leave blank for :live)."
24
- end
25
- base_uri uri
26
- end
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
- def self.authenticated_post(url, body)
30
- post(url, body: body, basic_auth: @@auth)
31
- end
32
- def self.authenticated_get(url, query = nil)
33
- get(url, query: query, basic_auth: @@auth)
34
- end
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
- def self.build_instance_from_response(response)
37
- new(response.parsed_response['response'])
38
- end
70
+ def build_instance_from_response(response)
71
+ new(response.parsed_response['response'])
72
+ end
39
73
 
40
- def self.build_collection_from_response(response)
41
- models = []
42
- if response.code == 200
43
- response.parsed_response['response'].each do |model|
44
- models << new(model)
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
@@ -15,19 +15,15 @@ module Pin
15
15
  hash
16
16
  end
17
17
 
18
- # options should be a hash with the following keys:
19
- # :number, :expiry_month, :expiry_year, :cvc, :name, :address_line1,
20
- # :address_city, :address_postcode, :address_state, :address_country
21
- #
22
- # it can also have the following optional keys:
23
- # :address_line2
24
- def self.create(options = {})
25
- response = authenticated_post '/cards', options
26
- if response.code == 201 # card created
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
@@ -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
- # options should be a hash with the following params
10
- # email, description, amount, currency, ip_address are mandatory
11
- # identifier must be a hash, can take the forms
12
- # {card: <Pin::Card>}
13
- # {card_token: String<"...">}
14
- # {customer_token: String<"...">}
15
- # {customer: <Pin::Customer>}
16
- # eg. {email: 'alex@payaus.com', description: '1 month of PayAus', amount: 19900, currency: 'AUD', ip_address: '203.192.1.172', customer_token: 'asdf'}
17
- def self.create(options = {})
18
- options[:customer_token] = options.delete(:customer).token unless options[:customer].nil?
19
- build_instance_from_response(authenticated_post('/charges', options))
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
- def self.all # TODO: pagination
23
- build_collection_from_response(authenticated_get('/charges'))
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
- def self.find(token)
27
- build_instance_from_response(authenticated_get("/charges/#{token}"))
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
- # email should be a string
6
- # card_or_token can be a Pin::Card object
7
- # or a card_token (as a string)
8
- def self.create(email, card_or_token)
9
- options = if card_or_token.respond_to?(:to_hash) # card
10
- {card: card_or_token.to_hash}
11
- else # token
12
- {card_token: card_or_token}
13
- end.merge(email: email)
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
- build_instance_from_response(authenticated_post('/customers', options))
16
- end
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
@@ -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 = '0.0.3'
8
- s.date = '2013-07-26'
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"]
@@ -20,6 +20,7 @@
20
20
  "pagination": {
21
21
  "current": 1,
22
22
  "per_page": 25,
23
+ "pages": 1,
23
24
  "count": 1
24
25
  }
25
26
  }
@@ -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
+ }
@@ -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::Base.setup SECRET_KEY, PIN_ENV
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, do_each = true)
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
@@ -4,7 +4,7 @@ class CardsTest < Test::Unit::TestCase
4
4
  include TestHelper
5
5
 
6
6
  def setup
7
- mock_post('Cards', false)
7
+ mock_post('Cards')
8
8
  end
9
9
 
10
10
  def test_create
@@ -4,7 +4,7 @@ class ChargesTest < Test::Unit::TestCase
4
4
  include TestHelper
5
5
 
6
6
  def setup
7
- mock_post('Cards', false)
7
+ mock_post('Cards')
8
8
  mock_api('Charges')
9
9
  mock_api('Customers')
10
10
  end
@@ -5,7 +5,7 @@ class CustomersTest < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
7
  mock_api('Customers')
8
- mock_post('Cards', false)
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: 0.0.3
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-07-26 00:00:00.000000000 Z
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