paid 0.1.0 → 1.0.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 +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