iron_bank 0.1.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.env.example +7 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- data/.gitignore +6 -1
- data/.reek +95 -0
- data/.rspec +1 -2
- data/.rubocop.yml +55 -0
- data/.travis.yml +22 -3
- data/Gemfile +3 -3
- data/LICENSE +176 -0
- data/README.md +133 -0
- data/Rakefile +39 -3
- data/bin/console +13 -1
- data/bin/setup +1 -0
- data/iron_bank.gemspec +34 -10
- data/lib/generators/iron_bank/install/install_generator.rb +20 -0
- data/lib/generators/iron_bank/install/templates/README +16 -0
- data/lib/generators/iron_bank/install/templates/iron_bank.rb +29 -0
- data/lib/iron_bank/action.rb +39 -0
- data/lib/iron_bank/actions/amend.rb +16 -0
- data/lib/iron_bank/actions/create.rb +19 -0
- data/lib/iron_bank/actions/delete.rb +19 -0
- data/lib/iron_bank/actions/execute.rb +21 -0
- data/lib/iron_bank/actions/generate.rb +19 -0
- data/lib/iron_bank/actions/query.rb +16 -0
- data/lib/iron_bank/actions/query_more.rb +21 -0
- data/lib/iron_bank/actions/subscribe.rb +32 -0
- data/lib/iron_bank/actions/update.rb +19 -0
- data/lib/iron_bank/associations.rb +73 -0
- data/lib/iron_bank/authentication.rb +37 -0
- data/lib/iron_bank/authentications/cookie.rb +80 -0
- data/lib/iron_bank/authentications/token.rb +82 -0
- data/lib/iron_bank/cacheable.rb +52 -0
- data/lib/iron_bank/client.rb +96 -0
- data/lib/iron_bank/collection.rb +31 -0
- data/lib/iron_bank/configuration.rb +86 -0
- data/lib/iron_bank/csv.rb +29 -0
- data/lib/iron_bank/describe/field.rb +65 -0
- data/lib/iron_bank/describe/object.rb +81 -0
- data/lib/iron_bank/describe/related.rb +40 -0
- data/lib/iron_bank/describe/tenant.rb +50 -0
- data/lib/iron_bank/endpoint.rb +36 -0
- data/lib/iron_bank/error.rb +45 -0
- data/lib/iron_bank/instrumentation.rb +14 -0
- data/lib/iron_bank/local.rb +72 -0
- data/lib/iron_bank/local_records.rb +52 -0
- data/lib/iron_bank/logger.rb +23 -0
- data/lib/iron_bank/metadata.rb +36 -0
- data/lib/iron_bank/object.rb +89 -0
- data/lib/iron_bank/open_tracing.rb +17 -0
- data/lib/iron_bank/operation.rb +33 -0
- data/lib/iron_bank/operations/billing_preview.rb +16 -0
- data/lib/iron_bank/query_builder.rb +72 -0
- data/lib/iron_bank/queryable.rb +55 -0
- data/lib/iron_bank/resource.rb +70 -0
- data/lib/iron_bank/resources/account.rb +62 -0
- data/lib/iron_bank/resources/amendment.rb +13 -0
- data/lib/iron_bank/resources/catalog_tiers/discount_amount.rb +26 -0
- data/lib/iron_bank/resources/catalog_tiers/discount_percentage.rb +26 -0
- data/lib/iron_bank/resources/catalog_tiers/price.rb +26 -0
- data/lib/iron_bank/resources/contact.rb +13 -0
- data/lib/iron_bank/resources/export.rb +11 -0
- data/lib/iron_bank/resources/import.rb +12 -0
- data/lib/iron_bank/resources/invoice.rb +37 -0
- data/lib/iron_bank/resources/invoice_adjustment.rb +13 -0
- data/lib/iron_bank/resources/invoice_item.rb +25 -0
- data/lib/iron_bank/resources/invoice_payment.rb +13 -0
- data/lib/iron_bank/resources/payment.rb +17 -0
- data/lib/iron_bank/resources/payment_method.rb +14 -0
- data/lib/iron_bank/resources/product.rb +14 -0
- data/lib/iron_bank/resources/product_rate_plan.rb +32 -0
- data/lib/iron_bank/resources/product_rate_plan_charge.rb +27 -0
- data/lib/iron_bank/resources/product_rate_plan_charge_tier.rb +60 -0
- data/lib/iron_bank/resources/rate_plan.rb +21 -0
- data/lib/iron_bank/resources/rate_plan_charge.rb +30 -0
- data/lib/iron_bank/resources/rate_plan_charge_tier.rb +26 -0
- data/lib/iron_bank/resources/subscription.rb +28 -0
- data/lib/iron_bank/resources/usage.rb +16 -0
- data/lib/iron_bank/response/raise_error.rb +16 -0
- data/lib/iron_bank/schema.rb +58 -0
- data/lib/iron_bank/utils.rb +59 -0
- data/lib/iron_bank/version.rb +4 -1
- data/lib/iron_bank.rb +152 -2
- metadata +300 -12
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
module IronBank
|
7
|
+
# Default logger for IronBank events
|
8
|
+
#
|
9
|
+
class Logger
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
PROGNAME = 'iron_bank'
|
13
|
+
LEVEL = ::Logger::DEBUG
|
14
|
+
|
15
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
16
|
+
|
17
|
+
def initialize(logger: ::Logger.new(STDOUT), level: LEVEL)
|
18
|
+
@logger = logger
|
19
|
+
@logger.progname = PROGNAME
|
20
|
+
@logger.level = level
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# Metadata to provide accessors to Zuora resources.
|
5
|
+
#
|
6
|
+
module Metadata
|
7
|
+
# Can be overriden to exclude specific fields for a given resource, see
|
8
|
+
# `Account` class for an example
|
9
|
+
def exclude_fields
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def fields
|
14
|
+
return [] unless schema
|
15
|
+
|
16
|
+
@fields ||= schema.fields.map(&:name) - exclude_fields
|
17
|
+
end
|
18
|
+
|
19
|
+
def query_fields
|
20
|
+
return [] unless schema
|
21
|
+
|
22
|
+
@query_fields ||= schema.query_fields - exclude_fields
|
23
|
+
end
|
24
|
+
|
25
|
+
def schema
|
26
|
+
@schema ||= IronBank::Schema.for(object_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_schema
|
30
|
+
fields.each do |field|
|
31
|
+
method_name = IronBank::Utils.underscore(field)
|
32
|
+
define_method(:"#{method_name}") { remote[field] }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# This object holds the initial payload (hash) sent through one of the
|
5
|
+
# action/operation. It exposes methods to convert the payload to either
|
6
|
+
# upper camel case (typically used by actions) or lower camel case.
|
7
|
+
#
|
8
|
+
# It is also use to parse the response from Zuora and convert it into a Ruby-
|
9
|
+
# friendly Hash.
|
10
|
+
#
|
11
|
+
class Object
|
12
|
+
SNOWFLAKE_FIELDS = ['fieldsToNull'].freeze
|
13
|
+
|
14
|
+
attr_reader :payload
|
15
|
+
|
16
|
+
def initialize(payload)
|
17
|
+
@payload = payload
|
18
|
+
end
|
19
|
+
|
20
|
+
# FIXME: refactor both camelize/underscore methods into one
|
21
|
+
def deep_camelize(type: :upper)
|
22
|
+
payload.each_pair.with_object({}) do |(field, value), hash|
|
23
|
+
field = field.to_s
|
24
|
+
|
25
|
+
key = if SNOWFLAKE_FIELDS.include?(field)
|
26
|
+
field
|
27
|
+
else
|
28
|
+
IronBank::Utils.camelize(field, type: type)
|
29
|
+
end
|
30
|
+
|
31
|
+
hash[key] = camelize(value, type: type)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# FIXME: refactor both camelize/underscore methods into one
|
36
|
+
def deep_underscore
|
37
|
+
payload.each_pair.with_object({}) do |(field, value), hash|
|
38
|
+
key = IronBank::Utils.underscore(field.to_s).to_sym
|
39
|
+
hash[key] = underscore(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# FIXME: refactor both camelize/underscore methods into one
|
46
|
+
def camelize(value, type: :upper)
|
47
|
+
if value.is_a?(Array)
|
48
|
+
camelize_array(value, type: type)
|
49
|
+
elsif value.is_a?(Hash)
|
50
|
+
IronBank::Object.new(value).deep_camelize(type: type)
|
51
|
+
elsif value.is_a?(IronBank::Object)
|
52
|
+
value.deep_camelize(type: type)
|
53
|
+
else
|
54
|
+
value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# FIXME: refactor both camelize/underscore methods into one
|
59
|
+
def camelize_array(value, type: :upper)
|
60
|
+
value.each.with_object([]) do |item, payload|
|
61
|
+
item = IronBank::Object.new(item) if item.is_a?(Hash)
|
62
|
+
item = item.deep_camelize(type: type) unless item.is_a?(String)
|
63
|
+
|
64
|
+
payload.push(item)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# FIXME: refactor both camelize/underscore methods into one
|
69
|
+
def underscore(value)
|
70
|
+
if value.is_a?(Array)
|
71
|
+
underscore_array(value)
|
72
|
+
elsif value.is_a?(Hash)
|
73
|
+
IronBank::Object.new(value).deep_underscore
|
74
|
+
elsif value.is_a?(IronBank::Object)
|
75
|
+
value.deep_underscore
|
76
|
+
else
|
77
|
+
value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# FIXME: refactor both camelize/underscore methods into one
|
82
|
+
def underscore_array(value)
|
83
|
+
value.each.with_object([]) do |item, payload|
|
84
|
+
item = IronBank::Object.new(item) if item.is_a?(Hash)
|
85
|
+
payload.push(item.deep_underscore)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# Open Tracing helper module
|
5
|
+
module OpenTracing
|
6
|
+
def open_tracing_enabled?
|
7
|
+
IronBank.configuration.open_tracing_enabled
|
8
|
+
end
|
9
|
+
|
10
|
+
def open_tracing_options
|
11
|
+
{
|
12
|
+
distributed_tracing: true,
|
13
|
+
split_by_domain: false
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# Base class for Zuora operations, e.g., billing preview
|
5
|
+
#
|
6
|
+
class Operation
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
def self.call(args)
|
10
|
+
new(args).call
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
IronBank.client.connection.post(endpoint, params).body
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :args
|
20
|
+
|
21
|
+
def initialize(args)
|
22
|
+
@args = args
|
23
|
+
end
|
24
|
+
|
25
|
+
def endpoint
|
26
|
+
"v1/operations/#{IronBank::Utils.kebab(name)}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
self.class.name.split('::').last
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Operations
|
5
|
+
# Delete one or more objects of the same type
|
6
|
+
# https://www.zuora.com/developer/api-reference/#operation/Action_POSTdelete
|
7
|
+
#
|
8
|
+
class BillingPreview < Operation
|
9
|
+
private
|
10
|
+
|
11
|
+
def params
|
12
|
+
IronBank::Object.new(args).deep_camelize(type: :lower)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# A query builder helps buidling a syntaxically correct query using ZOQL.
|
5
|
+
#
|
6
|
+
class QueryBuilder
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
def self.zoql(object, fields, conditions = {})
|
10
|
+
new(object, fields, conditions).zoql
|
11
|
+
end
|
12
|
+
|
13
|
+
def zoql
|
14
|
+
query = "select #{query_fields} from #{object}"
|
15
|
+
conditions.empty? ? query : "#{query} where #{query_conditions}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :object, :fields, :conditions
|
21
|
+
|
22
|
+
def initialize(object, fields, conditions)
|
23
|
+
@object = object
|
24
|
+
@fields = fields
|
25
|
+
@conditions = conditions
|
26
|
+
end
|
27
|
+
|
28
|
+
def query_fields
|
29
|
+
fields.join(',')
|
30
|
+
end
|
31
|
+
|
32
|
+
def query_conditions
|
33
|
+
ensure_range_single_condition
|
34
|
+
|
35
|
+
case conditions
|
36
|
+
when Hash
|
37
|
+
hash_query_conditions
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def range_query_builder(field, value)
|
42
|
+
value.each.with_object([]) do |option, range_query|
|
43
|
+
range_query << "#{field}='#{option}'"
|
44
|
+
end.join(' OR ')
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash_query_conditions
|
48
|
+
conditions.each.with_object([]) do |(field, value), filters|
|
49
|
+
# TODO: sanitize the value
|
50
|
+
field = IronBank::Utils.camelize(field)
|
51
|
+
filters << current_filter(field, value)
|
52
|
+
end.join(' AND ')
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_filter(field, value)
|
56
|
+
if value.is_a?(Array)
|
57
|
+
range_query_builder(field, value)
|
58
|
+
elsif [true, false].include? value
|
59
|
+
"#{field}=#{value}"
|
60
|
+
else
|
61
|
+
"#{field}='#{value}'"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def ensure_range_single_condition
|
66
|
+
return if conditions.count <= 1
|
67
|
+
return unless conditions.values.any? { |value| value.is_a?(Array) }
|
68
|
+
|
69
|
+
raise 'Filter ranges must be used in isolation.'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# Query-like features, such as `find` and `where` methods for a resource.
|
5
|
+
#
|
6
|
+
module Queryable
|
7
|
+
# We use the REST endpoint for the `find` method
|
8
|
+
def find(id)
|
9
|
+
raise IronBank::NotFound unless id
|
10
|
+
|
11
|
+
new(
|
12
|
+
IronBank.client.connection.get("v1/object/#{object_name}/#{id}").body
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
# This methods leverages the fact that Zuora only returns 2,000 records at a
|
17
|
+
# time, hance providing a default batch size
|
18
|
+
def find_each
|
19
|
+
return enum_for(:find_each) unless block_given?
|
20
|
+
|
21
|
+
client = IronBank.client
|
22
|
+
query_string = IronBank::QueryBuilder.zoql(object_name, query_fields)
|
23
|
+
query_result = client.query(query_string) # up to 2k records from Zuora
|
24
|
+
|
25
|
+
loop do
|
26
|
+
query_result['records'].each { |data| yield new(data) }
|
27
|
+
break if query_result['done']
|
28
|
+
|
29
|
+
query_result = client.query_more(query_result['queryLocator'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def all
|
34
|
+
where({})
|
35
|
+
end
|
36
|
+
|
37
|
+
def where(conditions)
|
38
|
+
query_string = IronBank::QueryBuilder.zoql(
|
39
|
+
object_name,
|
40
|
+
query_fields,
|
41
|
+
conditions
|
42
|
+
)
|
43
|
+
|
44
|
+
# FIXME: need to use logger instance instead
|
45
|
+
# puts "query: #{query_string}"
|
46
|
+
|
47
|
+
records = IronBank::Query.call(query_string)['records']
|
48
|
+
return [] unless records
|
49
|
+
|
50
|
+
records.each.with_object([]) do |data, result|
|
51
|
+
result << new(data)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
# An Iron Bank RESTful resource.
|
5
|
+
#
|
6
|
+
class Resource
|
7
|
+
include IronBank::Associations
|
8
|
+
extend IronBank::Associations::ClassMethods
|
9
|
+
extend IronBank::Metadata
|
10
|
+
extend IronBank::Queryable
|
11
|
+
|
12
|
+
def self.object_name
|
13
|
+
name.split('::').last
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.with_local_records
|
17
|
+
extend IronBank::Local
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.with_cache
|
21
|
+
include IronBank::Cacheable
|
22
|
+
extend IronBank::Cacheable::ClassMethods
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :remote
|
26
|
+
|
27
|
+
def initialize(remote = {})
|
28
|
+
@remote = remote
|
29
|
+
end
|
30
|
+
|
31
|
+
# Every Zuora object has an ID, so we can safely declare it for each
|
32
|
+
# resource
|
33
|
+
def id
|
34
|
+
remote['Id']
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
# NOTE: In Ruby, the IDs of objects start from the second bit on the right
|
39
|
+
# but in "value space" (used by the original `inspect` implementation)
|
40
|
+
# they start from the third bit on the right. Hence the bitsfhit operation
|
41
|
+
# here.
|
42
|
+
# https://stackoverflow.com/questions/2818602/in-ruby-why-does-inspect-print-out-some-kind-of-object-id-which-is-different
|
43
|
+
ruby_id = "#{self.class.name}:0x#{(object_id << 1).to_s(16)} id=\"#{id}\""
|
44
|
+
respond_to?(:name) ? "#<#{ruby_id} name=\"#{name}\">" : "#<#{ruby_id}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Two resources are equals if their remote (from Zuora) data are similar
|
48
|
+
def ==(other)
|
49
|
+
other.is_a?(IronBank::Resource) ? remote == other.remote : false
|
50
|
+
end
|
51
|
+
|
52
|
+
def reload
|
53
|
+
remove_instance_vars
|
54
|
+
@remote = self.class.find(id).remote
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_csv_row
|
58
|
+
self.class.fields.each.with_object([]) do |field, row|
|
59
|
+
row << remote[field]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_instance_vars
|
64
|
+
# Substract predefined variables from the instance variables
|
65
|
+
(instance_variables - [:@remote]).each do |var|
|
66
|
+
remove_instance_variable(:"#{var}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
# A Zuora account is used for billing purposes: it holds many subscriptions,
|
6
|
+
# has many contacts (but only one bill to and one sold to contact), can have
|
7
|
+
# a default payment method, hence auto-pay can be activated for this account
|
8
|
+
# or not, is billed invoices and can pay them using an electronic payment
|
9
|
+
# method (usually a credit card, but PayPal is also accepted by Zuora).
|
10
|
+
#
|
11
|
+
class Account < Resource
|
12
|
+
# Tenants without credit memo activated cannot query these fields BUT they
|
13
|
+
# are still described as `selectable` through the metadata.
|
14
|
+
#
|
15
|
+
# Similarly, accounts with `TaxExemptStatus` set to `No` cannot query
|
16
|
+
# the `TaxExemptEntityUseCode` related fields.
|
17
|
+
def self.exclude_fields
|
18
|
+
%w[
|
19
|
+
TaxExemptEntityUseCode
|
20
|
+
TotalDebitMemoBalance
|
21
|
+
UnappliedCreditMemoAmount
|
22
|
+
]
|
23
|
+
end
|
24
|
+
with_schema
|
25
|
+
|
26
|
+
# Contacts
|
27
|
+
with_one :bill_to, resource_name: 'Contact'
|
28
|
+
with_one :sold_to, resource_name: 'Contact'
|
29
|
+
with_many :contacts
|
30
|
+
|
31
|
+
# Subscriptions
|
32
|
+
with_many :subscriptions
|
33
|
+
with_many :active_subscriptions,
|
34
|
+
resource_name: 'Subscription',
|
35
|
+
conditions: { status: 'Active' }
|
36
|
+
|
37
|
+
# Invoices
|
38
|
+
with_many :invoices
|
39
|
+
|
40
|
+
# Payment Methods
|
41
|
+
with_one :default_payment_method, resource_name: 'PaymentMethod'
|
42
|
+
with_many :payment_methods
|
43
|
+
|
44
|
+
# Payments
|
45
|
+
with_many :payments
|
46
|
+
|
47
|
+
# Usages
|
48
|
+
with_many :usages
|
49
|
+
|
50
|
+
# Parent
|
51
|
+
with_one :parent, resource_name: 'Account'
|
52
|
+
|
53
|
+
def ultimate_parent
|
54
|
+
root if parent
|
55
|
+
end
|
56
|
+
|
57
|
+
def root
|
58
|
+
parent ? parent.root : self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
# An amendment updates a subscription version and has a type: new product,
|
6
|
+
# update product, remove product, renewal, terms and conditions amendment.
|
7
|
+
#
|
8
|
+
class Amendment < Resource
|
9
|
+
with_schema
|
10
|
+
with_one :subscription
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
module CatalogTiers
|
6
|
+
# A tier that holds an discount ammount for a given product rate plan
|
7
|
+
# charge.
|
8
|
+
#
|
9
|
+
class DiscountAmount < ProductRatePlanChargeTier
|
10
|
+
def self.exclude_fields
|
11
|
+
%w[
|
12
|
+
Active
|
13
|
+
DiscountPercentage
|
14
|
+
IncludedUnits
|
15
|
+
OveragePrice
|
16
|
+
Price
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.object_name
|
21
|
+
superclass.object_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
module CatalogTiers
|
6
|
+
# A tier that holds an discount percentage for a given product rate plan
|
7
|
+
# charge.
|
8
|
+
#
|
9
|
+
class DiscountPercentage < ProductRatePlanChargeTier
|
10
|
+
def self.exclude_fields
|
11
|
+
%w[
|
12
|
+
Active
|
13
|
+
DiscountAmount
|
14
|
+
IncludedUnits
|
15
|
+
OveragePrice
|
16
|
+
Price
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.object_name
|
21
|
+
superclass.object_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
module CatalogTiers
|
6
|
+
# A tier that holds an amount (cost) and a currency for a given product
|
7
|
+
# rate plan charge.
|
8
|
+
#
|
9
|
+
class Price < ProductRatePlanChargeTier
|
10
|
+
def self.exclude_fields
|
11
|
+
%w[
|
12
|
+
Active
|
13
|
+
DiscountAmount
|
14
|
+
DiscountPercentage
|
15
|
+
IncludedUnits
|
16
|
+
OveragePrice
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.object_name
|
21
|
+
superclass.object_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
# A Zuora contact, belongs to an account, can be set as the sold to/bill to
|
6
|
+
# contact for a given account.
|
7
|
+
#
|
8
|
+
class Contact < Resource
|
9
|
+
with_schema
|
10
|
+
with_one :account
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
# A Zuora invoice is generated through a bill run, belongs to an account and
|
6
|
+
# holds many invoice items.
|
7
|
+
#
|
8
|
+
class Invoice < Resource
|
9
|
+
# These fields are declared as `<selectable>true</selectable>` but Zuora
|
10
|
+
# returns a QueryError when trying to query an invoice with them. Also,
|
11
|
+
# the `Body` field can only be retrieved for a single invoice at a time.
|
12
|
+
def self.exclude_fields
|
13
|
+
%w[
|
14
|
+
AutoPay
|
15
|
+
BillRunId
|
16
|
+
BillToContactSnapshotId
|
17
|
+
Body
|
18
|
+
RegenerateInvoicePDF
|
19
|
+
SoldToContactSnapshotId
|
20
|
+
]
|
21
|
+
end
|
22
|
+
with_schema
|
23
|
+
|
24
|
+
with_one :account
|
25
|
+
|
26
|
+
with_many :invoice_adjustments, aka: :adjustments
|
27
|
+
with_many :invoice_items, aka: :items
|
28
|
+
with_many :invoice_payments
|
29
|
+
|
30
|
+
# We can only retrieve one invoice body at a time, hence Body is excluded
|
31
|
+
# from the query fields, but is populated using the `find` class method
|
32
|
+
def body
|
33
|
+
remote['Body'] || reload['Body']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IronBank
|
4
|
+
module Resources
|
5
|
+
# An invoice item holds a charge that is billed to a customer.
|
6
|
+
#
|
7
|
+
class InvoiceItem < Resource
|
8
|
+
def self.exclude_fields
|
9
|
+
%w[
|
10
|
+
AppliedToChargeNumber
|
11
|
+
Balance
|
12
|
+
]
|
13
|
+
end
|
14
|
+
with_schema
|
15
|
+
|
16
|
+
with_one :invoice
|
17
|
+
with_one :subscription
|
18
|
+
|
19
|
+
# NOTE: the `product_id` field is not always populated by Zuora in the GET
|
20
|
+
# request (`#find` method), I don't exactly know why.
|
21
|
+
with_one :product
|
22
|
+
with_one :charge
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|