recurly 0.4.16 → 2.0.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.
- data/README.markdown +118 -0
- data/bin/recurly +78 -0
- data/lib/rails/generators/recurly/config_generator.rb +16 -0
- data/lib/rails/recurly.rb +13 -0
- data/lib/recurly.rb +64 -139
- data/lib/recurly/account.rb +52 -111
- data/lib/recurly/add_on.rb +20 -0
- data/lib/recurly/adjustment.rb +51 -0
- data/lib/recurly/api.rb +73 -0
- data/lib/recurly/api/errors.rb +205 -0
- data/lib/recurly/api/net_http.rb +77 -0
- data/lib/recurly/billing_info.rb +45 -42
- data/lib/recurly/coupon.rb +63 -8
- data/lib/recurly/helper.rb +39 -0
- data/lib/recurly/invoice.rb +38 -16
- data/lib/recurly/js.rb +113 -0
- data/lib/recurly/money.rb +105 -0
- data/lib/recurly/plan.rb +26 -15
- data/lib/recurly/redemption.rb +34 -0
- data/lib/recurly/resource.rb +925 -0
- data/lib/recurly/resource/pager.rb +210 -0
- data/lib/recurly/subscription.rb +90 -67
- data/lib/recurly/subscription/add_ons.rb +73 -0
- data/lib/recurly/transaction.rb +65 -53
- data/lib/recurly/transaction/errors.rb +98 -0
- data/lib/recurly/version.rb +16 -2
- data/lib/recurly/xml.rb +85 -0
- data/lib/recurly/xml/nokogiri.rb +49 -0
- data/lib/recurly/xml/rexml.rb +50 -0
- metadata +76 -165
- data/LICENSE +0 -21
- data/README.md +0 -104
- data/init.rb +0 -1
- data/lib/patches/rails2/active_resource/base.rb +0 -35
- data/lib/patches/rails2/active_resource/connection.rb +0 -10
- data/lib/patches/rails3/active_model/serializers/xml.rb +0 -28
- data/lib/patches/rails3/active_resource/connection.rb +0 -10
- data/lib/recurly/account_base.rb +0 -35
- data/lib/recurly/base.rb +0 -195
- data/lib/recurly/charge.rb +0 -39
- data/lib/recurly/config_parser.rb +0 -31
- data/lib/recurly/credit.rb +0 -28
- data/lib/recurly/exceptions.rb +0 -32
- data/lib/recurly/formats/xml_with_errors.rb +0 -132
- data/lib/recurly/formats/xml_with_pagination.rb +0 -47
- data/lib/recurly/rails2/compatibility.rb +0 -8
- data/lib/recurly/rails3/railtie.rb +0 -21
- data/lib/recurly/rails3/recurly.rake +0 -28
- data/lib/recurly/transparent.rb +0 -148
- data/lib/recurly/verification.rb +0 -83
- data/spec/config/recurly.yml +0 -6
- data/spec/config/test1.yml +0 -4
- data/spec/config/test2.yml +0 -7
- data/spec/integration/account_spec.rb +0 -286
- data/spec/integration/add_on_spec.rb +0 -84
- data/spec/integration/billing_info_spec.rb +0 -148
- data/spec/integration/charge_spec.rb +0 -176
- data/spec/integration/coupon_spec.rb +0 -49
- data/spec/integration/credit_spec.rb +0 -106
- data/spec/integration/invoice_spec.rb +0 -86
- data/spec/integration/plan_spec.rb +0 -87
- data/spec/integration/subscription_spec.rb +0 -221
- data/spec/integration/transaction_spec.rb +0 -154
- data/spec/integration/transparent_spec.rb +0 -99
- data/spec/spec_helper.rb +0 -34
- data/spec/support/factory.rb +0 -211
- data/spec/support/vcr.rb +0 -11
- data/spec/unit/account_spec.rb +0 -19
- data/spec/unit/billing_info_spec.rb +0 -39
- data/spec/unit/charge_spec.rb +0 -20
- data/spec/unit/config_spec.rb +0 -42
- data/spec/unit/coupon_spec.rb +0 -13
- data/spec/unit/credit_spec.rb +0 -20
- data/spec/unit/plan_spec.rb +0 -18
- data/spec/unit/subscription_spec.rb +0 -25
- data/spec/unit/transaction_spec.rb +0 -32
- data/spec/unit/transparent_spec.rb +0 -152
- data/spec/unit/verification_spec.rb +0 -82
@@ -0,0 +1,20 @@
|
|
1
|
+
module Recurly
|
2
|
+
class AddOn < Resource
|
3
|
+
# @return [Plan]
|
4
|
+
belongs_to :plan
|
5
|
+
|
6
|
+
define_attribute_methods %w(
|
7
|
+
add_on_code
|
8
|
+
name
|
9
|
+
default_quantity
|
10
|
+
unit_amount_in_cents
|
11
|
+
display_quantity_on_hosted_page
|
12
|
+
created_at
|
13
|
+
)
|
14
|
+
alias to_param add_on_code
|
15
|
+
|
16
|
+
# Add-ons are only writeable and readable through {Plan} instances.
|
17
|
+
embedded!
|
18
|
+
private_class_method :find
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Recurly
|
2
|
+
class Adjustment < Resource
|
3
|
+
# @macro [attach] scope
|
4
|
+
# @scope class
|
5
|
+
# @return [Pager<Adjustment>] a pager that yields +$1+.
|
6
|
+
scope :charges, :type => 'charge'
|
7
|
+
scope :credits, :type => 'credit'
|
8
|
+
|
9
|
+
scope :pending, :state => 'pending'
|
10
|
+
scope :invoiced, :state => 'invoiced'
|
11
|
+
|
12
|
+
# @return [Account, nil]
|
13
|
+
belongs_to :account
|
14
|
+
# @return [Invoice, nil]
|
15
|
+
belongs_to :invoice
|
16
|
+
|
17
|
+
define_attribute_methods %w(
|
18
|
+
uuid
|
19
|
+
description
|
20
|
+
accounting_code
|
21
|
+
origin
|
22
|
+
unit_amount_in_cents
|
23
|
+
quantity
|
24
|
+
discount_in_cents
|
25
|
+
tax_in_cents
|
26
|
+
total_in_cents
|
27
|
+
currency
|
28
|
+
taxable
|
29
|
+
start_date
|
30
|
+
end_date
|
31
|
+
created_at
|
32
|
+
)
|
33
|
+
alias to_param uuid
|
34
|
+
|
35
|
+
# @return ["charge", "credit", nil] The type of adjustment.
|
36
|
+
attr_reader :type
|
37
|
+
|
38
|
+
# Adjustments should be built through {Account} instances.
|
39
|
+
#
|
40
|
+
# @return [Adjustment] A new adjustment.
|
41
|
+
# @example
|
42
|
+
# account.adjustments.new attributes
|
43
|
+
# @see Resource#initialize
|
44
|
+
def initialize attributes = {}
|
45
|
+
super({ :currency => Recurly.default_currency }.merge attributes)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Adjustments are only writeable through an {Account} instance.
|
49
|
+
embedded!
|
50
|
+
end
|
51
|
+
end
|
data/lib/recurly/api.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module Recurly
|
2
|
+
# The API class handles all requests to the Recurly API. While most of its
|
3
|
+
# functionality is leveraged by the Resource class, it can be used directly,
|
4
|
+
# as well.
|
5
|
+
#
|
6
|
+
# Requests are made with methods named after the four main HTTP verbs
|
7
|
+
# recognized by the Recurly API.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# Recurly::API.get 'accounts' # => #<Net::HTTPOK ...>
|
11
|
+
# Recurly::API.post 'accounts', xml_body # => #<Net::HTTPCreated ...>
|
12
|
+
# Recurly::API.put 'accounts/1', xml_body # => #<Net::HTTPOK ...>
|
13
|
+
# Recurly::API.delete 'accounts/1' # => #<Net::HTTPNoContent ...>
|
14
|
+
class API
|
15
|
+
require 'recurly/api/errors'
|
16
|
+
|
17
|
+
@@base_uri = "https://api.recurly.com/v2/"
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :accept_language
|
22
|
+
|
23
|
+
# @return [Net::HTTPOK, Net::HTTPResponse]
|
24
|
+
# @raise [ResponseError] With a non-2xx status code.
|
25
|
+
def head uri, params = {}, options = {}
|
26
|
+
request :head, uri, { :params => params }.merge(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Net::HTTPOK, Net::HTTPResponse]
|
30
|
+
# @raise [ResponseError] With a non-2xx status code.
|
31
|
+
def get uri, params = {}, options = {}
|
32
|
+
request :get, uri, { :params => params }.merge(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Net::HTTPCreated, Net::HTTPResponse]
|
36
|
+
# @raise [ResponseError] With a non-2xx status code.
|
37
|
+
def post uri, body = nil, options = {}
|
38
|
+
request :post, uri, { :body => body.to_s }.merge(options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Net::HTTPOK, Net::HTTPResponse]
|
42
|
+
# @raise [ResponseError] With a non-2xx status code.
|
43
|
+
def put uri, body = nil, options = {}
|
44
|
+
request :put, uri, { :body => body.to_s }.merge(options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Net::HTTPNoContent, Net::HTTPResponse]
|
48
|
+
# @raise [ResponseError] With a non-2xx status code.
|
49
|
+
def delete uri, options = {}
|
50
|
+
request :delete, uri, options
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [URI::Generic]
|
54
|
+
def base_uri
|
55
|
+
URI.parse @@base_uri
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [String]
|
59
|
+
def user_agent
|
60
|
+
"Recurly/#{Version::VERSION}; #{RUBY_DESCRIPTION}"
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def accept
|
66
|
+
'application/xml'
|
67
|
+
end
|
68
|
+
alias content_type accept
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
require 'recurly/api/net_http'
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Recurly
|
4
|
+
class API
|
5
|
+
# The superclass to all errors that occur when making an API request.
|
6
|
+
class ResponseError < Error
|
7
|
+
attr_reader :request
|
8
|
+
attr_reader :response
|
9
|
+
|
10
|
+
def initialize request, response
|
11
|
+
@request, @response = request, response
|
12
|
+
end
|
13
|
+
|
14
|
+
def code
|
15
|
+
response.code.to_i if response
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
if description
|
20
|
+
return CGI.unescapeHTML [description, details].compact.join(' ')
|
21
|
+
end
|
22
|
+
|
23
|
+
return super unless code
|
24
|
+
"%d %s (%s %s)" % [
|
25
|
+
code, http_error, request.method, API.base_uri + request.path
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
def symbol
|
30
|
+
xml and xml.root and xml.text '/error/symbol'
|
31
|
+
end
|
32
|
+
|
33
|
+
def description
|
34
|
+
xml and xml.root and xml.text '/error/description'
|
35
|
+
end
|
36
|
+
|
37
|
+
def details
|
38
|
+
xml and xml.root and xml.text '/error/details'
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def http_error
|
44
|
+
Helper.demodulize self.class.name.gsub(/([a-z])([A-Z])/, '\1 \2')
|
45
|
+
end
|
46
|
+
|
47
|
+
def xml
|
48
|
+
return @xml if defined? @xml
|
49
|
+
@xml = (XML.new(response.body) if response && !response.body.empty?)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# === 3xx Redirection
|
54
|
+
#
|
55
|
+
# Not an error, per se, but should result in one in the normal course of
|
56
|
+
# API interaction.
|
57
|
+
class Redirection < ResponseError
|
58
|
+
end
|
59
|
+
|
60
|
+
# === 304 Not Modified
|
61
|
+
#
|
62
|
+
# Catchably raised when a request is made with an ETag.
|
63
|
+
class NotModified < ResponseError
|
64
|
+
end
|
65
|
+
|
66
|
+
# === 4xx Client Error
|
67
|
+
#
|
68
|
+
# The superclass to all client errors (responses with status code 4xx).
|
69
|
+
class ClientError < ResponseError
|
70
|
+
end
|
71
|
+
|
72
|
+
# === 400 Bad Request
|
73
|
+
#
|
74
|
+
# The request was invalid or could not be understood by the server.
|
75
|
+
# Resubmitting the request will likely result in the same error.
|
76
|
+
class BadRequest < ClientError
|
77
|
+
end
|
78
|
+
|
79
|
+
# === 401 Unauthorized
|
80
|
+
#
|
81
|
+
# The API key is missing or invalid for the given request.
|
82
|
+
class Unauthorized < ClientError
|
83
|
+
def description
|
84
|
+
response.body.strip
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# === 402 Payment Required
|
89
|
+
#
|
90
|
+
# Your Recurly account is in production mode but is not in good standing.
|
91
|
+
# Please pay any outstanding invoices.
|
92
|
+
class PaymentRequired < ClientError
|
93
|
+
end
|
94
|
+
|
95
|
+
# === 403 Forbidden
|
96
|
+
#
|
97
|
+
# The login is attempting to perform an action it does not have privileges
|
98
|
+
# to access. The login credentials are correct.
|
99
|
+
class Forbidden < ClientError
|
100
|
+
end
|
101
|
+
|
102
|
+
# === 404 Not Found
|
103
|
+
#
|
104
|
+
# The resource was not found. This may be returned if the given account
|
105
|
+
# code or subscription plan does not exist. The response body will explain
|
106
|
+
# which resource was not found.
|
107
|
+
class NotFound < ClientError
|
108
|
+
end
|
109
|
+
|
110
|
+
# === 405 Method Not Allowed
|
111
|
+
#
|
112
|
+
# A method was attempted where it is not allowed.
|
113
|
+
#
|
114
|
+
# If this is raised, there may be a bug with the client library or with
|
115
|
+
# the server. Please contact support@recurly.com or
|
116
|
+
# {file a bug}[https://github.com/recurly/recurly-client-ruby/issues].
|
117
|
+
class MethodNotAllowed < ClientError
|
118
|
+
end
|
119
|
+
|
120
|
+
# === 406 Not Acceptable
|
121
|
+
#
|
122
|
+
# The request content type was not acceptable.
|
123
|
+
#
|
124
|
+
# If this is raised, there may be a bug with the client library or with
|
125
|
+
# the server. Please contact support@recurly.com or
|
126
|
+
# {file a bug}[https://github.com/recurly/recurly-client-ruby/issues].
|
127
|
+
class NotAcceptable < ClientError
|
128
|
+
end
|
129
|
+
|
130
|
+
# === 412 Precondition Failed
|
131
|
+
#
|
132
|
+
# The request was unsuccessful because a condition was not met. For
|
133
|
+
# example, this message may be returned if you attempt to cancel a
|
134
|
+
# subscription for an account that has no subscription.
|
135
|
+
class PreconditionFailed < ClientError
|
136
|
+
end
|
137
|
+
|
138
|
+
# === 415 Unsupported Media Type
|
139
|
+
#
|
140
|
+
# The request body was not recognized as XML.
|
141
|
+
#
|
142
|
+
# If this is raised, there may be a bug with the client library or with
|
143
|
+
# the server. Please contact support@recurly.com or
|
144
|
+
# {file a bug}[https://github.com/recurly/recurly-client-ruby/issues].
|
145
|
+
class UnsupportedMediaType < ClientError
|
146
|
+
end
|
147
|
+
|
148
|
+
# === 422 Unprocessable Entity
|
149
|
+
#
|
150
|
+
# Could not process a POST or PUT request because the request is invalid.
|
151
|
+
# See the response body for more details.
|
152
|
+
class UnprocessableEntity < ClientError
|
153
|
+
end
|
154
|
+
|
155
|
+
# === 5xx Server Error
|
156
|
+
#
|
157
|
+
# The superclass to all server errors (responses with status code 5xx).
|
158
|
+
class ServerError < ResponseError
|
159
|
+
end
|
160
|
+
|
161
|
+
# === 500 Internal Server Error
|
162
|
+
#
|
163
|
+
# The server encountered an error while processing your request and failed.
|
164
|
+
class InternalServerError < ServerError
|
165
|
+
end
|
166
|
+
|
167
|
+
# === 502 Gateway Error
|
168
|
+
#
|
169
|
+
# The load balancer or web server had trouble connecting to the Recurly.
|
170
|
+
# Please try the request again.
|
171
|
+
class GatewayError < ServerError
|
172
|
+
end
|
173
|
+
|
174
|
+
# === 503 Service Unavailable
|
175
|
+
#
|
176
|
+
# The service is temporarily unavailable. Please try the request again.
|
177
|
+
class ServiceUnavailable < ServerError
|
178
|
+
end
|
179
|
+
|
180
|
+
# Error mapping by status code.
|
181
|
+
ERRORS = Hash.new { |hash, code|
|
182
|
+
unless hash.key? code
|
183
|
+
case code
|
184
|
+
when 400...500 then ClientError
|
185
|
+
when 500...600 then ServerError
|
186
|
+
else ResponseError
|
187
|
+
end
|
188
|
+
end
|
189
|
+
}.update(
|
190
|
+
304 => NotModified,
|
191
|
+
400 => BadRequest,
|
192
|
+
401 => Unauthorized,
|
193
|
+
402 => PaymentRequired,
|
194
|
+
403 => Forbidden,
|
195
|
+
404 => NotFound,
|
196
|
+
406 => NotAcceptable,
|
197
|
+
412 => PreconditionFailed,
|
198
|
+
415 => UnsupportedMediaType,
|
199
|
+
422 => UnprocessableEntity,
|
200
|
+
500 => InternalServerError,
|
201
|
+
502 => GatewayError,
|
202
|
+
503 => ServiceUnavailable
|
203
|
+
).freeze
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
|
3
|
+
module Recurly
|
4
|
+
class API
|
5
|
+
module Net
|
6
|
+
module HTTP
|
7
|
+
private
|
8
|
+
|
9
|
+
METHODS = {
|
10
|
+
:head => ::Net::HTTP::Head,
|
11
|
+
:get => ::Net::HTTP::Get,
|
12
|
+
:post => ::Net::HTTP::Post,
|
13
|
+
:put => ::Net::HTTP::Put,
|
14
|
+
:delete => ::Net::HTTP::Delete
|
15
|
+
}
|
16
|
+
|
17
|
+
def request method, uri, options = {}
|
18
|
+
head = { 'Accept' => accept, 'User-Agent' => user_agent }
|
19
|
+
accept_language and head['Accept-Language'] ||= accept_language
|
20
|
+
head.update options[:head] if options[:head]
|
21
|
+
uri = base_uri + uri
|
22
|
+
if options[:params] && !options[:params].empty?
|
23
|
+
uri += "?#{options[:params].map { |k, v| "#{k}=#{v}" }.join '&' }"
|
24
|
+
end
|
25
|
+
request = METHODS[method].new uri.request_uri, head
|
26
|
+
request.basic_auth Recurly.api_key, nil
|
27
|
+
if options[:body]
|
28
|
+
head['Content-Type'] = content_type
|
29
|
+
request.body = options[:body]
|
30
|
+
end
|
31
|
+
http = ::Net::HTTP.new uri.host, uri.port
|
32
|
+
http.use_ssl = uri.scheme == 'https'
|
33
|
+
|
34
|
+
if Recurly.logger
|
35
|
+
Recurly.log :info, "===> %s %s" % [request.method, uri]
|
36
|
+
headers = request.to_hash
|
37
|
+
headers['authorization'] &&= ['Basic [FILTERED]']
|
38
|
+
Recurly.log :debug, headers.inspect
|
39
|
+
if request.body && !request.body.empty?
|
40
|
+
Recurly.log :debug, XML.filter(request.body)
|
41
|
+
end
|
42
|
+
start_time = Time.now
|
43
|
+
end
|
44
|
+
|
45
|
+
response = http.start { http.request request }
|
46
|
+
code = response.code.to_i
|
47
|
+
|
48
|
+
if Recurly.logger
|
49
|
+
latency = (Time.now - start_time) * 1_000
|
50
|
+
level = case code
|
51
|
+
when 200...300 then :info
|
52
|
+
when 300...400 then :warn
|
53
|
+
when 400...500 then :error
|
54
|
+
else :fatal
|
55
|
+
end
|
56
|
+
Recurly.log level, "<=== %d %s (%.1fms)" % [
|
57
|
+
code,
|
58
|
+
response.class.name[9, response.class.name.length].gsub(
|
59
|
+
/([a-z])([A-Z])/, '\1 \2'
|
60
|
+
),
|
61
|
+
latency
|
62
|
+
]
|
63
|
+
Recurly.log :debug, response.to_hash.inspect
|
64
|
+
Recurly.log :debug, response.body if response.body
|
65
|
+
end
|
66
|
+
|
67
|
+
case code
|
68
|
+
when 200...300 then response
|
69
|
+
else raise ERRORS[code].new request, response
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
extend Net::HTTP
|
76
|
+
end
|
77
|
+
end
|
data/lib/recurly/billing_info.rb
CHANGED
@@ -1,49 +1,52 @@
|
|
1
1
|
module Recurly
|
2
|
-
class BillingInfo <
|
3
|
-
|
2
|
+
class BillingInfo < Resource
|
3
|
+
# @return [Account]
|
4
|
+
belongs_to :account
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
6
|
+
define_attribute_methods %w(
|
7
|
+
first_name
|
8
|
+
last_name
|
9
|
+
company
|
10
|
+
address1
|
11
|
+
address2
|
12
|
+
city
|
13
|
+
state
|
14
|
+
zip
|
15
|
+
country
|
16
|
+
phone
|
17
|
+
vat_number
|
18
|
+
ip_address
|
19
|
+
ip_address_country
|
20
|
+
card_type
|
21
|
+
year
|
22
|
+
month
|
23
|
+
start_year
|
24
|
+
start_month
|
25
|
+
issue_number
|
26
|
+
first_six
|
27
|
+
last_four
|
28
|
+
paypal_billing_agreement_id
|
29
|
+
)
|
20
30
|
|
21
|
-
#
|
22
|
-
|
23
|
-
def self.known_attributes
|
24
|
-
[
|
25
|
-
"number",
|
26
|
-
"last_four",
|
27
|
-
"type",
|
28
|
-
"verification_value",
|
29
|
-
"month",
|
30
|
-
"year",
|
31
|
-
"start_month",
|
32
|
-
"start_year",
|
33
|
-
"issue_number"
|
34
|
-
]
|
35
|
-
end
|
36
|
-
end
|
31
|
+
# @return ["credit_card", "paypal", nil] The type of billing info.
|
32
|
+
attr_reader :type
|
37
33
|
|
38
|
-
#
|
39
|
-
def
|
40
|
-
attributes =
|
41
|
-
|
42
|
-
|
34
|
+
# @return [String]
|
35
|
+
def inspect
|
36
|
+
attributes = self.class.attribute_names
|
37
|
+
case type
|
38
|
+
when 'credit_card'
|
39
|
+
attributes -= %w(paypal_billing_agreement_id)
|
40
|
+
when 'paypal'
|
41
|
+
attributes -= %w(
|
42
|
+
card_type year month start_year start_month issue_number
|
43
|
+
first_six last_four
|
44
|
+
)
|
45
|
+
end
|
46
|
+
super attributes
|
43
47
|
end
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
end
|
49
|
+
# Billing info is only writeable through an {Account} instance.
|
50
|
+
embedded!
|
48
51
|
end
|
49
|
-
end
|
52
|
+
end
|