iron_bank 0.1.0 → 0.7.1
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 +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
|