pin_payment 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c7b070b4634a8b7e1db258cf2453aed51f23393
4
- data.tar.gz: 25fb4b21844ee2142355082d11ea250beea9fec0
3
+ metadata.gz: 0b482e0e3054497d152ef8302a1fa9af339834cf
4
+ data.tar.gz: 7394ef6e8624ac96d1db2b1e726141c0a918e4df
5
5
  SHA512:
6
- metadata.gz: df77eb656111fea702bf69ee97840b97cfd4e39f90663a9045f4e6c4b93ec1695523d764453630ef8fa213406110f3744ff29073e2ee0bf2212d677fdf66f628
7
- data.tar.gz: e1d6ae83373cf53c7f9ef981496eca10cb97e5e447dbc510fcb4fba6850156f277c1abae798ca155b492768cdc87705420bcb0d501336a7eb1a5411dc0db17e9
6
+ metadata.gz: 719872f68f5a3bdcec2f6be1368bb3a11f71281508b8b05f9a1fcc527b6c520f0a9d434e04a5b3f2bf0110dd43f5735e792c13760e67bb078a4dab931a3a774d
7
+ data.tar.gz: 66826324dcb94dc9bca096c36037c23d452a64068f6545dc414edbed98d98aa053e25103185fdba09db8187e781c7f449facc90111b65fbded2111fda85d00f1
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
1
  /.bundle
2
2
  /gems
3
3
  /pkg
4
+ *.swp
5
+ /.yardoc
6
+ /doc
data/Gemfile.lock CHANGED
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pin_payment (0.0.5)
4
+ pin_payment (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  fakeweb (1.3.0)
10
10
  rake (10.0.4)
11
+ yard (0.8.6.1)
11
12
 
12
13
  PLATFORMS
13
14
  ruby
@@ -16,3 +17,4 @@ DEPENDENCIES
16
17
  fakeweb
17
18
  pin_payment!
18
19
  rake
20
+ yard
data/README.md CHANGED
@@ -34,7 +34,7 @@ task is up to you), if you are only doing a single transaction, this step is
34
34
  not required (but recommended).
35
35
 
36
36
  ```ruby
37
- customer = PinPayment::Customer.create(email: 'foo@example.com', card_token: params[:card_token])
37
+ customer = PinPayment::Customer.create('foo@example.com', params[:card_token])
38
38
  ```
39
39
 
40
40
  The important information from the returned object is `customer.token`. You
@@ -45,12 +45,12 @@ Now you can create charges.
45
45
 
46
46
  ```ruby
47
47
  charge = PinPayment::Charge.create(
48
- customer_token: customer.token, # you can optionally pass a card_token instead
49
- email: customer.email,
50
- amount: 1000,
51
- currency: 'USD',
52
- description: 'Widgets',
53
- ip_address: request.ip
48
+ customer: customer, # or you can pass customer.token, either way
49
+ email: customer.email,
50
+ amount: 1000,
51
+ currency: 'USD', # only AUD and USD are supported by pin.net.au
52
+ description: 'Widgets',
53
+ ip_address: request.ip
54
54
  )
55
55
 
56
56
  if charge.success?
@@ -58,17 +58,81 @@ if charge.success?
58
58
  end
59
59
  ```
60
60
 
61
+ If you don't want to create customer records and just want to create once of
62
+ charges with the credit card data, this is quite simple also. You can do this
63
+ in 2 steps if you like, or 1.
64
+
65
+ First create the card
66
+
67
+ ```ruby
68
+ card = PinPayment::Card.create(
69
+ number: 5520000000000000,
70
+ expiry_month: 5,
71
+ expiry_year: 2014,
72
+ cvc: 123,
73
+ name: 'Roland Robot',
74
+ address_line1: '42 Sevenoaks St',
75
+ address_city: 'Lathlain',
76
+ address_postcode: 6454,
77
+ address_state: 'WA',
78
+ address_country: 'Australia'
79
+ )
80
+ ```
81
+
82
+ Once you have created the card via the API, you will have a `PinPayment::Card`
83
+ object, and you can use the charge example code above and replace the customer
84
+ key in the has with `:card`. The same principle applies here, you can pass
85
+ `:card` into the charge creation as the card object, or as a simple string being
86
+ the card token.
87
+
88
+ Alternatively, you can skip the card creation step, and pass `:card` to the
89
+ charge creation as a hash itself, it will create the card for you as part of the
90
+ charge process. Example
91
+
92
+ ```ruby
93
+ charge = PinPayment::Charge.create(
94
+ email: customer.email,
95
+ amount: 1000,
96
+ currency: 'USD', # only AUD and USD are supported by pin.net.au
97
+ description: 'Widgets',
98
+ ip_address: request.ip
99
+ card: {
100
+ number: 5520000000000000,
101
+ expiry_month: 5,
102
+ expiry_year: 2014,
103
+ cvc: 123,
104
+ name: 'Roland Robot',
105
+ address_line1: '42 Sevenoaks St',
106
+ address_city: 'Lathlain',
107
+ address_postcode: 6454,
108
+ address_state: 'WA',
109
+ address_country: 'Australia'
110
+ }
111
+ )
112
+ ```
113
+
114
+ You can refund charges as well, either directly on the charge object with
115
+ `charge.refund!` or you can pass a charge object or token directory into
116
+ `PinPayment::Refund.create`
117
+
118
+ Both the Charge and Customer objects have an `all` method that you can use to
119
+ iterate over your customers and charges. They simply return an array of their
120
+ respective objects.
121
+
122
+ They also both of course have a `find` method which takes a single argument,
123
+ being the token. For this reason I highly suggest storing `charge.token` as your
124
+ payment reference whenever you are creating payments. As well as storing
125
+ `customer.token` against your customers in your own customer database.
126
+
61
127
  ## TODO
62
128
 
63
- * `PinPayment::Card` is non existent. I haven't had a use for it myself as yet, it
64
- would be easy to build and will do so if I ever see the need. But as per the
65
- [guide in the documentation](https://pin.net.au/docs/guides/payment-forms),
66
- for a web interface it is much better to have the `card_token` created in
67
- the javascript and never have the responsibility of credit card info being
68
- sent directly to your server.
69
- * Neither of the models support being handed a `card` hash. The API supports
70
- doing so, but as above, I've not yet had the need and have always had a
71
- `card_token` handy to pass in.
129
+ * The `all` methods need to deal with pagination.
130
+ * Implement `PinPayment::Customer.charges`
131
+ * Implement `PinPayment::Charge.search`
132
+ * There is more info about a charge in a response than what the API says.
133
+ E.g. there is info about the fees, refund status, and trasfer status. Need
134
+ to find out what this data is all about. Since it's undocumented, I am
135
+ hesitent to implement anything that relies on it as yet.
72
136
 
73
137
  ## Testing
74
138
 
@@ -77,8 +141,15 @@ responses that I know the API gives. We're not really here to test the output of
77
141
  the API, I think we can safely assume it will always give the same output for
78
142
  the same input, and I don't really want to spam their service every time someone
79
143
  runs the test suite. Nor do I want to hard code my test API keys or expect every
80
- developer to create a pin account. Suggestions on improvement here are welcome
81
- though.
144
+ developer to create a pin account.
145
+
146
+ Having said that, you can simply jump into `test/test_helper.rb` and comment out
147
+ the line that sets up fakeweb, then you can uncomment the lines below that and
148
+ put your own pin.net.au test API keys into the code and run the tests. Note
149
+ however that this will create a large amount of customers and charges in your
150
+ test dashboard on pin.net.au.
151
+
152
+ Suggestions on improvement here are welcome though.
82
153
 
83
154
  ## Contributing
84
155
 
@@ -4,21 +4,25 @@ require 'pin_payment/error'
4
4
  module PinPayment
5
5
  class Base
6
6
 
7
+ def initialize token, options = {}
8
+ self.token = token
9
+ self.class.parse_card_data(options).each{|k,v| send("#{k}=", v) if self.class.attributes.include?(k.to_sym) }
10
+ end
11
+
7
12
  protected
8
13
 
9
- def self.post uri, options
14
+ def self.post uri, options = {}
10
15
  fetch Net::HTTP::Post, uri, options
11
16
  end
12
17
 
13
- def self.put uri, options
18
+ def self.put uri, options = {}
14
19
  fetch Net::HTTP::Put, uri, options
15
20
  end
16
21
 
17
- def self.get uri, options
22
+ def self.get uri, options = {}
18
23
  fetch Net::HTTP::Get, uri, options
19
24
  end
20
25
 
21
- # TODO: Accept card as a hash that would create the card at the same time as the charge
22
26
  def self.fetch klass, uri, options
23
27
  client = Net::HTTP.new(uri.host, uri.port)
24
28
  client.use_ssl = true
@@ -36,7 +40,84 @@ module PinPayment
36
40
  raise Error::InvalidResponse.new(e.message)
37
41
  end
38
42
  raise(Error.create(response['error'], response['error_description'], response['messages'])) if response['error']
39
- response['response']
43
+ response = response['response']
44
+ response.is_a?(Hash) ? parse_object_tokens(response) : response.map{|x| parse_object_tokens(x) }
45
+ end
46
+
47
+ def self.parse_card_data hash
48
+ hash = hash.dup
49
+ card = hash.delete('card') if hash['card']
50
+ card = hash.delete(:card) if hash[:card]
51
+ token = hash.delete('card_token') if hash['card_token']
52
+ token = hash.delete(:card_token) if hash[:card_token]
53
+ if card.is_a?(Card) and token and !card.token
54
+ card.token = token
55
+ elsif card.is_a?(Hash)
56
+ card = Card.new(token || card[:token] || card['token'], card)
57
+ elsif card.is_a?(String)
58
+ card = Card.new(card)
59
+ elsif token
60
+ card = Card.new(token)
61
+ end
62
+ hash['card'] = card if card
63
+ hash
64
+ end
65
+
66
+ def self.parse_customer_data hash
67
+ hash = hash.dup
68
+ customer = hash.delete('customer') if hash['customer']
69
+ customer = hash.delete(:customer) if hash[:customer]
70
+ token = hash.delete('customer_token') if hash['customer_token']
71
+ token = hash.delete(:customer_token) if hash[:customer_token]
72
+ if customer.is_a?(Customer) and token and !customer.token
73
+ customer.token = token
74
+ elsif customer.is_a?(String)
75
+ customer = Customer.new(customer)
76
+ elsif token
77
+ customer = Customer.new(token)
78
+ end
79
+ hash['customer'] = customer if customer
80
+ hash
81
+ end
82
+
83
+ def self.parse_charge_data hash
84
+ hash = hash.dup
85
+ charge = hash.delete('charge') if hash['charge']
86
+ charge = hash.delete(:charge) if hash[:charge]
87
+ token = hash.delete('charge_token') if hash['charge_token']
88
+ token = hash.delete(:charge_token) if hash[:charge_token]
89
+ if charge.is_a?(Charge) and token and !charge.token
90
+ charge.token = token
91
+ elsif charge.is_a?(String)
92
+ charge = Charge.new(charge)
93
+ elsif token
94
+ charge = Charge.new(token)
95
+ end
96
+ hash['charge'] = charge if charge
97
+ hash
98
+ end
99
+
100
+ def self.parse_object_tokens hash
101
+ parse_charge_data(parse_customer_data(parse_card_data(hash)))
102
+ end
103
+
104
+ def self.parse_options_for_request attributes, options
105
+ attributes = attributes.map(&:to_s)
106
+ options = parse_object_tokens(options.select{|k| attributes.include?(k.to_s) })
107
+
108
+ if card = options.delete('card')
109
+ if card.token
110
+ options['card_token'] = card.token
111
+ else
112
+ # Ruby's Net::HTTP#set_form_data doesn't deal with nested hashes :(
113
+ card.to_hash.each{|k,v| options["card[#{k}]"] = v }
114
+ end
115
+ end
116
+
117
+ options['customer_token'] = options.delete('customer').token if options['customer']
118
+ options['charge_token'] = options.delete('charge').token if options['charge']
119
+
120
+ options
40
121
  end
41
122
 
42
123
  end
@@ -0,0 +1,43 @@
1
+ module PinPayment
2
+ class Card < Base
3
+ attr_accessor :token, :display_number, :scheme, :address_line1, :address_line2, :address_city, :address_postcode, :address_state, :address_country
4
+ protected :token=, :display_number=, :scheme=, :address_line1=, :address_line2=, :address_city=, :address_postcode=, :address_state=, :address_country=
5
+
6
+ attr_accessor :number, :expiry_month, :expiry_year, :cvc, :name
7
+ protected :number, :expiry_month, :expiry_year, :cvc, :name
8
+ protected :number=, :expiry_month=, :expiry_year=, :cvc=, :name=
9
+
10
+ # Use the pin API to create a credit card token, usable for 1 month from creation.
11
+ #
12
+ # @param [Hash] card_data
13
+ # @option card_data [#to_s] :name
14
+ # @option card_data [#to_s] :number
15
+ # @option card_data [#to_s] :cvc
16
+ # @option card_data [#to_s] :address_line1
17
+ # @option card_data [#to_s] :address_line2 (optional)
18
+ # @option card_data [#to_s] :address_city
19
+ # @option card_data [#to_s] :address_postcode
20
+ # @option card_data [#to_s] :address_country
21
+ # @option card_data [#to_s] :expiry_month
22
+ # @option card_data [#to_s] :expiry_year (4 digits required)
23
+ # @return [PinPayment::Card]
24
+ def self.create card_data
25
+ attributes = self.attributes - [:token, :display_number, :scheme] # fix attributes allowed by POST API
26
+ options = parse_options_for_request(attributes, card_data)
27
+ response = post(URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/cards' }, options)
28
+ new(response.delete('token'), response)
29
+ end
30
+
31
+ # @return [Hash]
32
+ def to_hash
33
+ {}.tap{|h| self.class.attributes.each{|k| v = send(k) ; h[k] = v if v }}
34
+ end
35
+
36
+ protected
37
+
38
+ def self.attributes
39
+ [:token, :display_number, :scheme, :address_line1, :address_line2, :address_city, :address_postcode, :address_state, :address_country, :number, :expiry_month, :expiry_year, :cvc, :name]
40
+ end
41
+
42
+ end
43
+ end
@@ -1,30 +1,51 @@
1
1
  module PinPayment
2
2
  class Charge < Base
3
- attr_reader :token, :amount, :currency, :description, :email, :ip_address, :created_at, :card_token
3
+ attr_accessor :token, :amount, :currency, :description, :email, :ip_address, :created_at, :card, :customer, :success
4
+ protected :token=, :amount=, :currency=, :description=, :email=, :ip_address=, :created_at=, :card=, :customer=, :success=
4
5
 
5
- def self.create options
6
- response = self.post(
7
- URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/charges' },
8
- options.select{|k| %w(amount currency description email ip_address card_token customer_token).include?(k.to_s) }
9
- )
10
- self.new.tap do |charge|
11
- charge.instance_variable_set('@card_token', response['card']['token']) if response['card']
12
- %w(token amount currency description email ip_address created_at error_message success).each do |key|
13
- charge.instance_variable_set("@#{key}", response[key])
14
- end
15
- end
6
+ # Uses the pin API to create a charge.
7
+ #
8
+ # @param [Hash] charge_data
9
+ # @option charge_data [String] :amount *required*
10
+ # @option charge_data [String] :currency *required* only AUD and USD supported
11
+ # @option charge_data [String] :email *required*
12
+ # @option charge_data [String] :description *required*
13
+ # @option charge_data [String] :ip_address *required*
14
+ # @option charge_data [String, PinPayment::Customer] :customer can be a customer token or a customer object
15
+ # @option charge_data [String, PinPayment::Card, Hash] :card can be a card token, hash or a card object
16
+ # @return [PinPayment::Charge]
17
+ def self.create charge_data
18
+ attributes = self.attributes - [:token, :success, :created_at] # fix attributes allowed by POST API
19
+ options = parse_options_for_request(attributes, charge_data)
20
+ response = post(URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/charges' }, options)
21
+ new(response.delete('token'), response)
16
22
  end
17
23
 
24
+ # Fetches all of your charges using the pin API.
25
+ #
26
+ # @return [Array<PinPayment::Charge>]
27
+ # TODO: pagination
28
+ def self.all
29
+ response = get(URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/charges' })
30
+ response.map{|x| new(x.delete('token'), x) }
31
+ end
32
+
33
+ # Refund a charge via the pin API.
34
+ #
35
+ # @return [PinPayment::Refund]
18
36
  def refund!
19
- Refund.create(charge_token: token)
37
+ Refund.create self
20
38
  end
21
39
 
40
+ # @return [Boolean]
22
41
  def success?
23
- @success == true
42
+ success == true
24
43
  end
25
44
 
26
- def errors
27
- @error_message
45
+ protected
46
+
47
+ def self.attributes
48
+ [:token, :amount, :currency, :description, :email, :ip_address, :created_at, :card, :customer, :success]
28
49
  end
29
50
  end
30
51
  end
@@ -1,32 +1,66 @@
1
1
  module PinPayment
2
2
  class Customer < Base
3
- attr_reader :token, :email, :created_at, :card_token
4
-
5
- def self.create options
6
- response = post(
7
- URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/customers' },
8
- options.select{|k| %w(email card_token).include?(k.to_s) }
9
- )
10
- new.tap do |customer|
11
- customer.instance_variable_set('@card_token', response['card']['token']) if response['card']
12
- %w(token email created_at).each do |key|
13
- customer.instance_variable_set("@#{key}", response[key])
14
- end
15
- end
3
+ attr_accessor :token, :email, :created_at, :card
4
+ protected :token=, :email=, :created_at=, :card=
5
+
6
+ # Uses the pin API to create a customer.
7
+ #
8
+ # @param [String] email the customer's email address
9
+ # @param [String, PinPayment::Card, Hash] card_or_token the customer's credit card details
10
+ # @return [PinPayment::Customer]
11
+ def self.create email, card_or_token = nil
12
+ attributes = self.attributes - [:token, :created_at]
13
+ options = parse_options_for_request(attributes, email: email, card: card_or_token)
14
+ response = post(URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/customers' }, options)
15
+ new(response.delete('token'), response)
16
+ end
17
+
18
+ # Update a customer using the pin API.
19
+ #
20
+ # @param [String] token the customer token
21
+ # @param [String] email the customer's new email address
22
+ # @param [String, PinPayment::Card, Hash] card_or_token the customer's new credit card details
23
+ # @return [PinPayment::Customer]
24
+ def self.update token, email, card_or_token = nil
25
+ new(token).tap{|c| c.update(email, card_or_token) }
26
+ end
27
+
28
+ # Fetches a customer using the pin API.
29
+ #
30
+ # @param [String] token the customer token
31
+ # @return [PinPayment::Customer]
32
+ def self.find token
33
+ response = get(URI.parse(PinPayment.api_url).tap{|uri| uri.path = "/1/customers/#{token}" })
34
+ new(response.delete('token'), response)
16
35
  end
17
36
 
18
- def self.update options
19
- # PUT /1/customers/cus_XZg1ULpWaROQCOT5PdwLkQ
20
- response = put(
21
- URI.parse(PinPayment.api_url).tap{|uri| uri.path = "/1/customers/#{options[:token] || options['token']}" },
22
- options.select{|k| %w(email card_token).include?(k.to_s) }
23
- )
24
- new.tap do |customer|
25
- customer.instance_variable_set('@card_token', response['card']['token']) if response['card']
26
- %w(token email created_at).each do |key|
27
- customer.instance_variable_set("@#{key}", response[key])
28
- end
29
- end
37
+ # Fetches all of your customers using the pin API.
38
+ #
39
+ # @return [Array<PinPayment::Customer>]
40
+ # TODO: pagination
41
+ def self.all
42
+ response = get(URI.parse(PinPayment.api_url).tap{|uri| uri.path = '/1/customers' })
43
+ response.map{|x| new(x.delete('token'), x) }
44
+ end
45
+
46
+ # Update a customer using the pin API.
47
+ #
48
+ # @param [String] email the customer's new email address
49
+ # @param [String, PinPayment::Card, Hash] card_or_token the customer's new credit card details
50
+ # @return [PinPayment::Customer]
51
+ def update email, card_or_token = nil
52
+ attributes = self.class.attributes - [:token, :created_at]
53
+ options = self.class.parse_options_for_request(attributes, email: email, card: card_or_token)
54
+ response = self.class.put(URI.parse(PinPayment.api_url).tap{|uri| uri.path = "/1/customers/#{token}" }, options)
55
+ self.email = response['email']
56
+ self.card = response['card']
57
+ self
58
+ end
59
+
60
+ protected
61
+
62
+ def self.attributes
63
+ [:token, :email, :created_at, :card]
30
64
  end
31
65
 
32
66
  end
@@ -1,19 +1,19 @@
1
1
  module PinPayment
2
2
  class Refund < Base
3
- attr_reader :token, :amount, :currency, :charge_token, :created_at
3
+ attr_accessor :token, :amount, :currency, :charge, :created_at, :status_message
4
+ protected :token=, :amount=, :currency=, :charge=, :created_at=, :status_message=, :status_message
4
5
 
5
- def self.create options
6
- response = self.post(
7
- URI.parse(PinPayment.api_url).tap{|uri| uri.path = "/1/charges/#{options[:charge_token] || options['charge_token']}/refunds" },
8
- {}
9
- )
10
- self.new.tap do |charge|
11
- %w(token amount currency created_at error_message status_message).each do |key|
12
- charge.instance_variable_set("@#{key}", response[key])
13
- end
14
- end
6
+ # Uses the pin API to create a refund.
7
+ #
8
+ # @param [String, PinPayment::Charge] charge_or_token the charge (or token of the charge) to refund
9
+ # @return [PinPayment::Refund]
10
+ def self.create charge_or_token
11
+ token = charge_or_token.is_a?(Charge) ? charge_or_token.token : charge_or_token
12
+ response = post(URI.parse(PinPayment.api_url).tap{|uri| uri.path = "/1/charges/#{token}/refunds" })
13
+ new(response.delete('token'), response)
15
14
  end
16
15
 
16
+ # @return [Boolean]
17
17
  # TODO: API documentation only shows success as being "null" in the JSON
18
18
  # response, so not sure this is possible. All my refunds on the test site
19
19
  # end up in a "Pending" state so not entirely sure on this one.
@@ -21,12 +21,15 @@ module PinPayment
21
21
  @success == true
22
22
  end
23
23
 
24
+ # @return [String]
24
25
  def status
25
- @status_message
26
+ status_message
26
27
  end
27
28
 
28
- def errors
29
- @error_message
29
+ protected
30
+
31
+ def self.attributes
32
+ [:token, :amount, :currency, :charge, :created_at, :status_message]
30
33
  end
31
34
  end
32
35
  end
@@ -1,8 +1,8 @@
1
1
  module PinPayment
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 0
5
- PATCH = 5
4
+ MINOR = 1
5
+ PATCH = 0
6
6
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
  end
8
8
  end
data/lib/pin_payment.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'pin_payment/base'
2
+ require 'pin_payment/card'
2
3
  require 'pin_payment/charge'
3
4
  require 'pin_payment/customer'
4
5
  require 'pin_payment/error'
data/pin_payment.gemspec CHANGED
@@ -14,6 +14,7 @@ spec = Gem::Specification.new do |s|
14
14
 
15
15
  s.add_development_dependency('fakeweb')
16
16
  s.add_development_dependency('rake')
17
+ s.add_development_dependency('yard')
17
18
 
18
19
  s.required_ruby_version = '>= 1.9.2'
19
20
 
@@ -3,13 +3,17 @@ charge:
3
3
  token_already_used: '{"error":"token_already_used","error_description":"Token already used. Card tokens can only be used once, to create a charge or assign a card to a customer."}'
4
4
  invalid_amount: '{"error":"invalid_resource","error_description":"One or more parameters were missing or invalid.","messages":[{"param":"amount","code":"amount_invalid","message":"Amount must be an integer"},{"param":"amount","code":"amount_invalid","message":"Amount must be more than 1 USD"}]}'
5
5
  success: '{"response":{"token":"ch_BjGW-S6WUisI6mOgpDRimg","success":true,"amount":1000,"currency":"USD","description":"Widgets","email":"foo@example.com","ip_address":"127.0.0.1","created_at":"2013-06-12T23:55:38Z","status_message":"Success!","error_message":null,"card":{"token":"card_qMwnMfpG-olOhfJeyxmrcg","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"},"transfer":[],"amount_refunded":0,"total_fees":null,"merchant_entitlement":null,"refund_pending":false}}'
6
- update_customer:
6
+ create_with_card: '{"response":{"token":"ch_lfUYEBK14zotCTykezJkfg","success":true,"amount":400,"currency":"AUD","description":"test charge","email":"roland@pin.net.au","ip_address":"203.192.1.172","created_at":"2013-06-27T00:39:07Z","status_message":"Success","error_message":null,"card":{"token":"card_jxk5A8fjTtmz6Y81NX9G7w","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"},"transfer":null}}'
7
+ all: '{"response":[{"token":"ch_lfUYEBK14zotCTykezJkfg","success":true,"amount":400,"currency":"AUD","description":"test charge","email":"roland@pin.net.au","ip_address":"203.192.1.172","created_at":"2013-06-27T00:39:07Z","status_message":"Success","error_message":null,"card":{"token":"card_nytGw7koRg23EEp9NTmz9w","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"},"transfer":null},{"token":"ch_shldvbE5eqBQuyY9Fryhzw","success":true,"amount":400,"currency":"AUD","description":"test charge","email":"roland@pin.net.au","ip_address":"203.192.1.172","created_at":"2013-06-27T00:38:41Z","status_message":"Success","error_message":null,"card":{"token":"card_nytGw7koRg23EEp9NTmz9w","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"},"transfer":null}],"count":2,"pagination":{"current":1,"previous":null,"next":1,"per_page":25,"pages":1,"count":2}}'
8
+ customer:
7
9
  blank_email: '{"error":"invalid_resource","error_description":"One or more parameters were missing or invalid.","messages":[{"param":"email","code":"email_invalid","message":"Email can''t be blank"}]}'
8
- blank_token: '{"error":"resource_not_found","error_description":"No resource was found at this URL. See https://pin.net.au/docs/api for API documentation and a list of valid URLs."}'
9
- success: '{"response":{"token":"cus__03Cn1lSk3offZ0IGkwpCg","email":"foo@example.com","created_at":"2013-06-12T10:08:30Z","card":{"token":"card_qMwnMfpG-olOhfJeyxmrcg","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}}}'
10
- create_customer:
11
- blank_email: '{"error":"invalid_resource","error_description":"One or more parameters were missing or invalid.","messages":[{"param":"email","code":"email_invalid","message":"Email can''t be blank"}]}'
12
- success: '{"response":{"token":"cus__03Cn1lSk3offZ0IGkwpCg","email":"foo@example.com","created_at":"2013-06-12T10:08:30Z","card":{"token":"card_qMwnMfpG-olOhfJeyxmrcg","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}}}'
10
+ updated: '{"response":{"token":"cus__03Cn1lSk3offZ0IGkwpCg","email":"changed@example.com","created_at":"2013-06-12T10:08:30Z","card":{"token":"card_qMwnMfpG-olOhfJeyxmrcg","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}}}'
11
+ created: '{"response":{"token":"cus__03Cn1lSk3offZ0IGkwpCg","email":"foo@example.com","created_at":"2013-06-12T10:08:30Z","card":{"token":"card_qMwnMfpG-olOhfJeyxmrcg","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}}}'
12
+ all: '{"response":[{"token":"cus_OEHdj9KE_OiC9eig0h3IEA","email":"user1@example.com","created_at":"2013-06-25T04:14:35Z","card":{"token":"card_7rviJ2IZM__WC9Dnj0RHJA","display_number":"XXXX-XXXX-XXXX-0000","scheme":"visa","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}},{"token":"cus_cO2VtF4YzK6i1QBcLsdzOA","email":"user2@example.com","created_at":"2013-06-24T05:53:42Z","card":{"token":"card_bVou2J4hzbDIwe-sQ3ZqdQ","display_number":"XXXX-XXXX-XXXX-0000","scheme":"visa","address_line1":"123 Main St","address_line2":"","address_city":"Melbourne","address_postcode":"3000","address_state":"Victoria","address_country":"Australia"}}],"count":2,"pagination":{"current":1,"previous":null,"next":null,"per_page":25,"pages":1,"count":2}}'
13
+ create_with_card: '{"response":{"token":"cus_XZg1ULpWaROQCOT5PdwLkQ","email":"roland@pin.net.au","created_at":"2013-06-27T00:24:43Z","card":{"token":"card_nytGw7koRg23EEp9NTmz9w","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"}}}'
13
14
  refund:
14
15
  success: '{"response":{"token":"rf_wMYx5YHKaZAwQgj5rtNuTg","success":null,"amount":1000,"currency":"USD","charge":"ch_BjGW-S6WUisI6mOgpDRimg","created_at":"2013-06-25T03:16:33Z","error_message":null,"status_message":"Pending"}}'
15
16
  duplicate: '{"error":"invalid_resource","error_description":"One or more parameters were missing or invalid.","messages":{"charge":["You have tried to refund more than the original charge"]}}'
17
+ card:
18
+ success: '{"response":{"token":"card_nytGw7koRg23EEp9NTmz9w","display_number":"XXXX-XXXX-XXXX-0000","scheme":"master","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"}}'
19
+ invalid: '{"error":"invalid_resource","error_description":"One or more parameters were missing or invalid.","messages":[{"param":"number","code":"number_invalid","message":"Number is not a valid credit card number"}]}'
data/test/test_helper.rb CHANGED
@@ -9,3 +9,44 @@ def fixtures
9
9
  f['responses'] = YAML.load(File.read File.join(File.dirname(__FILE__), 'fixtures', 'responses.yml'))
10
10
  end
11
11
  end
12
+
13
+ def common_setup
14
+ FakeWeb.allow_net_connect = false
15
+
16
+ # If you want to test for realsies, change the above to true, and uncomment
17
+ # below, after putting in your own test keys
18
+
19
+ #PinPayment.secret_key = 'super secret'
20
+ #PinPayment.public_key = 'not so secret'
21
+ end
22
+
23
+ def card_hash
24
+ {
25
+ number: 5520000000000000,
26
+ expiry_month: 5,
27
+ expiry_year: 2014,
28
+ cvc: 123,
29
+ name: 'Roland Robot',
30
+ address_line1: '42 Sevenoaks St',
31
+ address_city: 'Lathlain',
32
+ address_postcode: 6454,
33
+ address_state: 'WA',
34
+ address_country: 'Australia'
35
+ }
36
+ end
37
+
38
+ def charge_hash
39
+ {
40
+ amount: 400,
41
+ currency: 'AUD',
42
+ description: 'test charge',
43
+ email: 'roland@pin.net.au',
44
+ ip_address: '203.192.1.172',
45
+ card: card_hash
46
+ }
47
+ end
48
+
49
+ def created_customer
50
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['customer']['created'])
51
+ customer = PinPayment::Customer.create('foo@example.com', card_hash)
52
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class TestPinCard < MiniTest::Unit::TestCase
4
+ def setup
5
+ common_setup
6
+ end
7
+
8
+ def test_successful_card
9
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/cards', body: fixtures['responses']['card']['success'])
10
+ card = PinPayment::Card.create(card_hash)
11
+ assert_equal 'XXXX-XXXX-XXXX-0000', card.display_number
12
+ assert_equal 'master', card.scheme
13
+ end
14
+
15
+ def test_invalid_card
16
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/cards', body: fixtures['responses']['card']['invalid'])
17
+ assert_raises PinPayment::Error::InvalidResource do
18
+ PinPayment::Card.create(card_hash.merge(number: 5520000000000099))
19
+ end
20
+ end
21
+
22
+ def test_new_from_hash
23
+ card = PinPayment::Card.new(nil, card_hash)
24
+ assert_kind_of PinPayment::Card, card
25
+ end
26
+
27
+ def test_to_hash
28
+ card = PinPayment::Card.new(nil, card_hash)
29
+ assert_kind_of Hash, card.to_hash
30
+ end
31
+ end
@@ -2,19 +2,35 @@ require 'test_helper'
2
2
 
3
3
  class TestPinCharge < MiniTest::Unit::TestCase
4
4
  def setup
5
- FakeWeb.allow_net_connect = false
5
+ common_setup
6
6
  end
7
7
 
8
8
  def test_invalid_amount
9
9
  FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['invalid_amount'])
10
10
  assert_raises PinPayment::Error::InvalidResource do
11
- PinPayment::Charge.create(customer_token: 'cus__03Cn1lSk3offZ0IGkwpCg', amount: 10.0)
11
+ PinPayment::Charge.create(charge_hash.merge(amount: 10.1))
12
12
  end
13
13
  end
14
14
 
15
15
  def test_successful_charge
16
16
  FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['success'])
17
- charge = PinPayment::Charge.create(customer_token: 'cus__03Cn1lSk3offZ0IGkwpCg', amount: 1000)
17
+ charge = PinPayment::Charge.create(charge_hash)
18
18
  assert_equal true, charge.success?
19
19
  end
20
+
21
+ def test_create_charge_with_card_hash
22
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['create_with_card'])
23
+ charge = PinPayment::Charge.create(charge_hash)
24
+ assert_equal true, charge.success?
25
+ assert_kind_of PinPayment::Card, charge.card
26
+ assert_kind_of String, charge.card.token
27
+ assert charge.card.token.length > 0
28
+ end
29
+
30
+ def test_fetch_all_charges
31
+ FakeWeb.register_uri(:get, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['all'])
32
+ charges = PinPayment::Charge.all
33
+ assert_kind_of Array, charges
34
+ assert_kind_of PinPayment::Charge, charges.first
35
+ end
20
36
  end
@@ -2,39 +2,54 @@ require 'test_helper'
2
2
 
3
3
  class TestPinCustomer < MiniTest::Unit::TestCase
4
4
  def setup
5
- FakeWeb.allow_net_connect = false
5
+ common_setup
6
6
  end
7
7
 
8
- def test_update_with_blank_email
9
- FakeWeb.register_uri(:put, 'https://test-api.pin.net.au/1/customers/cus__03Cn1lSk3offZ0IGkwpCg', body: fixtures['responses']['update_customer']['blank_email'])
8
+ def test_create_with_blank_email
9
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['customer']['blank_email'])
10
10
  assert_raises PinPayment::Error::InvalidResource do
