paid 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -1
- data/.travis.yml +16 -0
- data/History.txt +4 -0
- data/README.md +58 -0
- data/Rakefile +9 -29
- data/VERSION +1 -0
- data/bin/paid-console +7 -0
- data/gemfiles/default-with-activesupport.gemfile +10 -0
- data/gemfiles/json.gemfile +12 -0
- data/gemfiles/yajl.gemfile +12 -0
- data/lib/paid.rb +129 -177
- data/lib/paid/account.rb +14 -1
- data/lib/paid/api_class.rb +336 -0
- data/lib/paid/api_list.rb +47 -0
- data/lib/paid/api_resource.rb +8 -25
- data/lib/paid/api_singleton.rb +5 -0
- data/lib/paid/customer.rb +36 -21
- data/lib/paid/errors/api_error.rb +6 -0
- data/lib/paid/event.rb +22 -1
- data/lib/paid/invoice.rb +16 -21
- data/lib/paid/plan.rb +18 -2
- data/lib/paid/subscription.rb +17 -11
- data/lib/paid/transaction.rb +19 -12
- data/lib/paid/util.rb +53 -106
- data/lib/paid/version.rb +1 -1
- data/paid.gemspec +10 -11
- data/tasks/api_test.rb +187 -0
- data/test/mock_resource.rb +69 -0
- data/test/paid/account_test.rb +41 -4
- data/test/paid/api_class_test.rb +412 -0
- data/test/paid/api_list_test.rb +17 -0
- data/test/paid/api_resource_test.rb +13 -343
- data/test/paid/api_singleton_test.rb +12 -0
- data/test/paid/authentication_test.rb +50 -0
- data/test/paid/customer_test.rb +189 -29
- data/test/paid/event_test.rb +74 -0
- data/test/paid/invoice_test.rb +101 -20
- data/test/paid/plan_test.rb +84 -8
- data/test/paid/status_codes_test.rb +63 -0
- data/test/paid/subscription_test.rb +100 -20
- data/test/paid/transaction_test.rb +110 -37
- data/test/paid/util_test.rb +15 -24
- data/test/test_data.rb +144 -93
- data/test/test_helper.rb +6 -4
- metadata +32 -26
- data/Gemfile.lock +0 -54
- data/README.rdoc +0 -35
- data/lib/data/ca-certificates.crt +0 -0
- data/lib/paid/alias.rb +0 -16
- data/lib/paid/api_operations/create.rb +0 -17
- data/lib/paid/api_operations/delete.rb +0 -11
- data/lib/paid/api_operations/list.rb +0 -17
- data/lib/paid/api_operations/update.rb +0 -57
- data/lib/paid/certificate_blacklist.rb +0 -55
- data/lib/paid/list_object.rb +0 -37
- data/lib/paid/paid_object.rb +0 -187
- data/lib/paid/singleton_api_resource.rb +0 -20
- data/lib/tasks/paid_tasks.rake +0 -4
- data/test/paid/alias_test.rb +0 -22
- data/test/paid/certificate_blacklist_test.rb +0 -18
- data/test/paid/list_object_test.rb +0 -16
- data/test/paid/paid_object_test.rb +0 -27
- data/test/paid/properties_test.rb +0 -103
data/lib/paid/customer.rb
CHANGED
@@ -1,31 +1,46 @@
|
|
1
1
|
module Paid
|
2
2
|
class Customer < APIResource
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# attributes :id and :object inherited from APIResource
|
4
|
+
attribute :name
|
5
|
+
attribute :email
|
6
|
+
attribute :description
|
7
|
+
attribute :external_id
|
8
|
+
attribute :aliases, APIList
|
9
|
+
attribute :phone
|
10
|
+
attribute :address_line1
|
11
|
+
attribute :address_line2
|
12
|
+
attribute :address_city
|
13
|
+
attribute :address_state
|
14
|
+
attribute :address_zip
|
15
|
+
attribute :allow_ach
|
16
|
+
attribute :allow_wire
|
17
|
+
attribute :allow_check
|
18
|
+
attribute :allow_credit_card
|
19
|
+
attribute :terms
|
20
|
+
attribute :billing_type
|
21
|
+
attribute :billing_cycle
|
22
|
+
attribute :stripe_customer_id
|
7
23
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
refresh_from({ :invoice => response }, api_key, true)
|
14
|
-
invoice
|
15
|
-
end
|
24
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Customer)
|
25
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
26
|
+
api_class_method :create, :post
|
27
|
+
api_class_method :by_alias, :get, "/v0/aliases/:alias", :arguments => [:alias]
|
28
|
+
api_class_method :by_external_id, :get, ":path/by_external_id/:external_id", :arguments => [:external_id]
|
16
29
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
30
|
+
api_instance_method :save, :put, :default_params => :changed_attributes
|
31
|
+
api_instance_method :generate_invoice, :post, ":path/generate_invoice", :constructor => Invoice
|
20
32
|
|
21
|
-
|
22
|
-
|
23
|
-
end
|
33
|
+
api_instance_method :invoices, :get, Invoice.path, :default_params => :customer_id_hash, :constructor => APIList.constructor(Invoice)
|
34
|
+
api_instance_method :transactions, :get, Transaction.path, :default_params => :customer_id_hash, :constructor => APIList.constructor(Transaction)
|
24
35
|
|
25
|
-
|
36
|
+
def self.path
|
37
|
+
"/v0/customers"
|
38
|
+
end
|
26
39
|
|
27
|
-
def
|
28
|
-
|
40
|
+
def customer_id_hash
|
41
|
+
{ :customer => self.id }
|
29
42
|
end
|
43
|
+
|
44
|
+
APIClass.register_subclass(self, "customer")
|
30
45
|
end
|
31
46
|
end
|
data/lib/paid/event.rb
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
module Paid
|
2
2
|
class Event < APIResource
|
3
|
-
|
3
|
+
class Data
|
4
|
+
def self.construct(json={})
|
5
|
+
return nil if json.nil?
|
6
|
+
klass = APIClass.subclass_fetch(json[:object])
|
7
|
+
klass.construct(json)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# attributes :id and :object inherited from APIResource
|
12
|
+
attribute :created_at
|
13
|
+
attribute :type
|
14
|
+
attribute :data, Data
|
15
|
+
|
16
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Event)
|
17
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
18
|
+
|
19
|
+
|
20
|
+
def self.path
|
21
|
+
"/v0/events"
|
22
|
+
end
|
23
|
+
|
24
|
+
APIClass.register_subclass(self, "event")
|
4
25
|
end
|
5
26
|
end
|
data/lib/paid/invoice.rb
CHANGED
@@ -1,31 +1,26 @@
|
|
1
1
|
module Paid
|
2
2
|
class Invoice < APIResource
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# attributes :id and :object inherited from APIResource
|
4
|
+
attribute :summary
|
5
|
+
attribute :chase_schedule
|
6
|
+
attribute :next_chase_on
|
7
|
+
attribute :customer
|
8
|
+
attribute :issued_at
|
9
|
+
attribute :terms
|
10
|
+
attribute :url
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
:post, issue_url, api_key || @api_key, params, headers)
|
11
|
-
refresh_from(response, api_key)
|
12
|
-
end
|
12
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Invoice)
|
13
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
14
|
+
api_class_method :create, :post
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
response, api_key = Paid.request(
|
17
|
-
:post, mark_as_paid_url, api_key || @api_key, params, headers)
|
18
|
-
refresh_from(response, api_key)
|
19
|
-
end
|
16
|
+
api_instance_method :issue, :post, ":path/issue"
|
17
|
+
api_instance_method :mark_as_paid, :post, ":path/mark_as_paid" # requires :via in params
|
20
18
|
|
21
|
-
private
|
22
19
|
|
23
|
-
def
|
24
|
-
|
20
|
+
def self.path
|
21
|
+
"/v0/invoices"
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
api_url + '/mark_as_paid'
|
29
|
-
end
|
24
|
+
APIClass.register_subclass(self, "invoice")
|
30
25
|
end
|
31
26
|
end
|
data/lib/paid/plan.rb
CHANGED
@@ -1,6 +1,22 @@
|
|
1
1
|
module Paid
|
2
2
|
class Plan < APIResource
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
# attributes :id and :object inherited from APIResource
|
5
|
+
attribute :name
|
6
|
+
attribute :description
|
7
|
+
attribute :interval
|
8
|
+
attribute :interval_count
|
9
|
+
attribute :amount
|
10
|
+
attribute :created_at
|
11
|
+
|
12
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Plan)
|
13
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
14
|
+
api_class_method :create, :post
|
15
|
+
|
16
|
+
def self.path
|
17
|
+
"/v0/plans"
|
18
|
+
end
|
19
|
+
|
20
|
+
APIClass.register_subclass(self, "plan")
|
5
21
|
end
|
6
22
|
end
|
data/lib/paid/subscription.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
module Paid
|
2
2
|
class Subscription < APIResource
|
3
|
-
|
4
|
-
|
3
|
+
# attributes :id and :object inherited from APIResource
|
4
|
+
attribute :created_at
|
5
|
+
attribute :starts_on
|
6
|
+
attribute :next_transaction_on
|
7
|
+
attribute :plan, Plan
|
8
|
+
attribute :customer
|
9
|
+
attribute :started_at
|
10
|
+
attribute :ended_at
|
11
|
+
attribute :cancelled_at
|
5
12
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
:post, cancel_url, api_key || @api_key, params, headers)
|
10
|
-
refresh_from(response, api_key)
|
11
|
-
end
|
13
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Subscription)
|
14
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
15
|
+
api_class_method :create, :post
|
12
16
|
|
13
|
-
|
17
|
+
api_instance_method :cancel, :post, ":path/cancel"
|
14
18
|
|
15
|
-
def
|
16
|
-
|
19
|
+
def self.path
|
20
|
+
"/v0/subscriptions"
|
17
21
|
end
|
22
|
+
|
23
|
+
APIClass.register_subclass(self, "subscription")
|
18
24
|
end
|
19
25
|
end
|
data/lib/paid/transaction.rb
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
module Paid
|
2
2
|
class Transaction < APIResource
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# attributes :id and :object inherited from APIResource
|
4
|
+
attribute :amount # req for create
|
5
|
+
attribute :description # req for create
|
6
|
+
attribute :customer # optional for create
|
7
|
+
attribute :alias # optional for create
|
8
|
+
attribute :paid # invalid for create
|
9
|
+
attribute :paid_on # optional for create
|
10
|
+
attribute :properties # optional for create
|
11
|
+
attribute :invoice # invalid for create
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
api_class_method :create, :post
|
14
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
15
|
+
api_class_method :all, :get, :constructor => APIList.constructor(Transaction)
|
16
|
+
|
17
|
+
api_instance_method :save, :put, :default_params => changed_lambda
|
18
|
+
api_instance_method :mark_as_paid, :post, ":path/mark_as_paid"
|
13
19
|
|
14
|
-
private
|
15
20
|
|
16
|
-
def
|
17
|
-
|
21
|
+
def self.path
|
22
|
+
"/v0/transactions"
|
18
23
|
end
|
24
|
+
|
25
|
+
APIClass.register_subclass(self, "transaction")
|
19
26
|
end
|
20
27
|
end
|
data/lib/paid/util.rb
CHANGED
@@ -1,130 +1,77 @@
|
|
1
1
|
module Paid
|
2
2
|
module Util
|
3
|
-
def self.objects_to_ids(h)
|
4
|
-
case h
|
5
|
-
when APIResource
|
6
|
-
h.id
|
7
|
-
when Hash
|
8
|
-
res = {}
|
9
|
-
h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
|
10
|
-
res
|
11
|
-
when Array
|
12
|
-
h.map { |v| objects_to_ids(v) }
|
13
|
-
else
|
14
|
-
h
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.object_classes
|
19
|
-
@object_classes ||= {
|
20
|
-
# data structures
|
21
|
-
'list' => ListObject,
|
22
|
-
|
23
|
-
# business objects
|
24
|
-
'transaction' => Transaction,
|
25
|
-
'customer' => Customer,
|
26
|
-
'event' => Event,
|
27
|
-
'invoice' => Invoice,
|
28
|
-
'alias' => Alias,
|
29
|
-
'plan' => Plan,
|
30
|
-
'subscription' => Subscription
|
31
|
-
}
|
32
|
-
end
|
33
3
|
|
34
|
-
def self.
|
35
|
-
|
36
|
-
|
37
|
-
resp.map { |i| convert_to_paid_object(i, api_key) }
|
38
|
-
when Hash
|
39
|
-
# Try converting to a known object class. If none available, fall back to generic PaidObject
|
40
|
-
object_classes.fetch(resp[:object], PaidObject).construct_from(resp, api_key)
|
4
|
+
def self.query_string(params)
|
5
|
+
if params && params.any?
|
6
|
+
return query_array(params).join('&')
|
41
7
|
else
|
42
|
-
|
8
|
+
return ""
|
43
9
|
end
|
44
10
|
end
|
45
11
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.symbolize_names(object)
|
60
|
-
case object
|
61
|
-
when Hash
|
62
|
-
new_hash = {}
|
63
|
-
object.each do |key, value|
|
64
|
-
key = (key.to_sym rescue key) || key
|
65
|
-
new_hash[key] = symbolize_names(value)
|
12
|
+
# Three major use cases (and nesting of them needs to be supported):
|
13
|
+
# { :a => { :b => "bvalue" } } => ["a[b]=bvalue"]
|
14
|
+
# { :a => [1, 2] } => ["a[]=1", "a[]=2"]
|
15
|
+
# { :a => "value" } => ["a=value"]
|
16
|
+
def self.query_array(params, key_prefix=nil)
|
17
|
+
ret = []
|
18
|
+
params.each do |key, value|
|
19
|
+
if params.is_a?(Array)
|
20
|
+
value = key
|
21
|
+
key = ''
|
66
22
|
end
|
67
|
-
|
68
|
-
|
69
|
-
object.map { |value| symbolize_names(value) }
|
70
|
-
else
|
71
|
-
object
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.url_encode(key)
|
76
|
-
URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
77
|
-
end
|
23
|
+
key_suffix = escape(key)
|
24
|
+
full_key = key_prefix ? "#{key_prefix}[#{key_suffix}]" : key_suffix
|
78
25
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
result += flatten_params(value, calculated_key)
|
85
|
-
elsif value.is_a?(Array)
|
86
|
-
result += flatten_params_array(value, calculated_key)
|
26
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
27
|
+
# Handles the following cases:
|
28
|
+
# { :a => { :b => "bvalue" } } => ["a[b]=bvalue"]
|
29
|
+
# { :a => [1, 2] } => ["a[]=1", "a[]=2"]
|
30
|
+
ret += query_array(value, full_key)
|
87
31
|
else
|
88
|
-
|
32
|
+
# Handles the base case with just key and value:
|
33
|
+
# { :a => "value" } => ["a=value"]
|
34
|
+
ret << "#{full_key}=#{escape(value)}"
|
89
35
|
end
|
90
36
|
end
|
91
|
-
|
37
|
+
ret
|
92
38
|
end
|
93
39
|
|
94
|
-
def self.
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
40
|
+
def self.escape(val)
|
41
|
+
URI.escape(val.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.symbolize_keys(obj)
|
45
|
+
if obj.is_a?(Hash)
|
46
|
+
ret = {}
|
47
|
+
obj.each do |key, value|
|
48
|
+
ret[(key.to_sym rescue key) || key] = symbolize_keys(value)
|
103
49
|
end
|
50
|
+
return ret
|
51
|
+
elsif obj.is_a?(Array)
|
52
|
+
return obj.map{ |value| symbolize_keys(value) }
|
53
|
+
else
|
54
|
+
return obj
|
104
55
|
end
|
105
|
-
result
|
106
56
|
end
|
107
57
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
return nil, {}
|
114
|
-
when String
|
115
|
-
return opts, {}
|
116
|
-
when Hash
|
117
|
-
headers = {}
|
118
|
-
if opts[:idempotency_key]
|
119
|
-
headers[:idempotency_key] = opts[:idempotency_key]
|
58
|
+
def self.sorta_deep_clone(json)
|
59
|
+
if json.is_a?(Hash)
|
60
|
+
ret = {}
|
61
|
+
json.each do |k, v|
|
62
|
+
ret[k] = sorta_deep_clone(v)
|
120
63
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
return opts[:api_key], headers
|
64
|
+
ret
|
65
|
+
elsif json.is_a?(Array)
|
66
|
+
json.map{ |j| sorta_deep_clone(j) }
|
125
67
|
else
|
126
|
-
|
68
|
+
begin
|
69
|
+
json.dup
|
70
|
+
rescue
|
71
|
+
json
|
72
|
+
end
|
127
73
|
end
|
128
74
|
end
|
75
|
+
|
129
76
|
end
|
130
77
|
end
|
data/lib/paid/version.rb
CHANGED