pin_payment 0.0.5 → 0.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.
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: