gocardless 1.9.0 → 1.10.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: ed8ff8ba2e1109b3ec370bd8c52e2d1f2dc0ae70
4
- data.tar.gz: 4321b58cabecafefbf4a5257ae6ee6e218d49364
3
+ metadata.gz: d3541d1c3a98b1d8812387e1122381ccf061648d
4
+ data.tar.gz: d1280282fed2de29f439389679a27165dbef197e
5
5
  SHA512:
6
- metadata.gz: f8594375ca0b9ea638fedf5d2fc4ef137b81b791e2248307277eb4459e941b1606abd49f53e86a4829acd2fd3f09d72ca5a3fd5dbaadda148784d65df24d6a0e
7
- data.tar.gz: c92b6f3708f2595533dcc368f904fbd83593f8eabf7059b8b9955cfe5bb964792335e584fd129da8b150773f1c0e9a317e70948a374974682ec12c69d23bd214
6
+ metadata.gz: c4238571659011a414b4ec82b8dab479c9f4bc2274ffd9f6de010e28dad76f34356d7a41be4fe49bb3b354d4a3a8818cff35bb21618c30799b9b42a53763fbec
7
+ data.tar.gz: 4fe530f0bf5531541366cae496bcc8d613abca06e638b11f10d36e3aaba00ce0d2ec7246a6b3aa811a0581a8b494dedc7016f9c92737b1195d17c05858084b7e
@@ -1,3 +1,13 @@
1
+ ## 1.10.0 - June 02, 2014
2
+
3
+ - Add alias methods for boolean attributes
4
+ - Update resources with new attributes
5
+ - Remove any nil values before sending params to GC
6
+ - Support charge_customer_at on bill creation
7
+ - Make depedency specifier less strict
8
+ - Add pagination
9
+
10
+
1
11
  ## 1.9.0 - May 23, 2014
2
12
 
3
13
  - Add ability to refund bills
data/README.md CHANGED
@@ -3,10 +3,7 @@
3
3
  The GoCardless Ruby client provides a simple Ruby interface to the GoCardless
4
4
  API.
5
5
 
