recurly 2.9.3 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of recurly might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/README.md +1 -1
- data/lib/recurly.rb +1 -18
- data/lib/recurly/account.rb +1 -1
- data/lib/recurly/api.rb +1 -9
- data/lib/recurly/api/net_http_adapter.rb +0 -1
- data/lib/recurly/invoice.rb +1 -1
- data/lib/recurly/plan.rb +12 -0
- data/lib/recurly/purchase.rb +131 -0
- data/lib/recurly/resource.rb +24 -24
- data/lib/recurly/resource/pager.rb +3 -4
- data/lib/recurly/subscription.rb +1 -0
- data/lib/recurly/transaction.rb +1 -1
- data/lib/recurly/version.rb +2 -2
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2b2f5ee6a8f39d65f8f8b7bf0e7e28dc8fbfe5f7
|
4
|
+
data.tar.gz: 87bb6b057dd79daa33251094d2be8b4cf9030c80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44074d5b0f6e35dadb1a0d442be7f071b1f5a8466e838163afcb73cb9901f0b5ba5821916e2e1cd26c806f618940bbd1f2a32ced62610016cb86ba50dd76e875
|
7
|
+
data.tar.gz: '049c7dd6465aba53105a3d5d279d8a5cb9298dabb52be3c682020c0db665fce2e964b37a8fd21036d98226a9bd3b642b2902a294f29914b29a82ecf316dff170'
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Recurly is packaged as a Ruby gem. We recommend you install it with
|
|
14
14
|
[Bundler](http://gembundler.com/) by adding the following line to your Gemfile:
|
15
15
|
|
16
16
|
``` ruby
|
17
|
-
gem 'recurly', '~> 2.
|
17
|
+
gem 'recurly', '~> 2.10.0'
|
18
18
|
```
|
19
19
|
|
20
20
|
Recurly will automatically use [Nokogiri](http://nokogiri.org/) (for a nice
|
data/lib/recurly.rb
CHANGED
@@ -30,6 +30,7 @@ module Recurly
|
|
30
30
|
require 'recurly/xml'
|
31
31
|
require 'recurly/delivery'
|
32
32
|
require 'recurly/gift_card'
|
33
|
+
require 'recurly/purchase'
|
33
34
|
require 'recurly/webhook'
|
34
35
|
|
35
36
|
@subdomain = nil
|
@@ -86,8 +87,6 @@ module Recurly
|
|
86
87
|
end
|
87
88
|
|
88
89
|
# Assigns a logger to log requests/responses and more.
|
89
|
-
# The logger can only be set if the environment variable
|
90
|
-
# `RECURLY_INSECURE_DEBUG` equals `true`.
|
91
90
|
#
|
92
91
|
# @return [Logger, nil]
|
93
92
|
# @example
|
@@ -99,22 +98,6 @@ module Recurly
|
|
99
98
|
# Recurly.logger = nil # Or Recurly.logger = Logger.new nil
|
100
99
|
attr_accessor :logger
|
101
100
|
|
102
|
-
def logger=(logger)
|
103
|
-
if ENV['RECURLY_INSECURE_DEBUG'].to_s.downcase == 'true'
|
104
|
-
@logger = logger
|
105
|
-
puts <<-MSG
|
106
|
-
[WARNING] Recurly logger enabled. The logger has the potential to leak
|
107
|
-
PII and should never be used in production environments.
|
108
|
-
MSG
|
109
|
-
else
|
110
|
-
puts <<-MSG
|
111
|
-
[WARNING] Recurly logger has been disabled. If you wish to use it,
|
112
|
-
only do so in a non-production environment and make sure
|
113
|
-
the `RECURLY_INSECURE_DEBUG` environment variable is set to `true`.
|
114
|
-
MSG
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
101
|
# Convenience logging method includes a Logger#progname dynamically.
|
119
102
|
# @return [true, nil]
|
120
103
|
def log level, message
|
data/lib/recurly/account.rb
CHANGED
@@ -17,7 +17,7 @@ module Recurly
|
|
17
17
|
has_many :subscriptions
|
18
18
|
has_many :transactions
|
19
19
|
has_many :redemptions
|
20
|
-
has_many :shipping_addresses,
|
20
|
+
has_many :shipping_addresses, readonly: false
|
21
21
|
|
22
22
|
# @return [BillingInfo, nil]
|
23
23
|
has_one :billing_info, :readonly => false
|
data/lib/recurly/api.rb
CHANGED
@@ -15,9 +15,8 @@ module Recurly
|
|
15
15
|
require 'recurly/api/errors'
|
16
16
|
|
17
17
|
@@base_uri = "https://api.recurly.com/v2/"
|
18
|
-
@@valid_domains = [".recurly.com"]
|
19
18
|
|
20
|
-
RECURLY_API_VERSION = '2.
|
19
|
+
RECURLY_API_VERSION = '2.6'
|
21
20
|
|
22
21
|
FORMATS = Helper.hash_with_indifferent_read_access(
|
23
22
|
'pdf' => 'application/pdf',
|
@@ -76,13 +75,6 @@ module Recurly
|
|
76
75
|
URI.parse @@base_uri.sub('api', Recurly.subdomain)
|
77
76
|
end
|
78
77
|
|
79
|
-
def validate_uri!(uri)
|
80
|
-
domain = @@valid_domains.detect { |d| uri.host.end_with?(d) }
|
81
|
-
unless domain
|
82
|
-
raise ArgumentError, "URI #{uri} is invalid. You may only make requests to a Recurly domain."
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
78
|
# @return [String]
|
87
79
|
def user_agent
|
88
80
|
"Recurly/#{Version}; #{RUBY_DESCRIPTION}"
|
data/lib/recurly/invoice.rb
CHANGED
@@ -18,7 +18,7 @@ module Recurly
|
|
18
18
|
# @return [Subscription]
|
19
19
|
belongs_to :subscription
|
20
20
|
# @return [Invoice]
|
21
|
-
belongs_to :original_invoice, class_name:
|
21
|
+
belongs_to :original_invoice, class_name: :Invoice
|
22
22
|
|
23
23
|
# This will only be present if the invoice has > 500 line items
|
24
24
|
# @return [Adjustment]
|
data/lib/recurly/plan.rb
CHANGED
@@ -29,9 +29,21 @@ module Recurly
|
|
29
29
|
setup_fee_revenue_schedule_type
|
30
30
|
tax_exempt
|
31
31
|
tax_code
|
32
|
+
trial_requires_billing_info
|
32
33
|
created_at
|
33
34
|
updated_at
|
34
35
|
)
|
35
36
|
alias to_param plan_code
|
37
|
+
|
38
|
+
#TODO this can be removed after the server update
|
39
|
+
def trial_requires_billing_info
|
40
|
+
val = read_attribute(:trial_requires_billing_info)
|
41
|
+
case val
|
42
|
+
when String
|
43
|
+
val == 'true'
|
44
|
+
else
|
45
|
+
val
|
46
|
+
end
|
47
|
+
end
|
36
48
|
end
|
37
49
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Recurly
|
2
|
+
# The Purchase object works a slightly differently than the rest of the models.
|
3
|
+
# You build up the purchase data into an object then pass to either:
|
4
|
+
# {Purchase.invoice!} or {Purchase.preview!} and it will
|
5
|
+
# return an {Invoice}.
|
6
|
+
#
|
7
|
+
# You can build your purchase object with a new account or an existing account.
|
8
|
+
# For an existing account, you just need an account_code:
|
9
|
+
# Recurly::Purchase.new({account: {account_code: 'myexistingaccount'}})
|
10
|
+
# or
|
11
|
+
# account = Recurly::Account.find('existing_account')
|
12
|
+
# Recurly::Purchase.new({account: account})
|
13
|
+
# or
|
14
|
+
# account = Recurly::Account.find('existing_account')
|
15
|
+
# purchase = Recurly::Purchase.new
|
16
|
+
# purchase.account = account
|
17
|
+
#
|
18
|
+
# For a new account, you can pass in {Account} data, {BillingInfo} data, etc
|
19
|
+
# in the same way you would when creating a {Subscription} with a new account.
|
20
|
+
#
|
21
|
+
# You can also pass in adjustments and invoicing data to be passed to the invoice.
|
22
|
+
# Here is an example of a Purchase with a new account:
|
23
|
+
# require 'securerandom'
|
24
|
+
#
|
25
|
+
# purchase = Recurly::Purchase.new({
|
26
|
+
# currency: 'USD',
|
27
|
+
# collection_method: :automatic,
|
28
|
+
# account: {
|
29
|
+
# account_code: SecureRandom.uuid,
|
30
|
+
# billing_info: {
|
31
|
+
# first_name: 'Benjamin',
|
32
|
+
# last_name: 'Du Monde',
|
33
|
+
# address1: '400 Alabama St',
|
34
|
+
# city: 'San Francisco',
|
35
|
+
# state: 'CA',
|
36
|
+
# zip: '94110',
|
37
|
+
# country: 'US',
|
38
|
+
# number: '4111-1111-1111-1111',
|
39
|
+
# month: 12,
|
40
|
+
# year: 2019,
|
41
|
+
# }
|
42
|
+
# },
|
43
|
+
# adjustments: [
|
44
|
+
# {
|
45
|
+
# product_code: 'product_1',
|
46
|
+
# unit_amount_in_cents: 1000,
|
47
|
+
# quantity: 1,
|
48
|
+
# revenue_schedule_type: :at_invoice
|
49
|
+
# },
|
50
|
+
# {
|
51
|
+
# product_code: 'product_2'
|
52
|
+
# unit_amount_in_cents: 3000,
|
53
|
+
# quantity: 5,
|
54
|
+
# revenue_schedule_type: :at_invoice
|
55
|
+
# }
|
56
|
+
# ]
|
57
|
+
# })
|
58
|
+
#
|
59
|
+
# begin
|
60
|
+
# preview_invoice = Recurly::Purchase.invoice!(purchase)
|
61
|
+
# puts preview_invoice.inspect
|
62
|
+
# rescue Recurly::Resource::Invalid => e
|
63
|
+
# # Invalid data
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# begin
|
67
|
+
# invoice = Recurly::Purchase.invoice!(purchase)
|
68
|
+
# rescue Recurly::Resource::Invalid => e
|
69
|
+
# # Invalid data
|
70
|
+
# rescue Recurly::Transaction::DeclinedError => e
|
71
|
+
# # Display e.message and/or subscription (and associated) errors...
|
72
|
+
# rescue Recurly::Transaction::RetryableError => e
|
73
|
+
# # You should be able to attempt to save this again later.
|
74
|
+
# rescue Recurly::Transaction::Error => e
|
75
|
+
# # Fallback transaction error
|
76
|
+
# # e.transaction
|
77
|
+
# # e.transaction_error_code
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
class Purchase < Resource
|
81
|
+
# @return [[Adjustment], nil]
|
82
|
+
has_many :adjustments, class_name: :Adjustment, readonly: false
|
83
|
+
|
84
|
+
# @return [Account, nil]
|
85
|
+
has_one :account, readonly: false
|
86
|
+
|
87
|
+
define_attribute_methods %w(
|
88
|
+
currency
|
89
|
+
collection_method
|
90
|
+
po_number
|
91
|
+
net_terms
|
92
|
+
)
|
93
|
+
|
94
|
+
class << self
|
95
|
+
|
96
|
+
# Generate an invoice for the purchase and run any needed transactions
|
97
|
+
#
|
98
|
+
# @param purchase [Purchase] The purchase data for the request
|
99
|
+
# @return [Invoice] The new invoice representing this purchase
|
100
|
+
# @raise [Invalid] Raised if the account cannot be invoiced.
|
101
|
+
# @raise [Transaction::Error] Raised if the transaction failed
|
102
|
+
def invoice!(purchase)
|
103
|
+
post(purchase, collection_path)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Generate a preview invoice for the purchase. Runs validations
|
107
|
+
# but does not run any transactions.
|
108
|
+
#
|
109
|
+
# @param purchase [Purchase] The purchase data for the request
|
110
|
+
# @return [Invoice] The new invoice representing this purchase
|
111
|
+
# @raise [Invalid] Raised if the account cannot be invoiced.
|
112
|
+
def preview!(purchase)
|
113
|
+
post(purchase, "#{collection_path}/preview")
|
114
|
+
end
|
115
|
+
|
116
|
+
def post(purchase, path)
|
117
|
+
response = API.send(:post, path, purchase.to_xml)
|
118
|
+
Invoice.from_response(response)
|
119
|
+
rescue API::UnprocessableEntity => e
|
120
|
+
purchase.apply_errors(e)
|
121
|
+
Transaction::Error.validate!(e, nil)
|
122
|
+
raise Resource::Invalid.new(purchase)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# This object does not represent a model on the server side
|
127
|
+
# so we do not need to expose thses methods.
|
128
|
+
protected(*%w(save save!))
|
129
|
+
private_class_method(*%w(all find_each first paginate scoped where post create! create))
|
130
|
+
end
|
131
|
+
end
|
data/lib/recurly/resource.rb
CHANGED
@@ -163,7 +163,6 @@ module Recurly
|
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
|
-
|
167
166
|
class << self
|
168
167
|
# @return [String] The demodulized name of the resource class.
|
169
168
|
# @example
|
@@ -336,8 +335,9 @@ module Recurly
|
|
336
335
|
raise NotFound, "can't find a record with nil identifier"
|
337
336
|
end
|
338
337
|
|
338
|
+
uri = uuid =~ /^http/ ? uuid : member_path(uuid)
|
339
339
|
begin
|
340
|
-
from_response API.get(
|
340
|
+
from_response API.get(uri, {}, options)
|
341
341
|
rescue API::NotFound => e
|
342
342
|
raise NotFound, e.description
|
343
343
|
end
|
@@ -509,7 +509,7 @@ module Recurly
|
|
509
509
|
# @param collection_name [Symbol] Association name.
|
510
510
|
# @param options [Hash] A hash of association options.
|
511
511
|
# @option options [true, false] :readonly Don't define a setter.
|
512
|
-
# [String] :
|
512
|
+
# [String] :class_name Actual associated resource class name
|
513
513
|
# if not same as collection_name.
|
514
514
|
def has_many(collection_name, options = {})
|
515
515
|
associations << Association.new(:has_many, collection_name.to_s, options)
|
@@ -535,7 +535,7 @@ module Recurly
|
|
535
535
|
# @param member_name [Symbol] Association name.
|
536
536
|
# @param options [Hash] A hash of association options.
|
537
537
|
# @option options [true, false] :readonly Don't define a setter.
|
538
|
-
# [String] :
|
538
|
+
# [String] :class_name Actual associated resource class name
|
539
539
|
# if not same as member_name.
|
540
540
|
def has_one(member_name, options = {})
|
541
541
|
associations << Association.new(:has_one, member_name.to_s, options)
|
@@ -573,7 +573,7 @@ module Recurly
|
|
573
573
|
# @param parent_name [Symbol] Association name.
|
574
574
|
# @param options [Hash] A hash of association options.
|
575
575
|
# @option options [true, false] :readonly Don't define a setter.
|
576
|
-
# [String] :
|
576
|
+
# [String] :class_name Actual associated resource class name
|
577
577
|
# if not same as parent_name.
|
578
578
|
def belongs_to(parent_name, options = {})
|
579
579
|
associations << Association.new(:belongs_to, parent_name.to_s, options)
|
@@ -634,12 +634,9 @@ module Recurly
|
|
634
634
|
return if response.body.to_s.length.zero?
|
635
635
|
fresh = self.class.from_response response
|
636
636
|
else
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
else
|
641
|
-
self.class.find(to_param, options)
|
642
|
-
end
|
637
|
+
fresh = self.class.find(
|
638
|
+
@href || to_param, :etag => (etag unless changed?)
|
639
|
+
)
|
643
640
|
end
|
644
641
|
fresh and copy_from fresh
|
645
642
|
persist! true
|
@@ -849,7 +846,7 @@ module Recurly
|
|
849
846
|
if new_record? || changed?
|
850
847
|
clear_errors
|
851
848
|
@response = API.send(
|
852
|
-
persisted? ? :put : :post, path, to_xml
|
849
|
+
persisted? ? :put : :post, path, to_xml
|
853
850
|
)
|
854
851
|
reload response
|
855
852
|
persist! true
|
@@ -1026,6 +1023,15 @@ module Recurly
|
|
1026
1023
|
end
|
1027
1024
|
alias to_s inspect
|
1028
1025
|
|
1026
|
+
def apply_errors(exception)
|
1027
|
+
@response = exception.response
|
1028
|
+
document = XML.new exception.response.body
|
1029
|
+
document.each_element 'error' do |el|
|
1030
|
+
attribute_path = el.attribute('field').value.split '.'
|
1031
|
+
invalid! attribute_path[1, attribute_path.length], el.text
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1029
1035
|
protected
|
1030
1036
|
|
1031
1037
|
def path
|
@@ -1064,23 +1070,17 @@ module Recurly
|
|
1064
1070
|
end
|
1065
1071
|
end
|
1066
1072
|
|
1067
|
-
def apply_errors(exception)
|
1068
|
-
@response = exception.response
|
1069
|
-
document = XML.new exception.response.body
|
1070
|
-
document.each_element 'error' do |el|
|
1071
|
-
attribute_path = el.attribute('field').value.split '.'
|
1072
|
-
invalid! attribute_path[1, attribute_path.length], el.text
|
1073
|
-
end
|
1074
|
-
end
|
1075
|
-
|
1076
1073
|
private
|
1077
1074
|
|
1078
|
-
def fetch_associated(name, value)
|
1075
|
+
def fetch_associated(name, value, options = {})
|
1079
1076
|
case value
|
1080
1077
|
when Array
|
1081
|
-
value.map
|
1078
|
+
value.map do |v|
|
1079
|
+
fetch_associated(Helper.singularize(name), v, association_name: name)
|
1080
|
+
end
|
1082
1081
|
when Hash
|
1083
|
-
|
1082
|
+
association_name = options[:association_name] || name
|
1083
|
+
associated_class_name = self.class.find_association(association_name).class_name
|
1084
1084
|
associated_class_name ||= Helper.classify(name)
|
1085
1085
|
Recurly.const_get(associated_class_name, false).send(:new, value)
|
1086
1086
|
when Proc, Resource, Resource::Pager, nil
|
@@ -65,7 +65,7 @@ module Recurly
|
|
65
65
|
@uri = options.delete :uri
|
66
66
|
@etag = options.delete :etag
|
67
67
|
@resource_class, @options = resource_class, options
|
68
|
-
@collection =
|
68
|
+
@collection = nil
|
69
69
|
end
|
70
70
|
|
71
71
|
# @return [Boolean] whether or not the xml element is present
|
@@ -81,7 +81,7 @@ module Recurly
|
|
81
81
|
# @return [Integer] The total record count of the resource in question.
|
82
82
|
# @see Resource.count
|
83
83
|
def count
|
84
|
-
|
84
|
+
API.head(uri, @options)['X-Records'].to_i
|
85
85
|
end
|
86
86
|
|
87
87
|
# @return [Array] Iterates through the current page of records.
|
@@ -134,7 +134,7 @@ module Recurly
|
|
134
134
|
# Recurly::Account.active.paginate :per_page => 20
|
135
135
|
def paginate options = {}
|
136
136
|
dup.instance_eval {
|
137
|
-
@collection = @
|
137
|
+
@collection = @etag = nil
|
138
138
|
@options = @options.merge options
|
139
139
|
self
|
140
140
|
}
|
@@ -220,7 +220,6 @@ module Recurly
|
|
220
220
|
response = API.get uri, params, options
|
221
221
|
|
222
222
|
@etag = response['ETag']
|
223
|
-
@count = response['X-Records'].to_i
|
224
223
|
@links = {}
|
225
224
|
if links = response['Link']
|
226
225
|
links.scan(/<([^>]+)>; rel="([^"]+)"/).each do |link, rel|
|
data/lib/recurly/subscription.rb
CHANGED
data/lib/recurly/transaction.rb
CHANGED
@@ -21,7 +21,7 @@ module Recurly
|
|
21
21
|
belongs_to :subscription
|
22
22
|
|
23
23
|
# @return [Transaction, nil]
|
24
|
-
has_one :original_transaction, class_name:
|
24
|
+
has_one :original_transaction, class_name: :Transaction, readonly: true
|
25
25
|
|
26
26
|
define_attribute_methods %w(
|
27
27
|
id
|
data/lib/recurly/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recurly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Recurly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 11.
|
33
|
+
version: '11.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 11.
|
40
|
+
version: '11.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,6 +171,7 @@ files:
|
|
171
171
|
- lib/recurly/measured_unit.rb
|
172
172
|
- lib/recurly/money.rb
|
173
173
|
- lib/recurly/plan.rb
|
174
|
+
- lib/recurly/purchase.rb
|
174
175
|
- lib/recurly/redemption.rb
|
175
176
|
- lib/recurly/resource.rb
|
176
177
|
- lib/recurly/resource/association.rb
|
@@ -238,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
238
239
|
version: '0'
|
239
240
|
requirements: []
|
240
241
|
rubyforge_project:
|
241
|
-
rubygems_version: 2.
|
242
|
+
rubygems_version: 2.6.8
|
242
243
|
signing_key:
|
243
244
|
specification_version: 4
|
244
245
|
summary: Recurly API Client
|