zuora-ruby 0.1.0 → 0.2.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 +2 -1
- data/.rubocop.yml +27 -3
- data/README.md +37 -19
- data/lib/zuora.rb +51 -0
- data/lib/zuora/client.rb +51 -25
- data/lib/zuora/models.rb +4 -3
- data/lib/zuora/models/account.rb +58 -47
- data/lib/zuora/models/card_holder.rb +46 -52
- data/lib/zuora/models/contact.rb +65 -38
- data/lib/zuora/models/dirty.rb +192 -0
- data/lib/zuora/models/payment_methods/credit_card.rb +23 -23
- data/lib/zuora/models/rate_plan.rb +6 -10
- data/lib/zuora/models/rate_plan_charge.rb +111 -49
- data/lib/zuora/models/subscription.rb +72 -42
- data/lib/zuora/models/tier.rb +16 -16
- data/lib/zuora/models/validation_predicates.rb +29 -0
- data/lib/zuora/resources.rb +0 -11
- data/lib/zuora/resources/accounts.rb +9 -8
- data/lib/zuora/resources/payment_methods/credit_card.rb +1 -3
- data/lib/zuora/resources/subscriptions.rb +2 -6
- data/lib/zuora/serializers/attribute.rb +3 -3
- data/lib/zuora/version.rb +1 -1
- data/zuora/fixtures/vcr_cassettes/account_create_.yml +111 -0
- data/zuora/fixtures/vcr_cassettes/account_update_.yml +113 -0
- data/zuora/fixtures/vcr_cassettes/subscription_create_.yml +114 -0
- data/zuora/fixtures/vcr_cassettes/subscription_update_.yml +114 -0
- data/zuora_ruby.gemspec +2 -3
- metadata +13 -8
- data/lib/zuora/models/utils.rb +0 -23
@@ -3,58 +3,52 @@
|
|
3
3
|
module Zuora
|
4
4
|
module Models
|
5
5
|
class CardHolder
|
6
|
-
include
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
length: { maximum: 20 },
|
53
|
-
allow_nil: true
|
54
|
-
|
55
|
-
validates :email,
|
56
|
-
length: { maximum: 80 },
|
57
|
-
allow_nil: true
|
6
|
+
include DirtyValidAttr
|
7
|
+
|
8
|
+
dirty_valid_attr :card_holder_name,
|
9
|
+
type: String,
|
10
|
+
required?: true,
|
11
|
+
valid?: max_length(50)
|
12
|
+
|
13
|
+
dirty_valid_attr :address_line_1,
|
14
|
+
type: String,
|
15
|
+
required?: true,
|
16
|
+
valid?: max_length(255)
|
17
|
+
|
18
|
+
dirty_valid_attr :address_line_2,
|
19
|
+
type: String,
|
20
|
+
valid?: max_length(255)
|
21
|
+
|
22
|
+
dirty_valid_attr :city,
|
23
|
+
type: String,
|
24
|
+
required?: true,
|
25
|
+
valid?: max_length(40)
|
26
|
+
|
27
|
+
dirty_valid_attr :state,
|
28
|
+
type: String,
|
29
|
+
required?: true,
|
30
|
+
valid?: one_of(Zuora::STATE_ABBREVIATIONS)
|
31
|
+
|
32
|
+
dirty_valid_attr :zip_code,
|
33
|
+
type: String,
|
34
|
+
required?: true,
|
35
|
+
valid?: max_length(20)
|
36
|
+
|
37
|
+
dirty_valid_attr :country,
|
38
|
+
type: String,
|
39
|
+
required?: true,
|
40
|
+
valid?: max_length(50)
|
41
|
+
|
42
|
+
dirty_valid_attr :phone,
|
43
|
+
type: String,
|
44
|
+
required?: true,
|
45
|
+
valid?: max_length(20)
|
46
|
+
|
47
|
+
dirty_valid_attr :email,
|
48
|
+
type: String,
|
49
|
+
required?: true
|
50
|
+
|
51
|
+
alias_method :initialize, :initialize_attributes!
|
58
52
|
end
|
59
53
|
end
|
60
54
|
end
|
data/lib/zuora/models/contact.rb
CHANGED
@@ -1,44 +1,71 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Zuora
|
4
2
|
module Models
|
5
3
|
class Contact
|
6
|
-
include
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
4
|
+
include DirtyValidAttr
|
5
|
+
|
6
|
+
dirty_valid_attr :address_1,
|
7
|
+
type: String,
|
8
|
+
required?: true
|
9
|
+
|
10
|
+
dirty_valid_attr :address_2,
|
11
|
+
type: String
|
12
|
+
|
13
|
+
dirty_valid_attr :city,
|
14
|
+
type: String
|
15
|
+
|
16
|
+
dirty_valid_attr :country,
|
17
|
+
type: String
|
18
|
+
|
19
|
+
dirty_valid_attr :county,
|
20
|
+
type: String
|
21
|
+
|
22
|
+
dirty_valid_attr :fax,
|
23
|
+
type: String
|
24
|
+
|
25
|
+
dirty_valid_attr :home_phone,
|
26
|
+
type: String
|
27
|
+
|
28
|
+
dirty_valid_attr :first_name,
|
29
|
+
type: String,
|
30
|
+
required?: true,
|
31
|
+
valid?: max_length(100)
|
32
|
+
|
33
|
+
dirty_valid_attr :last_name,
|
34
|
+
type: String,
|
35
|
+
required?: true,
|
36
|
+
valid?: max_length(100)
|
37
|
+
|
38
|
+
dirty_valid_attr :mobile_phone,
|
39
|
+
type: String
|
40
|
+
|
41
|
+
dirty_valid_attr :nickname,
|
42
|
+
type: String
|
43
|
+
|
44
|
+
dirty_valid_attr :other_phone,
|
45
|
+
type: String
|
46
|
+
|
47
|
+
dirty_valid_attr :other_phone_type,
|
48
|
+
type: String
|
49
|
+
|
50
|
+
dirty_valid_attr :personal_email,
|
51
|
+
type: String
|
52
|
+
|
53
|
+
dirty_valid_attr :state,
|
54
|
+
type: String
|
55
|
+
|
56
|
+
dirty_valid_attr :tax_region,
|
57
|
+
type: String
|
58
|
+
|
59
|
+
dirty_valid_attr :work_email,
|
60
|
+
type: String
|
61
|
+
|
62
|
+
dirty_valid_attr :work_phone,
|
63
|
+
type: String
|
64
|
+
|
65
|
+
dirty_valid_attr :zip_code,
|
66
|
+
type: String
|
67
|
+
|
68
|
+
alias_method :initialize, :initialize_attributes!
|
42
69
|
end
|
43
70
|
end
|
44
71
|
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# Thanks to @jcarbo, @jwg2s, @jbender
|
2
|
+
|
3
|
+
# Rationale:
|
4
|
+
|
5
|
+
# Create classes of objects with a self-enforcing schemas, and the ability to
|
6
|
+
# track which fields have changed.
|
7
|
+
|
8
|
+
# Useful in modeling, validating, and serializing remote API endpoints,
|
9
|
+
# especially for PATCH updates where sending ambiguous nil values could
|
10
|
+
# override invisible defaults.
|
11
|
+
|
12
|
+
# Features:
|
13
|
+
|
14
|
+
# - attr_accessor like getter and setters, plus...
|
15
|
+
# - constructor checks required fields with support for multi-field
|
16
|
+
# validation predicates
|
17
|
+
# - per attribute coercion
|
18
|
+
# - type check
|
19
|
+
# - validation
|
20
|
+
# - dirty attribute tracking: what changed?
|
21
|
+
# (checks are all optional, and are applied in the above order)
|
22
|
+
|
23
|
+
require 'set'
|
24
|
+
require_relative 'validation_predicates'
|
25
|
+
|
26
|
+
## Composite Types
|
27
|
+
module Boolean; end
|
28
|
+
class TrueClass; include Boolean; end
|
29
|
+
class FalseClass; include Boolean; end
|
30
|
+
# All roads lead to TrueClass
|
31
|
+
# true.is_a? Boolean => true (.is_a? Boolean => true ... )
|
32
|
+
# false.is_a? Boolean => true (.is_a? Boolean => true ... )
|
33
|
+
|
34
|
+
module DirtyValidAttr
|
35
|
+
def self.included(base)
|
36
|
+
base.include InstanceMethods
|
37
|
+
base.extend ClassMethods
|
38
|
+
base.extend ValidationPredicates
|
39
|
+
end
|
40
|
+
|
41
|
+
module InstanceMethods
|
42
|
+
attr_accessor :changed_attributes
|
43
|
+
attr_accessor :attributes
|
44
|
+
|
45
|
+
def fail_validation!(attr, value)
|
46
|
+
message = "Invalid value for: attr: #{attr} - value: #{value}}"
|
47
|
+
fail message
|
48
|
+
end
|
49
|
+
|
50
|
+
def fail_type!(attr, value, type)
|
51
|
+
fail %(Invalid type for: attr: #{attr}
|
52
|
+
- value: #{value}
|
53
|
+
- is: #{value.class}
|
54
|
+
- should be: #{type})
|
55
|
+
end
|
56
|
+
|
57
|
+
def coerce_value(coerce, value)
|
58
|
+
return coerce.call(value)
|
59
|
+
rescue
|
60
|
+
throw "Unable to coerce #{value}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module ClassMethods
|
65
|
+
attr_accessor :attr_definitions
|
66
|
+
|
67
|
+
# @param [symbol] attr - attribute name
|
68
|
+
# @param [Hash] options - {[Class] type - checked using .is_a?, optional
|
69
|
+
# [Proc] valid? - predicate fn, optional
|
70
|
+
# [Proc] coerce - coercion fn, optional
|
71
|
+
# [Boolean] required? - default: nil (falsy)
|
72
|
+
def dirty_valid_attr(attr, options = {})
|
73
|
+
upsert_attr_definition! attr, options
|
74
|
+
|
75
|
+
# Setter
|
76
|
+
define_setter attr, options
|
77
|
+
|
78
|
+
# Getter
|
79
|
+
attr_reader attr
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# Defines setter method for instance (plus validation)
|
85
|
+
# @param [Object] attr
|
86
|
+
# @param [Object] options
|
87
|
+
def define_setter(attr, options = {})
|
88
|
+
define_method("#{attr}=") do |value|
|
89
|
+
self.changed_attributes ||= Set.new
|
90
|
+
|
91
|
+
type, validation, coerce = options.values_at(:type, :valid?, :coerce)
|
92
|
+
value = coerce_value(coerce, value) if coerce
|
93
|
+
fail_validation!(attr, value) if validation && !validation.call(value)
|
94
|
+
fail_type!(attr, value, type) unless type && value.is_a?(type)
|
95
|
+
|
96
|
+
changed_attributes << attr
|
97
|
+
instance_variable_set "@#{attr}", value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Upsert to class-level hash of {attr => options}
|
102
|
+
# @param [Sym] attr - attribtue name
|
103
|
+
# @param [Hash] options - see structure in dirty_valid_attr
|
104
|
+
# @sfx Updates class-level method
|
105
|
+
def upsert_attr_definition!(attr, options)
|
106
|
+
self.attr_definitions ||= {}
|
107
|
+
self.attr_definitions[attr] = options
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param [Hash] attrs - initial attribute keys and values
|
112
|
+
# @return [Nil]
|
113
|
+
def initialize_attributes!(attrs = {})
|
114
|
+
required = required_attrs(attrs)
|
115
|
+
missing = required.keys - attrs.keys
|
116
|
+
fail "Missing required attrs: #{missing} " unless missing.empty?
|
117
|
+
attrs.each do |attr, v|
|
118
|
+
send("#{attr}=", v)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# @param [Hash] attrs - [Symbol] attr
|
125
|
+
# [String] value
|
126
|
+
# @return [Hash] - [String] attr
|
127
|
+
# [Hash] options (:required?, :valid?, :coerce)
|
128
|
+
def required_attrs(attrs = {})
|
129
|
+
# An attribute is determined to be 'missing' using the :required? key.
|
130
|
+
# if provided present in the attribute's definition.
|
131
|
+
#
|
132
|
+
# If :required? is callable, call it on attrs.
|
133
|
+
# This allows for expression logic like:
|
134
|
+
# require attr A if attr B == 3
|
135
|
+
# Else
|
136
|
+
# Use the boolean value true, or nil/false
|
137
|
+
# Defaults to :required? nil(false)
|
138
|
+
#
|
139
|
+
self.class.attr_definitions.select do |_attr, definition|
|
140
|
+
required = definition[:required?]
|
141
|
+
required.respond_to?(:call) ? required.call(attrs) : required
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# class Account
|
147
|
+
# include DirtyValidAttr
|
148
|
+
#
|
149
|
+
# dirty_valid_attr :fuz,
|
150
|
+
# :type => String,
|
151
|
+
# valid: ->(attr) { attr == 'fuzz' },
|
152
|
+
# coerce => ->(attr) { attr.to_str }
|
153
|
+
#
|
154
|
+
# dirty_valid_attr :bizz,
|
155
|
+
# type: Fixnum,
|
156
|
+
# valid: ->(attr) { attr > 3 },
|
157
|
+
# :coerce => ->(attr){ attr.to_i }
|
158
|
+
#
|
159
|
+
# dirty_valid_attr :gaz,
|
160
|
+
# type: Fixnum
|
161
|
+
#
|
162
|
+
# def initialize(attrs)
|
163
|
+
# initialize_attributes!(attrs)
|
164
|
+
# end
|
165
|
+
# end
|
166
|
+
|
167
|
+
# Usage:
|
168
|
+
|
169
|
+
# Create a valid record
|
170
|
+
# > a = Account.new(:fuz => 'fuzz', :bizz => "4")
|
171
|
+
# <Account:0x007f8f0c9052c0 @changed_attributes=
|
172
|
+
# #<Set: {:fuz, :bizz}>, @fuz="fuzz", @bizz=4>
|
173
|
+
|
174
|
+
# Access changed attributes
|
175
|
+
# > a.changed_attributes
|
176
|
+
# #<Set: {:fuz, :bizz}>
|
177
|
+
|
178
|
+
# Basic coercion, validation, type checking:
|
179
|
+
|
180
|
+
# Raises on invalid value:
|
181
|
+
# > a = Account.new(:fuz => 'fuzz', :bizz => "2")
|
182
|
+
# RuntimeError: Invalid value for: attr: bizz - value: 2}
|
183
|
+
|
184
|
+
# Raises if unable to coerce
|
185
|
+
# > a = Account.new(:fuz => 'fuzz', :bizz => Set.new)
|
186
|
+
# RuntimeError: Unable to coerce #<Set:0x007f8f0b8588f0>
|
187
|
+
|
188
|
+
# Raises if invalid type
|
189
|
+
# RuntimeError: Invalid type for: attr: gaz
|
190
|
+
# - value: abc
|
191
|
+
# - is: String
|
192
|
+
# - should be: Fixnum
|
@@ -2,35 +2,35 @@ module Zuora
|
|
2
2
|
module Models
|
3
3
|
module PaymentMethods
|
4
4
|
class CreditCard
|
5
|
-
include
|
5
|
+
include DirtyValidAttr
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
:security_code
|
7
|
+
dirty_valid_attr :card_type,
|
8
|
+
type: String,
|
9
|
+
required?: true,
|
10
|
+
valid?: one_of(Zuora::CREDIT_CARD_TYPES)
|
12
11
|
|
13
|
-
|
12
|
+
dirty_valid_attr :card_number,
|
13
|
+
type: String,
|
14
|
+
required?: true
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
validates :card_type,
|
20
|
-
:card_number,
|
21
|
-
:expiration_month,
|
22
|
-
:expiration_year,
|
23
|
-
:security_code,
|
24
|
-
presence: true
|
16
|
+
dirty_valid_attr :expiration_month,
|
17
|
+
type: String,
|
18
|
+
required?: true,
|
19
|
+
valid?: one_of(Zuora::MONTHS)
|
25
20
|
|
26
|
-
|
27
|
-
|
21
|
+
dirty_valid_attr :expiration_year,
|
22
|
+
type: String,
|
23
|
+
required?: true,
|
24
|
+
valid?: valid_year
|
28
25
|
|
29
|
-
|
30
|
-
|
26
|
+
dirty_valid_attr :security_code,
|
27
|
+
type: String,
|
28
|
+
required: true
|
31
29
|
|
32
|
-
|
33
|
-
|
30
|
+
# @param [Hash] attrs
|
31
|
+
def initialize(attrs)
|
32
|
+
initialize_attributes! attrs
|
33
|
+
end
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|