6
- If you want to use the library as an individual merchant, refer to the
7
- [merchant guide](https://gocardless.com/docs/ruby/merchant_client_guide). If
8
- you want to support multiple merchant accounts, see the
9
- [partner guide](https://gocardless.com/docs/ruby/partner_client_guide).
6
+ API documentation, usage guides, and setup information can be found at [developer.gocardless.com](https://developer.gocardless.com/ruby/).
10
7
 
11
8
  The full API reference is available at on
12
9
  [rubydoc.info](http://rubydoc.info/github/gocardless/gocardless-ruby/master/frames).
@@ -7,7 +7,6 @@ module GoCardless
7
7
  require 'gocardless/pre_authorization'
8
8
  require 'gocardless/user'
9
9
  require 'gocardless/bill'
10
- require 'gocardless/payment'
11
10
  require 'gocardless/merchant'
12
11
  require 'gocardless/client'
13
12
  require 'gocardless/payout'
@@ -5,20 +5,29 @@ module GoCardless
5
5
  creatable
6
6
 
7
7
  attr_accessor :amount,
8
- :source_type,
8
+ :currency,
9
9
  :description,
10
10
  :name,
11
- :plan_id,
12
11
  :status,
13
12
  :gocardless_fees,
14
- :partner_fees
13
+ :partner_fees,
14
+ :amount_minus_fees,
15
+ :can_be_retried,
16
+ :can_be_cancelled,
17
+ :is_setup_fee
15
18
 
16
19
  # @attribute source_id
17
20
  # @return [String] the ID of the bill's source (eg subscription, pre_authorization)
18
21
  attr_accessor :source_id
22
+ attr_accessor :source_type
19
23
 
20
- reference_accessor :merchant_id, :user_id, :payment_id, :payout_id
21
- date_accessor :created_at, :paid_at
24
+ reference_accessor :merchant_id, :user_id, :payout_id
25
+ date_accessor :created_at, :paid_at, :charge_customer_at
26
+
27
+ # Alias getter methods
28
+ alias_method :is_setup_fee?, :is_setup_fee
29
+ alias_method :can_be_cancelled?, :can_be_cancelled
30
+ alias_method :can_be_retried?, :can_be_retried
22
31
 
23
32
  def source
24
33
  klass = GoCardless.const_get(Utils.camelize(source_type.to_s))
@@ -47,7 +56,7 @@ module GoCardless
47
56
 
48
57
  # The ability to refund a payment is disabled by default.
49
58
  #
50
- # Please contact help@gocardless.com if you require access to
59
+ # Please contact help@gocardless.com if you require access to
51
60
  # the refunds API endpoint.
52
61
  def refund!
53
62
  path = self.class.endpoint.gsub(':id', id.to_s) + '/refund'
@@ -55,14 +64,17 @@ module GoCardless
55
64
  end
56
65
 
57
66
  def save
58
- save_data({
59
- :bill => {
60
- :pre_authorization_id => self.source_id,
61
- :amount => self.amount,
62
- :name => self.name,
63
- :description => self.description,
64
- }
65
- })
67
+ bill_params = {
68
+ :pre_authorization_id => self.source_id,
69
+ :amount => self.amount,
70
+ :name => self.name,
71
+ :description => self.description,
72
+ :charge_customer_at => self.charge_customer_at,
73
+ }
74
+
75
+ bill_params.delete_if { |_,v| v.nil? }
76
+
77
+ save_data({ :bill => bill_params })
66
78
  self
67
79
  end
68
80
 
@@ -117,7 +117,7 @@ module GoCardless
117
117
  # @param [Hash] params query string parameters
118
118
  # @return [Hash] hash the parsed response data
119
119
  def api_get(path, params = {})
120
- request(:get, "#{API_PATH}#{path}", :params => params).parsed
120
+ api_request(:get, path, :params => params).parsed
121
121
  end
122
122
 
123
123
  # Issue a POST request to the API server
@@ -127,7 +127,7 @@ module GoCardless
127
127
  # @param [Hash] data a hash of data that will be sent as the request body
128
128
  # @return [Hash] hash the parsed response data
129
129
  def api_post(path, data = {})
130
- request(:post, "#{API_PATH}#{path}", :data => data).parsed
130
+ api_request(:post, path, :data => data).parsed
131
131
  end
132
132
 
133
133
  # Issue a PUT request to the API server
@@ -137,7 +137,7 @@ module GoCardless
137
137
  # @param [Hash] data a hash of data that will be sent as the request body
138
138
  # @return [Hash] hash the parsed response data
139
139
  def api_put(path, data = {})
140
- request(:put, "#{API_PATH}#{path}", :data => data).parsed
140
+ api_request(:put, path, :data => data).parsed
141
141
  end
142
142
 
143
143
  # Issue a DELETE request to the API server
@@ -147,7 +147,18 @@ module GoCardless
147
147
  # @param [Hash] data a hash of data that will be sent as the request body
148
148
  # @return [Hash] hash the parsed response data
149
149
  def api_delete(path, data = {})
150
- request(:delete, "#{API_PATH}#{path}", :data => data).parsed
150
+ api_request(:delete, path, :data => data).parsed
151
+ end
152
+
153
+
154
+ # Issue a request to the API server, returning the full response
155
+ #
156
+ # @note this method is for internal use
157
+ # @param [Symbol] method the HTTP method to use (e.g. +:get+, +:post+)
158
+ # @param [String] path the path that will be added to the API prefix
159
+ # @option [Hash] opts additional request options (e.g. form data, params)
160
+ def api_request(method, path, opts = {})
161
+ request(method, "#{API_PATH}#{path}", opts)
151
162
  end
152
163
 
153
164
  # @method merchant
@@ -185,13 +196,6 @@ module GoCardless
185
196
  Bill.find_with_client(self, id)
186
197
  end
187
198
 
188
- # @method payment(id)
189
- # @param [String] id of the payment
190
- # @return [Payment] the payment matching the id requested
191
- def payment(id)
192
- Payment.find_with_client(self, id)
193
- end
194
-
195
199
  # Create a new bill under a given pre-authorization
196
200
  # @see PreAuthorization#create_bill
197
201
  #
@@ -239,7 +243,7 @@ module GoCardless
239
243
  end
240
244
 
241
245
  # Confirm a newly-created subscription, pre-authorzation or one-off
242
- # payment. This method also checks that the resource response data includes
246
+ # bill. This method also checks that the resource response data includes
243
247
  # a valid signature and will raise a {SignatureError} if the signature is
244
248
  # invalid.
245
249
  #
@@ -11,6 +11,7 @@ module GoCardless
11
11
  :pending_balance,
12
12
  :next_payout_amount,
13
13
  :hide_variable_amount
14
+
14
15
  date_accessor :created_at, :next_payout_date
15
16
  end
16
17
  end
@@ -0,0 +1,43 @@
1
+ module GoCardless
2
+ class Page
3
+ include Enumerable
4
+
5
+ def initialize(resource_class, data, links)
6
+ @resource_class = resource_class
7
+ @data = data
8
+ @links = links
9
+ end
10
+
11
+ # The next page number, nil if there is no next page
12
+ def next_page
13
+ @links['next']
14
+ end
15
+
16
+ # The previous page number, nil if there is no previous page
17
+ def previous_page
18
+ @links['previous']
19
+ end
20
+
21
+ # The first page number, nil if this is the first page
22
+ def first_page
23
+ @links['first']
24
+ end
25
+
26
+ # The last page number, nil if this is the last page
27
+ def last_page
28
+ @links['last']
29
+ end
30
+
31
+ # Used for page iteration
32
+ def has_next?
33
+ !!@links['next']
34
+ end
35
+
36
+ # Yield each of the items in the page as instances of the resource class
37
+ def each(&block)
38
+ @data.each do |attrs|
39
+ yield @resource_class.new(attrs)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,86 @@
1
+ require 'multi_json'
2
+ require 'gocardless/page'
3
+
4
+ module GoCardless
5
+ class Paginator
6
+ include Enumerable
7
+
8
+ attr_reader :num_records
9
+ attr_reader :num_pages
10
+
11
+ DEFAULT_PAGE_NUMBER = 1
12
+ DEFAULT_PAGE_SIZE = 30
13
+
14
+ def initialize(client, resource_class, path, query)
15
+ @client = client
16
+ @resource_class = resource_class
17
+ @path, @query = path, query
18
+ @page_number, @per_page = DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE
19
+ end
20
+
21
+ # Set the number of records per page (page size), if an argument is
22
+ # provided. Returns the current per_page value, whether an argument is
23
+ # provided or not.
24
+ def per_page(results_per_page = nil)
25
+ if results_per_page
26
+ @num_records, @num_pages = nil, nil
27
+ @per_page = results_per_page
28
+ self
29
+ else
30
+ @per_page
31
+ end
32
+ end
33
+
34
+ # Fetch and return a single page.
35
+ def load_page(page_num)
36
+ params = @query.merge(pagination_params(page_num))
37
+ response = @client.api_request(:get, @path, :params => params)
38
+
39
+ metadata = parse_metadata(response)
40
+ @num_records, @num_pages = metadata['records'], metadata['pages']
41
+
42
+ Page.new(@resource_class, response.parsed, metadata['links'])
43
+ end
44
+
45
+ alias_method :page, :load_page
46
+
47
+ # Yield every record from every current page, auto-fetching new pages as
48
+ # the iteration happens. Records are returned as instances of the
49
+ # appropriate resource classes (e.g. Subscription).
50
+ def each(&block)
51
+ each_page { |page| page.each(&block) }
52
+ end
53
+
54
+ # Fetch and yield each page of results.
55
+ def each_page
56
+ page_obj = load_page(1)
57
+ loop do
58
+ yield page_obj
59
+ break unless page_obj.has_next?
60
+ page_obj = load_page(page_obj.next_page)
61
+ end
62
+ end
63
+
64
+ # Return the total number of records. May trigger an HTTP request.
65
+ def count
66
+ load_page(1) if @num_records.nil? # load pagination metadata
67
+ @num_records
68
+ end
69
+
70
+ # Return the total number of pages. May trigger an HTTP request.
71
+ def page_count
72
+ load_page(1) if @num_records.nil? # load pagination metadata
73
+ @num_pages
74
+ end
75
+
76
+ private
77
+
78
+ def pagination_params(page_num)
79
+ { :page => page_num, :per_page => @per_page }
80
+ end
81
+
82
+ def parse_metadata(response)
83
+ MultiJson.load(response.headers['X-Pagination'])
84
+ end
85
+ end
86
+ end
@@ -9,9 +9,9 @@ module GoCardless
9
9
  :interval_unit,
10
10
  :name,
11
11
  :description,
12
- :plan_id,
13
12
  :status,
14
- :remaining_amount
13
+ :remaining_amount,
14
+ :setup_fee
15
15
 
16
16
  reference_accessor :merchant_id, :user_id
17
17
 
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require 'gocardless/paginator'
2
3
 
3
4
  module GoCardless
4
5
  class Resource
@@ -18,18 +19,7 @@ module GoCardless
18
19
  path = uri.path.sub(%r{^/api/v\d+}, '')
19
20
 
20
21
  # Modify the instance's metaclass to add the method
21
- metaclass = class << self; self; end
22
- metaclass.send(:define_method, name) do |*args|
23
- # 'name' will be something like 'bills', convert it to Bill and
24
- # look up the resource class with that name
25
- class_name = Utils.camelize(Utils.singularize(name.to_s))
26
- klass = GoCardless.const_get(class_name)
27
- query = default_query.merge(args.first || {})
28
- client.api_get(path, query).map do |attrs|
29
- # Convert the results to instances of the looked-up class
30
- klass.new_with_client(client, attrs)
31
- end
32
- end
22
+ define_paginated_resource_method(name, path, default_query)
33
23
  end
34
24
 
35
25
  # Set resource attribute values
@@ -182,5 +172,21 @@ module GoCardless
182
172
  response = client.send("api_#{method}", path, data)
183
173
  response.each { |key,val| send("#{key}=", val) if respond_to?("#{key}=") } if response.is_a? Hash
184
174
  end
175
+
176
+ def define_paginated_resource_method(name, path, default_query)
177
+ metaclass = class << self; self; end
178
+ metaclass.send(:define_method, name) do |*args|
179
+ # 'name' will be something like 'bills', convert it to Bill and
180
+ # look up the resource class with that name
181
+ class_name = Utils.camelize(Utils.singularize(name.to_s))
182
+ klass = GoCardless.const_get(class_name)
183
+
184
+ # merge the default query, which may have been included in the
185
+ # sub_resource_uri, with the query params provided by the user
186
+ query = default_query.merge(args.first || {})
187
+
188
+ Paginator.new(client, self, path, query)
189
+ end
190
+ end
185
191
  end
186
192
  end
@@ -9,17 +9,13 @@ module GoCardless
9
9
  :interval_unit,
10
10
  :name,
11
11
  :description,
12
- :plan_id,
13
12
  :status,
14
- :setup_fee,
15
- :trial_length,
16
- :trial_unit
13
+ :setup_fee
17
14
 
18
15
  reference_accessor :merchant_id, :user_id
19
16
 
20
17
  date_accessor :start_at, :expires_at, :created_at, :next_interval_start
21
18
 
22
-
23
19
  def cancel!
24
20
  path = self.class.endpoint.gsub(':id', id.to_s) + '/cancel'
25
21
  client.api_put(path)
@@ -2,7 +2,12 @@ module GoCardless
2
2
  class User < Resource
3
3
  self.endpoint = '/users/:id'
4
4
 
5
- attr_accessor :name, :first_name, :last_name, :email
5
+ attr_accessor :name,
6
+ :first_name,
7
+ :last_name,
8
+ :company_name,
9
+ :email
10
+
6
11
  date_accessor :created_at
7
12
 
8
13
  def name
@@ -1,3 +1,3 @@
1
1
  module GoCardless
2
- VERSION = '1.9.0'.freeze
2
+ VERSION = '1.10.0'.freeze
3
3
  end
@@ -1,96 +1,46 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardless::Bill do
4
- before :each do
5
- @app_id = 'abc'
6
- @app_secret = 'xyz'
7
- GoCardless.account_details = {:app_id => @app_id, :app_secret => @app_secret,
8
- :token => 'xxx', :merchant_id => '1'}
9
- @client = GoCardless.client
4
+ before do
5
+ GoCardless.account_details = {:app_id => 'abc', :app_secret => 'xyz',
6
+ :token => 'xxx', :merchant_id => '123'}
10
7
  end
8
+ let(:client) { GoCardless.client }
9
+ let(:bill) { GoCardless::Bill.new(:id => 123) }
11
10
 
12
11
  it "source getter works" do
13
- b = GoCardless::Bill.new(:source_type => :subscription, :source_id => 123)
14
- @client.access_token = 'TOKEN'
15
- @client.merchant_id = '123'
16
- stub_get(@client, :id => 123)
17
- source = b.source
12
+ bill.source_id = 123
13
+ bill.source_type = :subscription
14
+ stub_get(client, :id => 123)
15
+ source = bill.source
18
16
  source.should be_a GoCardless::Subscription
19
17
  source.id.should == 123
20
18
  end
21
19
 
22
20
  it "source setter works" do
23
- b = GoCardless::Bill.new
24
- b.source = GoCardless::Subscription.new(:id => 123)
25
- b.source_id.should == 123
26
- b.source_type.should.to_s == 'subscription'
21
+ bill.source = GoCardless::Subscription.new(:id => 123)
22
+ bill.source_id.should == 123
23
+ bill.source_type.should.to_s == 'subscription'
27
24
  end
28
25
 
29
26
  it "should be able to be retried" do
30
- b = GoCardless::Bill.new(:id => 123)
31
- @client.should_receive(:api_post).with('/bills/123/retry')
32
- b.retry!
27
+ client.should_receive(:api_post).with('/bills/123/retry')
28
+ bill.retry!
33
29
  end
34
30
 
35
31
  it "should be able to be cancelled" do
36
- b = GoCardless::Bill.new(:id => 123)
37
- @client.should_receive(:api_put).with('/bills/123/cancel')
38
- b.cancel!
32
+ client.should_receive(:api_put).with('/bills/123/cancel')
33
+ bill.cancel!
39
34
  end
40
35
 
41
36
  it "should be able to be refunded" do
42
- b = GoCardless::Bill.new(:id => 123)
43
- @client.should_receive(:api_post).with('/bills/123/refund')
44
- b.refund!
37
+ client.should_receive(:api_post).with('/bills/123/refund')
38
+ bill.refund!
45
39
  end
46
40
 
47
- describe "pending query method" do
48
- it "and_return true when the subscription status is pending" do
49
- GoCardless::Bill.new(:status => 'pending').pending?.should be_true
50
- end
51
-
52
- it "and_return false otherwise" do
53
- GoCardless::Bill.new.pending?.should be_false
54
- end
55
- end
56
-
57
- describe "paid query method" do
58
- it "and_return true when the subscription status is paid" do
59
- GoCardless::Bill.new(:status => 'paid').paid?.should be_true
60
- end
61
-
62
- it "and_return false otherwise" do
63
- GoCardless::Bill.new.paid?.should be_false
64
- end
65
- end
66
-
67
- describe "failed query method" do
68
- it "and_return true when the subscription status is failed" do
69
- GoCardless::Bill.new(:status => 'failed').failed?.should be_true
70
- end
71
-
72
- it "and_return false otherwise" do
73
- GoCardless::Bill.new.failed?.should be_false
74
- end
75
- end
76
-
77
- describe "withdrawn query method" do
78
- it "and_return true when the subscription status is withdrawn" do
79
- GoCardless::Bill.new(:status => 'withdrawn').withdrawn?.should be_true
80
- end
81
-
82
- it "and_return false otherwise" do
83
- GoCardless::Bill.new.withdrawn?.should be_false
84
- end
85
- end
86
-
87
- describe "refunded query method" do
88
- it "and_return true when the subscription status is refunded" do
89
- GoCardless::Bill.new(:status => 'refunded').refunded?.should be_true
90
- end
91
-
92
- it "and_return false otherwise" do
93
- GoCardless::Bill.new.refunded?.should be_false
94
- end
95
- end
41
+ it_behaves_like "it has a query method for", "pending"
42
+ it_behaves_like "it has a query method for", "paid"
43
+ it_behaves_like "it has a query method for", "failed"
44
+ it_behaves_like "it has a query method for", "withdrawn"
45
+ it_behaves_like "it has a query method for", "refunded"
96
46
  end