active_zuora 1.5.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +57 -0
  3. data/README.md +155 -0
  4. data/Rakefile +6 -22
  5. data/TODO.md +2 -0
  6. data/active_zuora.gemspec +25 -68
  7. data/lib/active_zuora.rb +37 -6
  8. data/lib/active_zuora/amend.rb +43 -0
  9. data/lib/active_zuora/base.rb +73 -0
  10. data/lib/active_zuora/belongs_to_associations.rb +56 -0
  11. data/lib/active_zuora/connection.rb +41 -0
  12. data/lib/active_zuora/fields.rb +122 -0
  13. data/lib/active_zuora/fields/array_field_decorator.rb +28 -0
  14. data/lib/active_zuora/fields/boolean_field.rb +12 -0
  15. data/lib/active_zuora/fields/date_time_field.rb +19 -0
  16. data/lib/active_zuora/fields/decimal_field.rb +12 -0
  17. data/lib/active_zuora/fields/field.rb +76 -0
  18. data/lib/active_zuora/fields/integer_field.rb +11 -0
  19. data/lib/active_zuora/fields/object_field.rb +31 -0
  20. data/lib/active_zuora/fields/string_field.rb +11 -0
  21. data/lib/active_zuora/generate.rb +43 -0
  22. data/lib/active_zuora/generator.rb +220 -0
  23. data/lib/active_zuora/has_many_associations.rb +37 -0
  24. data/lib/active_zuora/has_many_proxy.rb +50 -0
  25. data/lib/active_zuora/persistence.rb +176 -0
  26. data/lib/active_zuora/relation.rb +253 -0
  27. data/lib/active_zuora/scoping.rb +50 -0
  28. data/lib/active_zuora/subscribe.rb +42 -0
  29. data/lib/active_zuora/version.rb +3 -0
  30. data/lib/active_zuora/z_object.rb +21 -0
  31. data/spec/belongs_to_associations_spec.rb +35 -0
  32. data/spec/has_many_integration_spec.rb +53 -0
  33. data/spec/spec_helper.rb +21 -0
  34. data/spec/subscribe_integration_spec.rb +218 -0
  35. data/spec/zobject_integration_spec.rb +104 -0
  36. data/wsdl/zuora.wsdl +1548 -0
  37. metadata +128 -72
  38. checksums.yaml +0 -7
  39. data/LICENSE +0 -202
  40. data/README.rdoc +0 -36
  41. data/VERSION +0 -1
  42. data/custom_fields.yml +0 -17
  43. data/lib/active_zuora/account.rb +0 -31
  44. data/lib/active_zuora/amendment.rb +0 -7
  45. data/lib/active_zuora/bill_run.rb +0 -4
  46. data/lib/active_zuora/contact.rb +0 -7
  47. data/lib/active_zuora/invoice.rb +0 -46
  48. data/lib/active_zuora/invoice_item.rb +0 -26
  49. data/lib/active_zuora/invoice_item_adjustment.rb +0 -4
  50. data/lib/active_zuora/invoice_payment.rb +0 -11
  51. data/lib/active_zuora/payment.rb +0 -18
  52. data/lib/active_zuora/payment_method.rb +0 -10
  53. data/lib/active_zuora/product.rb +0 -4
  54. data/lib/active_zuora/product_rate_plan.rb +0 -9
  55. data/lib/active_zuora/product_rate_plan_charge.rb +0 -11
  56. data/lib/active_zuora/product_rate_plan_charge_tier.rb +0 -7
  57. data/lib/active_zuora/product_rate_plan_charge_tier_data.rb +0 -4
  58. data/lib/active_zuora/rate_plan.rb +0 -16
  59. data/lib/active_zuora/rate_plan_charge.rb +0 -71
  60. data/lib/active_zuora/rate_plan_charge_data.rb +0 -4
  61. data/lib/active_zuora/rate_plan_charge_tier.rb +0 -4
  62. data/lib/active_zuora/rate_plan_data.rb +0 -4
  63. data/lib/active_zuora/refund.rb +0 -4
  64. data/lib/active_zuora/subscribe_options.rb +0 -4
  65. data/lib/active_zuora/subscribe_request.rb +0 -13
  66. data/lib/active_zuora/subscribe_with_existing_account_request.rb +0 -4
  67. data/lib/active_zuora/subscription.rb +0 -17
  68. data/lib/active_zuora/subscription_data.rb +0 -4
  69. data/lib/active_zuora/usage.rb +0 -4
  70. data/lib/active_zuora/zobject.rb +0 -154
  71. data/lib/soap/property +0 -1
  72. data/lib/zuora/ZUORA.rb +0 -1560
  73. data/lib/zuora/ZUORADriver.rb +0 -145
  74. data/lib/zuora/ZUORAMappingRegistry.rb +0 -1709
  75. data/lib/zuora/ZuoraServiceClient.rb +0 -124
  76. data/lib/zuora/api.rb +0 -18
  77. data/lib/zuora_client.rb +0 -191
  78. data/lib/zuora_interface.rb +0 -215
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_zuora (2.0.0)
5
+ activemodel (>= 3.0.0, < 4.0.0)
6
+ activesupport (>= 3.0.0, < 4.0.0)
7
+ savon (~> 0.9.9)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activemodel (3.2.3)
13
+ activesupport (= 3.2.3)
14
+ builder (~> 3.0.0)
15
+ activesupport (3.2.3)
16
+ i18n (~> 0.6)
17
+ multi_json (~> 1.0)
18
+ akami (1.0.0)
19
+ gyoku (>= 0.4.0)
20
+ builder (3.0.0)
21
+ diff-lcs (1.1.3)
22
+ gyoku (0.4.5)
23
+ builder (>= 2.1.2)
24
+ httpi (0.9.7)
25
+ rack
26
+ i18n (0.6.0)
27
+ multi_json (1.5.0)
28
+ nokogiri (1.5.2)
29
+ nori (1.1.0)
30
+ rack (1.4.1)
31
+ rake (0.8.7)
32
+ rspec (2.8.0)
33
+ rspec-core (~> 2.8.0)
34
+ rspec-expectations (~> 2.8.0)
35
+ rspec-mocks (~> 2.8.0)
36
+ rspec-core (2.8.0)
37
+ rspec-expectations (2.8.0)
38
+ diff-lcs (~> 1.1.2)
39
+ rspec-mocks (2.8.0)
40
+ savon (0.9.9)
41
+ akami (~> 1.0)
42
+ builder (>= 2.1.2)
43
+ gyoku (>= 0.4.0)
44
+ httpi (~> 0.9)
45
+ nokogiri (>= 1.4.0)
46
+ nori (~> 1.1)
47
+ wasabi (~> 2.1)
48
+ wasabi (2.1.1)
49
+ nokogiri (>= 1.4.0)
50
+
51
+ PLATFORMS
52
+ ruby
53
+
54
+ DEPENDENCIES
55
+ active_zuora!
56
+ rake (~> 0.8.7)
57
+ rspec (~> 2.8.0)
@@ -0,0 +1,155 @@
1
+ # active_zuora - Auto-Generated ActiveModel Interface for Zuora
2
+
3
+ [![TravisCI](https://secure.travis-ci.org/tstmedia/active_zuora.png "TravisCI")](http://travis-ci.org/tstmedia/active_zuora "Travis-CI ActiveZuora") [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/tstmedia/active_zuora)
4
+
5
+ Use Zuora's API like ActiveRecord. Auto-generate all the classes from the wsdl file, or easily declare your own.
6
+
7
+ ## Configuration
8
+
9
+ ActiveZuora.configure(
10
+ :username => 'user@example.com',
11
+ :password => 'password'
12
+ )
13
+
14
+ Enable SOAP logging to stderr or provide your own wsdl file.
15
+
16
+ ActiveZuora.configure(
17
+ :username => 'user@example.com',
18
+ :password => 'password',
19
+ :log => true,
20
+ :wsdl => 'path/to/zuora.wsdl'
21
+ )
22
+
23
+ ## Defining Classes
24
+
25
+ You can auto-generate all your Zuora classes from the wsdl file. It will generate all Z-Objects, like Account and Subscription, and Zuora Complex objects, such as SubscribeRequest.
26
+
27
+ ActiveZuora.generate_classes
28
+
29
+ By default, it will generate the classes inside the ActiveZuora module. But you can specify a different nesting if you'd like.
30
+
31
+ ActiveZuora.generate_classes :under => SomeOtherModule
32
+
33
+ Or, if you prefer, you can define your ZObjects or Complex Types manually.
34
+
35
+ class Account
36
+
37
+ include ActiveZuora::ZObject
38
+
39
+ field :name, :string
40
+ field :auto_pay, :boolean, :default => true
41
+ field :balance, :decimal
42
+ field :created_date, :datetime
43
+
44
+ has_many :subscriptions, :order => :name
45
+ has_many :active_subscriptions, :class_name => 'Subscription',
46
+ :conditions => { :status => 'Active' },
47
+ :order => [ :name, :desc ]
48
+ belongs_to :parent, :class_name => 'Account'
49
+ has_many :children, :class_name => 'Account', :foreign_key => :parent_id, :inverse_of => :parent
50
+
51
+ validates_presence_of :name
52
+
53
+ end
54
+
55
+ class SubscriptionData
56
+
57
+ include ActiveZuora::Base
58
+
59
+ field :subscription, :object
60
+ field :rate_plan_data, :object, :array => true
61
+
62
+ end
63
+
64
+ ## Saving, Updating, and Deleting
65
+
66
+ These familiar functions are available: save, create, and update_attributes, along with ! versions that raise exceptions upon failure.
67
+
68
+ account = ActiveZuora::Account.new :name => "Frank's Pest Control"
69
+ account.new_record?
70
+ account.save
71
+
72
+ account = ActiveZuora::Account.create! :name => "Frank's Pest Control"
73
+ account.update_attributes :auto_pay => false, :currency => "USD"
74
+
75
+ Changes are also tracked.
76
+
77
+ account = ActiveZuora::Account.new :name => "Frank's Pest Control"
78
+ account.changes # { :name => [nil, "Frank's Pest Control"] }
79
+ account.save!
80
+ account.changes # []
81
+
82
+ Errors are captured using ActiveModel::Validations, or from error messages received from the server.
83
+
84
+ account = ActiveZuora::Account.new
85
+ account.save # false
86
+ account.errors # { :base => ["Missing attribute: Name"] } # Returned from server.
87
+
88
+ Delete a record with #delete.
89
+
90
+ account.delete
91
+
92
+ ## Querying
93
+
94
+ ActiveZuora::Account.find(id)
95
+
96
+ ActiveZuora::Account.where(:name => "Frank's Pest Control").all
97
+
98
+ ActiveZuora::Account.where(:name => { :like => '%Pest Control' }).count
99
+
100
+ ActiveZuora::Account.where(:auto_pay => true).or(:balance => 0).all
101
+
102
+ ActiveZuora::Account.select(:id, :name).where(:created_date => { "<" => Date.yesterday })
103
+
104
+ There is no "order by" clause in the ZQL query language, but ActiveZuora's query system can post-sort results for you:
105
+
106
+ ActiveZuora::Account.where(:status => "Active").order(:name)
107
+
108
+ ActiveZuora::Account.where(:status => "Draft").order(:created_date, :desc)
109
+
110
+ By default, every Query object caches the results once you call an array-like method on it. However, if you know you'll have a very large result set and you just want to iterate through them without keeping them, you can use `find_each`.
111
+
112
+ ActiveZuora::Account.where(:status => "Active").find_each do |account|
113
+ ...
114
+ end
115
+
116
+ ## Scopes
117
+
118
+ ActiveZuora::Account.instance_eval do
119
+ scope :active, :status => "Active"
120
+ scope :draft, where(:status => "Draft")
121
+ scope :since, lambda { |datetime| where(:created_date => { ">=" => datetime }) }
122
+ end
123
+
124
+ ActiveZuora::Account.select(:id).draft.since(Date.new 2012).to_zql
125
+ # => "select Id from Account where Status = 'Draft' and CreatedDate >= '2012-01-01T00:00:00+08:00'"
126
+
127
+ Like ActiveRecord, you can also chain any class method on the ZObject, since named scopes are nothing more than class methods that return a Relation object.
128
+
129
+ ## Update or Delete Using Queries
130
+
131
+ You can update or delete multiple records at once. The following command issues two requests to the Zuora API server: the first to query for the records, and the second to update them all at once. The method returns the count of records that were successfully updated.
132
+
133
+ ActiveZuora::Account.where(:status => "Draft").update_all :status => "Active" # 56
134
+
135
+ You can also use a block to update your records, in case your updates depend on the records themselves.
136
+
137
+ ActiveZuora::Account.where(:status => "Draft").update_all do |account|
138
+ account.name += " (#{account.currency})"
139
+ end
140
+
141
+ You can also delete all records matching a query as well. The method returns the amount of records deleted.
142
+
143
+ ActiveZuora::Account.where(:status => "Draft").delete_all # 56
144
+
145
+ ## License
146
+
147
+ Active Zuora is released under the MIT license:
148
+
149
+ http://www.opensource.org/licenses/MIT
150
+
151
+ ## Support
152
+
153
+ Bug reports and feature requests can be filed as github issues here:
154
+
155
+ https://github.com/tstmedia/active_zuora/issues
data/Rakefile CHANGED
@@ -1,28 +1,12 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'bundler'
3
3
  Bundler.setup
4
- require 'rake'
5
- require 'test-unit'
4
+ require 'rspec/core/rake_task'
6
5
 
7
- require 'rake/testtask'
8
- Rake::TestTask.new(:test) do |test|
9
- test.libs << 'lib' << 'test'
10
- test.pattern = 'test/**/test_*.rb'
11
- test.verbose = true
12
- end
6
+ desc 'Default: run library specs.'
7
+ task :default => :spec
13
8
 
14
- begin
15
- require 'rcov/rcovtask'
16
- Rcov::RcovTask.new do |test|
17
- test.libs << 'test'
18
- test.pattern = 'test/**/test_*.rb'
19
- test.verbose = true
20
- end
21
- rescue LoadError
22
- task :rcov do
23
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
24
- end
9
+ desc "Run library specs"
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.pattern = ["./spec/**/*_spec.rb"]
25
12
  end
26
-
27
- task :default => :test
28
-
data/TODO.md ADDED
@@ -0,0 +1,2 @@
1
+ * add deeper customizations for more classes in generator
2
+ * add get_user_info and other operations
@@ -1,72 +1,29 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
1
  # -*- encoding: utf-8 -*-
5
- # stub: active_zuora 1.4.21 ruby lib
6
-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "active_zuora/version"
4
+ authors = {
5
+ "Ed Lebert" => "edlebert@gmail.com",
6
+ "Andy Fleener" => "andy.fleener@tstmedia.com",
7
+ }
7
8
  Gem::Specification.new do |s|
8
- s.name = "active_zuora"
9
- s.version = "1.5.2"
10
-
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.name = "active_zuora"
10
+ s.version = ActiveZuora::VERSION.to_s
11
+ s.platform = Gem::Platform::RUBY
12
+ s.authors = authors.keys
13
+ s.email = authors.values
14
+ s.homepage = "https://github.com/tstmedia/active_zuora"
15
+ s.summary = %q{ActiveZuora - Zuora API that looks and feels like ActiveRecord.}
16
+ s.description = %q{ActiveZuora - Zuora API based on ActiveModel and auto-generated from your zuora.wsdl.}
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
20
  s.require_paths = ["lib"]
13
- s.authors = ["Andy Fleener", "Ed Lebert", "Nate Greene"]
14
- s.date = "2015-04-10"
15
- s.description = "A client for Zuora API"
16
- s.email = "andy.fleener@tstmedia.com"
17
- s.extra_rdoc_files = [
18
- "LICENSE",
19
- "README.rdoc"
20
- ]
21
- s.files = [
22
- "Rakefile",
23
- "VERSION",
24
- "active_zuora.gemspec",
25
- "custom_fields.yml",
26
- "lib/active_zuora.rb",
27
- "lib/active_zuora/account.rb",
28
- "lib/active_zuora/amendment.rb",
29
- "lib/active_zuora/bill_run.rb",
30
- "lib/active_zuora/contact.rb",
31
- "lib/active_zuora/invoice.rb",
32
- "lib/active_zuora/invoice_item.rb",
33
- "lib/active_zuora/invoice_item_adjustment.rb",
34
- "lib/active_zuora/invoice_payment.rb",
35
- "lib/active_zuora/payment.rb",
36
- "lib/active_zuora/payment_method.rb",
37
- "lib/active_zuora/product.rb",
38
- "lib/active_zuora/product_rate_plan.rb",
39
- "lib/active_zuora/product_rate_plan_charge.rb",
40
- "lib/active_zuora/product_rate_plan_charge_tier.rb",
41
- "lib/active_zuora/product_rate_plan_charge_tier_data.rb",
42
- "lib/active_zuora/rate_plan.rb",
43
- "lib/active_zuora/rate_plan_charge.rb",
44
- "lib/active_zuora/rate_plan_charge_data.rb",
45
- "lib/active_zuora/rate_plan_charge_tier.rb",
46
- "lib/active_zuora/rate_plan_data.rb",
47
- "lib/active_zuora/refund.rb",
48
- "lib/active_zuora/subscribe_options.rb",
49
- "lib/active_zuora/subscribe_request.rb",
50
- "lib/active_zuora/subscribe_with_existing_account_request.rb",
51
- "lib/active_zuora/subscription.rb",
52
- "lib/active_zuora/subscription_data.rb",
53
- "lib/active_zuora/usage.rb",
54
- "lib/active_zuora/zobject.rb",
55
- "lib/soap/property",
56
- "lib/zuora/ZUORA.rb",
57
- "lib/zuora/ZUORADriver.rb",
58
- "lib/zuora/ZUORAMappingRegistry.rb",
59
- "lib/zuora/ZuoraServiceClient.rb",
60
- "lib/zuora/api.rb",
61
- "lib/zuora_client.rb",
62
- "lib/zuora_interface.rb"
63
- ]
64
- s.homepage = "http://github.com/tstmedia/active_zuora"
65
- s.requirements = ["none"]
66
- s.rubygems_version = "2.4.6"
67
- s.summary = "Active Zuora"
68
- s.add_dependency('soap4r-ng')
69
- s.add_development_dependency('rake')
70
- s.add_development_dependency('test-unit')
71
- end
21
+ s.extra_rdoc_files = [ "README.md" ]
72
22
 
23
+ s.add_runtime_dependency('savon', ["~> 0.9.9"])
24
+ s.add_runtime_dependency('activesupport', [">= 3.0.0", "< 4.0.0"])
25
+ s.add_runtime_dependency('activemodel', [">= 3.0.0", "< 4.0.0"])
26
+
27
+ s.add_development_dependency('rake', ["~> 0.8.7"])
28
+ s.add_development_dependency('rspec', ["~> 2.8.0"])
29
+ end
@@ -1,8 +1,39 @@
1
- require 'delegate'
2
- require 'zuora_client'
3
- require 'active_zuora/zobject.rb'
4
- Dir[File.join(File.dirname(__FILE__),"active_zuora","*.rb")].each do |file|
5
- require file
6
- end
1
+ require 'savon'
2
+ require 'active_model'
3
+ require 'active_support/all'
4
+
5
+ require 'active_zuora/connection'
6
+ require 'active_zuora/generator'
7
+ require 'active_zuora/fields'
8
+ require 'active_zuora/belongs_to_associations'
9
+ require 'active_zuora/base'
10
+ require 'active_zuora/relation'
11
+ require 'active_zuora/scoping'
12
+ require 'active_zuora/persistence'
13
+ require 'active_zuora/has_many_proxy'
14
+ require 'active_zuora/has_many_associations'
15
+ require 'active_zuora/z_object'
16
+ require 'active_zuora/subscribe'
17
+ require 'active_zuora/amend'
18
+ require 'active_zuora/generate'
19
+
20
+ module ActiveZuora
7
21
 
22
+ # Setup configuration. None of this sends a request.
23
+ def self.configure(configuration)
24
+ # Set some sensible defaults with the savon SOAP client.
25
+ Savon.configure do |config|
26
+ config.log = HTTPI.log = configuration[:log] || false
27
+ config.log_level = configuration[:log_level] || :info
28
+ config.raise_errors = true
29
+ end
30
+ # Create a default connection on Base
31
+ Base.connection = Connection.new(configuration)
32
+ end
8
33
 
34
+ def self.generate_classes(options={})
35
+ generator = Generator.new(Base.connection.soap_client.wsdl.parser, options)
36
+ generator.generate_classes
37
+ end
38
+
39
+ end
@@ -0,0 +1,43 @@
1
+ module ActiveZuora
2
+ module Amend
3
+
4
+ # This is meant to be included onto a AmendRequest class.
5
+ # Returns true/false on success.
6
+ # Result hash is stored in #result.
7
+ # If success, the ids will be set in the given amendments.
8
+ # If failure, errors will be present on object.
9
+
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ include Base
14
+ attr_accessor :result
15
+ end
16
+
17
+ def amend
18
+ self.result = self.class.connection.request(:amend) do |soap|
19
+ soap.body do |xml|
20
+ build_xml(xml, soap,
21
+ :namespace => soap.namespace,
22
+ :element_name => :requests,
23
+ :force_type => true)
24
+ end
25
+ end[:amend_response][:results]
26
+ if result[:success]
27
+ [result[:amendment_ids]].flatten.compact.each_with_index do |id, i|
28
+ amendments[i].id = id
29
+ end
30
+ clear_changed_attributes
31
+ true
32
+ else
33
+ add_zuora_errors(result[:errors])
34
+ false
35
+ end
36
+ end
37
+
38
+ def amend!
39
+ raise "Could not amend: #{errors.full_messages.join ', '}" unless amend
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,73 @@
1
+ require 'bigdecimal'
2
+ require 'bigdecimal/util'
3
+
4
+ module ActiveZuora
5
+ module Base
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ # This is the default connection object to use for all Base classes.
10
+ # Each individual Base class can overwrite it.
11
+ class << self
12
+ attr_accessor :connection
13
+ end
14
+
15
+ included do
16
+ include Fields
17
+ include ActiveModel::Validations
18
+ include BelongsToAssociations
19
+ class << self
20
+ attr_accessor :namespace
21
+ attr_writer :zuora_object_name
22
+ attr_writer :connection
23
+ end
24
+ delegate :namespace, :zuora_object_name, :to => 'self.class'
25
+ end
26
+
27
+ def xml_field_names
28
+ # Which field names should be rendered during build_xml.
29
+ # Choose only field names that have been changed.
30
+ # Make sure the order in fields is maintained.
31
+ field_names & changed.map(&:to_sym)
32
+ end
33
+
34
+ def build_xml(xml, soap, options={})
35
+ namespace = options.delete(:namespace) || self.namespace
36
+ qualifier = soap.namespace_by_uri(namespace)
37
+ custom_element_name = options.delete(:element_name)
38
+ element_name = custom_element_name || zuora_object_name
39
+ attributes = options.delete(:force_type) ?
40
+ { "xsi:type" => "#{qualifier}:#{zuora_object_name}" } : {}
41
+ xml.tag!(qualifier, element_name.to_sym, attributes) do
42
+ xml_field_names.map { |field_name| get_field!(field_name) }.each do |field|
43
+ field.build_xml(xml, soap, send(field.name), options)
44
+ end
45
+ end
46
+ end
47
+
48
+ def add_zuora_errors(zuora_errors)
49
+ return if zuora_errors.blank?
50
+ zuora_errors = [zuora_errors] unless zuora_errors.is_a?(Array)
51
+ zuora_errors.each { |error| errors.add(:base, error[:message].capitalize) }
52
+ end
53
+
54
+ module ClassMethods
55
+
56
+ def zuora_object_name
57
+ @zuora_object_name ||= self.name.split("::").last
58
+ end
59
+
60
+ def connection
61
+ @connection || Base.connection
62
+ end
63
+
64
+ def nested_class_name(unnested_class_name)
65
+ # This helper method will take a class name, and nest it inside
66
+ # the same module/class as self.
67
+ (name.split("::")[0..-2] << unnested_class_name).join("::")
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+ end