11
- PinPayment::Customer.update(token: 'cus__03Cn1lSk3offZ0IGkwpCg', email: nil)
11
+ PinPayment::Customer.create(email: nil, card: card_hash)
12
12
  end
13
13
  end
14
14
 
15
- def test_update_with_blank_token
16
- FakeWeb.register_uri(:put, 'https://test-api.pin.net.au/1/customers/', body: fixtures['responses']['update_customer']['blank_token'])
17
- assert_raises PinPayment::Error::ResourceNotFound do
18
- PinPayment::Customer.update(email: 'foo@example.com')
19
- end
15
+ def test_create_success
16
+ customer = created_customer
17
+ assert_kind_of PinPayment::Customer, customer
20
18
  end
21
19
 
22
- def test_create_with_blank_email
23
- FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['create_customer']['blank_email'])
24
- assert_raises PinPayment::Error::InvalidResource do
25
- PinPayment::Customer.create(email: nil)
26
- end
20
+ def test_direct_update
21
+ customer = created_customer
22
+ FakeWeb.register_uri(:put, "https://test-api.pin.net.au/1/customers/#{customer.token}", body: fixtures['responses']['customer']['updated'])
23
+ customer = PinPayment::Customer.update(customer.token, 'changed@example.com')
24
+ assert_equal 'changed@example.com', customer.email
27
25
  end
28
26
 
29
- def test_create_success
30
- FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['create_customer']['success'])
31
- customer = PinPayment::Customer.create(email: 'foo@example.com')
32
- assert_equal customer.token, 'cus__03Cn1lSk3offZ0IGkwpCg'
27
+ def test_object_update
28
+ customer = created_customer
29
+ FakeWeb.register_uri(:put, "https://test-api.pin.net.au/1/customers/#{customer.token}", body: fixtures['responses']['customer']['updated'])
30
+ customer.update('changed@example.com')
31
+ assert_equal 'changed@example.com', customer.email
32
+ end
33
+
34
+ def test_find_customer
35
+ customer = created_customer
36
+ FakeWeb.register_uri(:get, "https://test-api.pin.net.au/1/customers/#{customer.token}", body: fixtures['responses']['customer']['created'])
37
+ customer = PinPayment::Customer.find(customer.token)
38
+ assert_kind_of PinPayment::Customer, customer
39
+ end
40
+
41
+ def test_fetch_all_customers
42
+ FakeWeb.register_uri(:get, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['customer']['all'])
43
+ customers = PinPayment::Customer.all
44
+ assert_kind_of Array, customers
45
+ assert_kind_of PinPayment::Customer, customers.first
33
46
  end
34
47
 
35
- def test_update_success
36
- FakeWeb.register_uri(:put, 'https://test-api.pin.net.au/1/customers/cus__03Cn1lSk3offZ0IGkwpCg', body: fixtures['responses']['update_customer']['success'])
37
- customer = PinPayment::Customer.update(token: 'cus__03Cn1lSk3offZ0IGkwpCg', email: 'foo@example.com')
38
- assert_equal customer.token, 'cus__03Cn1lSk3offZ0IGkwpCg'
48
+ def test_create_customer_with_card_hash
49
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/customers', body: fixtures['responses']['customer']['create_with_card'])
50
+ customer = PinPayment::Customer.create('roland@pin.net.au', card_hash)
51
+ assert_kind_of PinPayment::Card, customer.card
52
+ assert_kind_of String, customer.card.token
53
+ assert customer.card.token.length > 0
39
54
  end
40
55
  end
@@ -2,30 +2,29 @@ require 'test_helper'
2
2
 
3
3
  class TestPinRefund < MiniTest::Unit::TestCase
4
4
  def setup
5
- FakeWeb.allow_net_connect = false
5
+ common_setup
6
+ FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['success'])
7
+ @charge = PinPayment::Charge.create(charge_hash)
6
8
  end
7
9
 
8
10
  def test_duplicate_refund
9
- token = 'ch_BjGW-S6WUisI6mOgpDRimg'
10
- FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{token}/refunds", body: fixtures['responses']['refund']['duplicate'])
11
+ FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{@charge.token}/refunds", body: fixtures['responses']['refund']['success'])
12
+ PinPayment::Refund.create(@charge)
13
+ FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{@charge.token}/refunds", body: fixtures['responses']['refund']['duplicate'])
11
14
  assert_raises PinPayment::Error::InvalidResource do
12
- PinPayment::Refund.create(charge_token: token)
15
+ PinPayment::Refund.create(@charge)
13
16
  end
14
17
  end
15
18
 
16
- def test_manual_refund
17
- token = 'ch_BjGW-S6WUisI6mOgpDRimg'
18
- FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{token}/refunds", body: fixtures['responses']['refund']['success'])
19
- refund = PinPayment::Refund.create(charge_token: token)
19
+ def test_direct_refund
20
+ FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{@charge.token}/refunds", body: fixtures['responses']['refund']['success'])
21
+ refund = PinPayment::Refund.create(@charge.token)
20
22
  assert_equal 'Pending', refund.status
21
23
  end
22
24
 
23
- def test_charge_refund
24
- FakeWeb.register_uri(:post, 'https://test-api.pin.net.au/1/charges', body: fixtures['responses']['charge']['success'])
25
- charge = PinPayment::Charge.create(customer_token: 'cus__03Cn1lSk3offZ0IGkwpCg', amount: 1000)
26
-
27
- FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{charge.token}/refunds", body: fixtures['responses']['refund']['success'])
28
- refund = charge.refund!
25
+ def test_object_refund
26
+ FakeWeb.register_uri(:post, "https://test-api.pin.net.au/1/charges/#{@charge.token}/refunds", body: fixtures['responses']['refund']['success'])
27
+ refund = @charge.refund!
29
28
  assert_equal 'Pending', refund.status
30
29
  end
31
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pin_payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danial Pearce
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-25 00:00:00.000000000 Z
11
+ date: 2013-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fakeweb
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: Pin is the easiest way to accept payments online. See https://pin.net.au/
42
56
  for details.
43
57
  email:
@@ -54,6 +68,7 @@ files:
54
68
  - Rakefile
55
69
  - lib/pin_payment.rb
56
70
  - lib/pin_payment/base.rb
71
+ - lib/pin_payment/card.rb
57
72
  - lib/pin_payment/charge.rb
58
73
  - lib/pin_payment/customer.rb
59
74
  - lib/pin_payment/error.rb
@@ -62,6 +77,7 @@ files:
62
77
  - pin_payment.gemspec
63
78
  - test/fixtures/responses.yml
64
79
  - test/test_helper.rb
80
+ - test/test_pin_card.rb
65
81
  - test/test_pin_charge.rb
66
82
  - test/test_pin_customer.rb
67
83
  - test/test_pin_refund.rb
@@ -93,7 +109,9 @@ summary: Ruby bindings for the Pin API
93
109
  test_files:
94
110
  - test/fixtures/responses.yml
95
111
  - test/test_helper.rb
112
+ - test/test_pin_card.rb
96
113
  - test/test_pin_charge.rb
97
114
  - test/test_pin_customer.rb
98
115
  - test/test_pin_refund.rb
99
116
  - test/test_pin_setup.rb
117
+ has_rdoc: