netsuite 0.0.49 → 0.0.50

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.
Files changed (34) hide show
  1. data/README.md +47 -103
  2. data/lib/netsuite.rb +16 -6
  3. data/lib/netsuite/actions/add.rb +3 -0
  4. data/lib/netsuite/actions/search.rb +126 -0
  5. data/lib/netsuite/actions/search_more_with_id.rb +106 -0
  6. data/lib/netsuite/actions/update.rb +1 -0
  7. data/lib/netsuite/configuration.rb +52 -3
  8. data/lib/netsuite/namespaces/act_sched.rb +11 -0
  9. data/lib/netsuite/records/assembly_item.rb +2 -0
  10. data/lib/netsuite/records/bin_number_list.rb +48 -0
  11. data/lib/netsuite/records/contact.rb +44 -0
  12. data/lib/netsuite/records/contact_list.rb +52 -0
  13. data/lib/netsuite/records/custom_field.rb +4 -0
  14. data/lib/netsuite/records/custom_field_list.rb +11 -2
  15. data/lib/netsuite/records/custom_record_ref.rb +2 -0
  16. data/lib/netsuite/records/customer.rb +1 -1
  17. data/lib/netsuite/records/inventory_item.rb +3 -1
  18. data/lib/netsuite/records/invoice.rb +5 -4
  19. data/lib/netsuite/records/invoice_item.rb +3 -1
  20. data/lib/netsuite/records/kit_item.rb +7 -0
  21. data/lib/netsuite/records/non_inventory_sale_item.rb +1 -0
  22. data/lib/netsuite/records/sales_order.rb +1 -1
  23. data/lib/netsuite/records/task.rb +29 -0
  24. data/lib/netsuite/records/transaction.rb +35 -0
  25. data/lib/netsuite/response.rb +2 -1
  26. data/lib/netsuite/support/actions.rb +4 -0
  27. data/lib/netsuite/support/fields.rb +11 -1
  28. data/lib/netsuite/support/requests.rb +6 -1
  29. data/lib/netsuite/support/search_result.rb +67 -0
  30. data/lib/netsuite/version.rb +1 -1
  31. data/spec/netsuite/configuration_spec.rb +8 -0
  32. data/spec/netsuite/records/non_inventory_sale_item_spec.rb +2 -1
  33. data/spec/netsuite/support/record_refs_spec.rb +10 -1
  34. metadata +12 -2
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  * This gem will act as a wrapper around the NetSuite SuiteTalk WebServices API. Wow, that is a mouthful.
4
4
  * The gem does not cover the entire API, only the subset that we have found useful to cover so far.
5
- * Extending the wrapper is pretty simple. See below for an example.
5
+ * Extending the wrapper is pretty simple. Check out the [contribution help doc](https://github.com/RevolutionPrep/netsuite/wiki/Contributing-to-the-Supported-NetSuite-API)
6
+ * NetSuite development is overall a pretty poor experience. We have a list of [NetSuite Development Resources](https://github.com/RevolutionPrep/netsuite/wiki/NetSuite-Development-Resources) that might make things a bit less painful.
6
7
 
7
8
  ## Installation
8
9
 
@@ -24,7 +25,7 @@ This gem is built for ruby 1.9.x, checkout the [1-8-stable](https://github.com/R
24
25
  Before contributing a patch make sure all existing tests pass.
25
26
 
26
27
  ```
27
- git clone git://github.com/iloveitaly/netsuite.git
28
+ git clone git://github.com/RevolutionPrep/netsuite.git
28
29
  cd netsuite
29
30
  bundle
30
31
  bundle exec rspec
@@ -36,114 +37,57 @@ bundle exec rspec
36
37
  NetSuite.configure do
37
38
  reset!
38
39
 
40
+ # optional, defaults to 2011_2
39
41
  api_version '2012_1'
40
42
 
41
- # specify full wsdl URL for sandbox / production switching
43
+ # optionally specify full wsdl URL (to switch to sandbox, for example)
42
44
  wsdl "https://webservices.sandbox.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl"
43
45
 
46
+ # or specify the sandbox flag if you don't want to deal with specifying a full URL
47
+ sandbox true
48
+
49
+ # often the netsuite servers will hang which would cause a timeout exception to be raised
50
+ # if you don't mind waiting (e.g. processing NS via DJ), increasing the timeout should fix the issue
51
+ read_timeout 100000
52
+
53
+ # you can specify a file or file descriptor to send the log output to (defaults to STDOUT)
54
+ log File.join(Rails.root, 'log/netsuite.log')
55
+
44
56
  # login information
45
- email 'email@domain.com'
46
- password 'password'
57
+ email 'email@domain.com'
58
+ password 'password'
47
59
  account '12345'
48
60
  role 1111
49
61
  end
50
62
  ```
51
63
 
52
- ### Customer
53
-
54
- * Initializing a customer can be done using a hash of attributes.
55
-
56
- ### Get
57
-
58
- * Retrieves the customer by internalId.
59
-
60
- ```Ruby
61
- customer = NetSuite::Records::Customer.get(:internal_id => 4)
62
- # => #<NetSuite::Records::Customer:0x1042f59b8>
63
- customer.is_person
64
- # => true
65
-
66
- # or
67
- NetSuite::Records::Customer.get(4).is_person
68
- ```
69
-
70
- ## Additions
71
-
72
- * Please submit a pull request for any models or actions that you would like to be included. The API is quite large and so we will necessarily not cover all of it.
73
- * Records should go into the `lib/netsuite/records/` directory.
74
- * Actions should be placed in their respective subdirectory under `lib/netsuite/actions`.
75
- * Example:
76
-
77
- ```Ruby
78
- # lib/netsuite/actions/customer/add.rb
79
-
80
- module NetSuite
81
- module Actions
82
- module Customer
83
- class Add
84
-
85
- def initialize(attributes = {})
86
- @attributes = attributes
87
- end
88
-
89
- def self.call(attributes)
90
- new(attributes).call
91
- end
92
-
93
- def call
94
- response = NetSuite::Configuration.connection.request :add do
95
- soap.header = NetSuite::Configuration.auth_header
96
- soap.body = {
97
- :entityId => @attributes[:entity_id],
98
- :companyName => @attributes[:company_name],
99
- :unsubscribe => @attributes[:unsubscribe]
100
- }
101
- end
102
- success = response.to_hash[:add_response][:write_response][:status][:@is_success] == 'true'
103
- body = response.to_hash[:add_response][:write_response][:base_ref]
104
- NetSuite::Response.new(:success => success, :body => body)
105
- end
106
-
107
- end
108
- end
109
- end
110
- end
111
-
112
- response = NetSuite::Actions::Customer::Add.call(
113
- :entity_id => 'Shutter Fly',
114
- :company_name => 'Shutter Fly, Inc.',
115
- :unsubscribe => false
116
- ) # => #<NetSuite::Response:0x1041f64b5>
117
- response.success? # => true
118
- response.body # => { :internal_id => '979', :type => 'customer' }
119
- ```
120
-
121
- ## Gotchas
122
-
123
- * The Initialize Action duck-punches the .initialize method on any class that includes it.
124
- This has not proven to be a issue yet, but should be taken into account when analyzing any
125
- strange issues with the gem.
126
- * Some records define a 'class' field. Defining a 'class' field on a record overrides the
127
- #class and #class= methods for this class. This is very obviously a problem. You can,
128
- instead, define a 'klass' field that will be turned into 'class' before being submitted
129
- to the API. The Invoice record has an example of this.
130
-
131
- ## Contributing
132
-
133
- 1. Fork it
134
- 2. Create your feature branch (`git checkout -b my-new-feature`)
135
- 3. Write new test and ensure that `bundle exec rspec` doesn't fail
136
- 4. Commit your changes (`git commit -am 'Added some feature'`)
137
- 5. Push to the branch (`git push origin my-new-feature`)
138
- 6. Create new Pull Request
139
-
140
- ## Fields and RecordRefs
141
-
142
- Note that some record attributes are specified as Fields while others are specified as RecordRefs. In some cases
143
- attributes are actually RecordRefs in the schema, but we indicate them as Fields. Our experience has shown
144
- this works as long as the attribute is only read from and is not written to. Writing a value for an attribute
145
- that has been wrongly specified will result in an error. Be careful when initializing objects from other objects --
146
- they may carry attributes that write to the new object.
147
-
148
- As we build up this gem we will replace these inconsistent Fields with RecordRefs. Feel free to contribute new Record
149
- definitions to help us along.
64
+ ### Examples
65
+
66
+ ```ruby
67
+ # retrieve a customer
68
+ customer = NetSuite::Records::Customer.get(:internal_id => 4)
69
+ customer.is_person
70
+
71
+ # or
72
+ NetSuite::Records::Customer.get(4).is_person
73
+
74
+ # randomly assign a task
75
+ customer_support_reps = [12345, 12346]
76
+
77
+ task = NetSuite::Records::Task.new(
78
+ :title => 'Take Care of a Customer',
79
+ :assigned => NetSuite::Records::RecordRef.new(customer_support_reps.sample),
80
+ :due_date => DateTime.now + 1,
81
+ :message => "Take care of this"
82
+ )
83
+
84
+ task.add
85
+
86
+ # this will only work on OS X, open a browser to the record that was just created
87
+ `open https://system.sandbox.netsuite.com/app/crm/calendar/task.nl?id=#{invoice.internal_id}`
88
+
89
+ task.update :message => 'New Message'
90
+ ```
91
+
92
+
93
+
data/lib/netsuite.rb CHANGED
@@ -11,6 +11,7 @@ module NetSuite
11
11
  autoload :Response, 'netsuite/response'
12
12
 
13
13
  module Namespaces
14
+ autoload :ActSched, 'netsuite/namespaces/act_sched'
14
15
  autoload :ListAcct, 'netsuite/namespaces/list_acct'
15
16
  autoload :ListRel, 'netsuite/namespaces/list_rel'
16
17
  autoload :PlatformCommon, 'netsuite/namespaces/platform_common'
@@ -28,14 +29,17 @@ module NetSuite
28
29
  autoload :RecordRefs, 'netsuite/support/record_refs'
29
30
  autoload :Records, 'netsuite/support/records'
30
31
  autoload :Requests, 'netsuite/support/requests'
32
+ autoload :SearchResult, 'netsuite/support/search_result'
31
33
  end
32
34
 
33
35
  module Actions
34
- autoload :Add, 'netsuite/actions/add'
35
- autoload :Delete, 'netsuite/actions/delete'
36
- autoload :Get, 'netsuite/actions/get'
37
- autoload :Initialize, 'netsuite/actions/initialize'
38
- autoload :Update, 'netsuite/actions/update'
36
+ autoload :Add, 'netsuite/actions/add'
37
+ autoload :Delete, 'netsuite/actions/delete'
38
+ autoload :Get, 'netsuite/actions/get'
39
+ autoload :Initialize, 'netsuite/actions/initialize'
40
+ autoload :Update, 'netsuite/actions/update'
41
+ autoload :Search, 'netsuite/actions/search'
42
+ autoload :SearchMoreWithId, 'netsuite/actions/search_more_with_id'
39
43
  end
40
44
 
41
45
  module Records
@@ -43,6 +47,7 @@ module NetSuite
43
47
  autoload :Account, 'netsuite/records/account'
44
48
  autoload :AccountingPeriod, 'netsuite/records/accounting_period'
45
49
  autoload :BillAddress, 'netsuite/records/bill_address'
50
+ autoload :BinNumberList, 'netsuite/records/bin_number_list'
46
51
  autoload :Classification, 'netsuite/records/classification'
47
52
  autoload :CreditMemo, 'netsuite/records/credit_memo'
48
53
  autoload :CreditMemoApply, 'netsuite/records/credit_memo_apply'
@@ -63,6 +68,8 @@ module NetSuite
63
68
  autoload :CustomerRefundApplyList, 'netsuite/records/customer_refund_apply_list'
64
69
  autoload :CustomerRefundDeposit, 'netsuite/records/customer_refund_deposit'
65
70
  autoload :CustomerRefundDepositList, 'netsuite/records/customer_refund_deposit_list'
71
+ autoload :ContactList, 'netsuite/records/contact_list'
72
+ autoload :Contact, 'netsuite/records/contact'
66
73
  autoload :Department, 'netsuite/records/department'
67
74
  autoload :Duration, 'netsuite/records/duration'
68
75
  autoload :InventoryItem, 'netsuite/records/inventory_item'
@@ -73,6 +80,7 @@ module NetSuite
73
80
  autoload :JournalEntry, 'netsuite/records/journal_entry'
74
81
  autoload :JournalEntryLine, 'netsuite/records/journal_entry_line'
75
82
  autoload :JournalEntryLineList, 'netsuite/records/journal_entry_line_list'
83
+ autoload :KitItem, 'netsuite/records/kit_item'
76
84
  autoload :Location, 'netsuite/records/location'
77
85
  autoload :NonInventorySaleItem, 'netsuite/records/non_inventory_sale_item'
78
86
  autoload :PaymentMethod, 'netsuite/records/payment_method'
@@ -83,13 +91,15 @@ module NetSuite
83
91
  autoload :SalesOrderItem, 'netsuite/records/sales_order_item'
84
92
  autoload :SalesOrderItemList, 'netsuite/records/sales_order_item_list'
85
93
  autoload :ShipAddress, 'netsuite/records/ship_address'
94
+ autoload :Task, 'netsuite/records/task'
86
95
  autoload :Term, 'netsuite/records/term'
96
+ autoload :Transaction, 'netsuite/records/transaction'
87
97
  end
88
98
 
89
99
  def self.configure(&block)
90
100
  NetSuite::Configuration.instance_eval(&block)
91
101
  Savon.configure do |config|
92
- config.logger = NetSuite::XmlLogger.new(STDOUT)
102
+ config.logger = NetSuite::Configuration.logger
93
103
  end
94
104
  end
95
105
 
@@ -17,6 +17,7 @@ module NetSuite
17
17
  soap.namespaces['xmlns:tranSales'] = "urn:sales_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
18
18
  soap.namespaces['xmlns:platformCommon'] = "urn:common_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
19
19
  soap.namespaces['xmlns:listAcct'] = "urn:accounting_#{NetSuite::Configuration.api_version}.lists.webservices.netsuite.com"
20
+ soap.namespaces['xmlns:actSched'] = "urn:scheduling_#{NetSuite::Configuration.api_version}.activities.webservices.netsuite.com"
20
21
  soap.namespaces['xmlns:tranCust'] = "urn:customers_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
21
22
  soap.namespaces['xmlns:setupCustom'] = "urn:customization_#{NetSuite::Configuration.api_version}.setup.webservices.netsuite.com"
22
23
  soap.namespaces['xmlns:tranGeneral'] = "urn:general_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
@@ -69,6 +70,8 @@ module NetSuite
69
70
  if response.success?
70
71
  @internal_id = response.body[:@internal_id]
71
72
  true
73
+ else
74
+ false
72
75
  end
73
76
  end
74
77
  end
@@ -0,0 +1,126 @@
1
+ # TODO: Tests
2
+ module NetSuite
3
+ module Actions
4
+ class Search
5
+ include Support::Requests
6
+
7
+ def initialize(klass, options = { })
8
+ @klass = klass
9
+ @options = options
10
+ end
11
+
12
+ private
13
+
14
+ def request
15
+ # need to do this outside the block below because of variable scoping
16
+ preferences = (@options[:preferences] || {}).inject({}) do |h, (k, v)|
17
+ h[k.to_s.lower_camelcase] = v
18
+ h
19
+ end
20
+
21
+ connection.request(:search) do
22
+ soap.namespaces['xmlns:platformMsgs'] = "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
23
+ soap.namespaces['xmlns:platformCore'] = "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
24
+ soap.namespaces['xmlns:platformCommon'] = "urn:common_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
25
+ soap.namespaces['xmlns:listRel'] = "urn:relationships_#{NetSuite::Configuration.api_version}.lists.webservices.netsuite.com"
26
+ soap.namespaces['xmlns:tranSales'] = "urn:sales_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
27
+
28
+ # https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteFlex/WebServices/STP_SettingSearchPreferences.html#N2028598271-3
29
+ soap.header = auth_header.merge(preferences.empty? ? {} : { 'platformMsgs:searchPreferences' => preferences })
30
+
31
+ soap.body = request_body
32
+ end
33
+ end
34
+
35
+ # basic search XML
36
+
37
+ # <soap:Body>
38
+ # <platformMsgs:search>
39
+ # <searchRecord xsi:type="ContactSearch">
40
+ # <customerJoin xsi:type="CustomerSearchBasic">
41
+ # <email operator="contains" xsi:type="platformCore:SearchStringField">
42
+ # <platformCore:searchValue>shutterfly.com</platformCore:searchValue>
43
+ # <email>
44
+ # <customerJoin>
45
+ # </searchRecord>
46
+ # </search>
47
+ # </soap:Body>
48
+
49
+ def request_body
50
+ criteria = @options[:criteria] || @options
51
+
52
+ # TODO wish there was a cleaner way to do this: we need the namespace of the record
53
+ example_instance = @klass.new
54
+ namespace = example_instance.record_namespace
55
+
56
+ # extract the class name without the module
57
+ class_name = @klass.to_s.split("::").last
58
+
59
+ search_record = {}
60
+
61
+ criteria.each_pair do |condition_category, conditions|
62
+ search_record["#{namespace}:#{condition_category}"] = conditions.inject({}) do |h, condition|
63
+ h["platformCommon:#{condition[:field]}"] = {
64
+ "platformCore:searchValue" => condition[:value]
65
+ }
66
+
67
+ (h[:attributes!] ||= {}).merge!({
68
+ "platformCommon:#{condition[:field]}" => {
69
+ 'operator' => condition[:operator]
70
+ }
71
+ })
72
+
73
+ h
74
+ end
75
+ end
76
+
77
+ {
78
+ 'searchRecord' => search_record,
79
+ :attributes! => {
80
+ 'searchRecord' => {
81
+ 'xsi:type' => "#{namespace}:#{class_name}Search"
82
+ },
83
+ }
84
+ }
85
+ end
86
+
87
+ def response_header
88
+ @response_header ||= response_header_hash
89
+ end
90
+
91
+ def response_header_hash
92
+ @response_header_hash = @response.header[:document_info]
93
+ end
94
+
95
+ def response_body
96
+ @response_body ||= search_result
97
+ end
98
+
99
+ def search_result
100
+ @search_result = @response[:search_response][:search_result]
101
+ end
102
+
103
+ def success?
104
+ @success ||= search_result[:status][:@is_success] == 'true'
105
+ end
106
+
107
+ module Support
108
+ def self.included(base)
109
+ base.extend(ClassMethods)
110
+ end
111
+
112
+ module ClassMethods
113
+ def search(options = { })
114
+ response = NetSuite::Actions::Search.call(self, options)
115
+
116
+ if response.success?
117
+ NetSuite::Support::SearchResult.new(response, self)
118
+ else
119
+ false
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,106 @@
1
+ # TODO: Tests
2
+ # TODO: DBC
3
+ module NetSuite
4
+ module Actions
5
+ class SearchMoreWithId
6
+ include Support::Requests
7
+
8
+ def initialize(klass, options = { })
9
+ @klass = klass
10
+
11
+ @options = options
12
+ end
13
+
14
+ private
15
+
16
+ def request
17
+ connection.request(:search_more_with_id) do
18
+ soap.namespaces['xmlns:platformMsgs'] = "urn:messages_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
19
+ soap.namespaces['xmlns:platformCore'] = "urn:core_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
20
+ soap.namespaces['xmlns:platformCommon'] = "urn:common_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
21
+ soap.namespaces['xmlns:listRel'] = "urn:relationships_#{NetSuite::Configuration.api_version}.lists.webservices.netsuite.com"
22
+ soap.namespaces['xmlns:tranSales'] = "urn:sales_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
23
+
24
+ soap.header = auth_header
25
+
26
+ soap.body = request_body
27
+ end
28
+ end
29
+
30
+ # TODO: Consistent use of namespace qualifying
31
+ def request_body
32
+ buffer = ''
33
+
34
+ xml = Builder::XmlMarkup.new(target: buffer)
35
+
36
+ xml.platformMsgs(:searchId, @options[:search_id])
37
+ xml.platformMsgs(:pageIndex, @options[:page].present? ? @options[:page] : 2)
38
+
39
+ buffer
40
+ end
41
+
42
+ def response_body
43
+ @response_body ||= response_body_hash
44
+ end
45
+
46
+ def response_body_hash
47
+ @response_body_hash = @response[:search_more_with_id_response][:search_result]
48
+ end
49
+
50
+ def success?
51
+ @success ||= response_body_hash[:status][:@is_success] == 'true'
52
+ end
53
+
54
+ # TODO: Refactor
55
+ def more?
56
+ @more ||= response_body_hash[:page_index] < response_body_hash[:total_pages]
57
+ end
58
+
59
+ module Support
60
+ def self.included(base)
61
+ base.extend(ClassMethods)
62
+ end
63
+
64
+ # TODO: Rename page_index to page
65
+ module ClassMethods
66
+ # Preconditions
67
+ # => options[:search_id] is a string
68
+ # => options[:page], optional, is an integer
69
+ # Postconditions
70
+ # => Hash with the following keys:
71
+ # * page_index which is an integer
72
+ # * total_pages which is an integer
73
+ # * search_results containing array of SearchResult's
74
+ def search_more_with_id(options = { })
75
+ response = NetSuite::Actions::SearchMoreWithId.call(self, options)
76
+
77
+ response_hash = { }
78
+
79
+ if response.success?
80
+ search_results = []
81
+
82
+ if response.body[:search_row_list].present?
83
+ response.body[:search_row_list][:search_row].each do |record|
84
+ search_result = NetSuite::Support::SearchResult.new(record)
85
+
86
+ search_results << search_result
87
+ end
88
+ end
89
+
90
+ page_index = response.body[:page_index]
91
+ total_pages = response.body[:total_pages]
92
+
93
+ response_hash[:page_index] = page_index
94
+ response_hash[:total_pages] = total_pages
95
+ response_hash[:search_results] = search_results
96
+
97
+ response_hash
98
+ else
99
+ raise ArgumentError
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -16,6 +16,7 @@ module NetSuite
16
16
  soap.namespaces['xmlns:tranSales'] = "urn:sales_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
17
17
  soap.namespaces['xmlns:platformCommon'] = "urn:common_#{NetSuite::Configuration.api_version}.platform.webservices.netsuite.com"
18
18
  soap.namespaces['xmlns:listAcct'] = "urn:accounting_#{NetSuite::Configuration.api_version}.lists.webservices.netsuite.com"
19
+ soap.namespaces['xmlns:actSched'] = "urn:scheduling_#{NetSuite::Configuration.api_version}.activities.webservices.netsuite.com"
19
20
  soap.namespaces['xmlns:tranCust'] = "urn:customers_#{NetSuite::Configuration.api_version}.transactions.webservices.netsuite.com"
20
21
  soap.namespaces['xmlns:setupCustom'] = "urn:customization_#{NetSuite::Configuration.api_version}.setup.webservices.netsuite.com"
21
22
  soap.header = auth_header
@@ -11,9 +11,14 @@ module NetSuite
11
11
  end
12
12
 
13
13
  def connection
14
- attributes[:connection] ||= Savon::Client.new(self.wsdl)
14
+ unless attributes[:connection]
15
+ attributes[:connection] = Savon::Client.new(self.wsdl)
16
+ attributes[:connection].http.read_timeout = read_timeout
17
+ end
18
+
19
+ attributes[:connection]
15
20
  end
16
-
21
+
17
22
  def api_version(version = nil)
18
23
  if version
19
24
  self.api_version = version
@@ -26,6 +31,18 @@ module NetSuite
26
31
  attributes[:api_version] = version
27
32
  end
28
33
 
34
+ def sandbox=(flag)
35
+ attributes[:flag] = flag
36
+ end
37
+
38
+ def sandbox(flag = nil)
39
+ if flag.nil?
40
+ attributes[:flag] ||= false
41
+ else
42
+ self.sandbox = flag
43
+ end
44
+ end
45
+
29
46
  def wsdl=(wsdl)
30
47
  attributes[:wsdl] = wsdl
31
48
  end
@@ -34,7 +51,14 @@ module NetSuite
34
51
  if wsdl
35
52
  self.wsdl = wsdl
36
53
  else
37
- attributes[:wsdl] ||= File.expand_path("../../../wsdl/#{api_version}.wsdl", __FILE__)
54
+ if sandbox
55
+ wsdl_path = "https://webservices.sandbox.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl"
56
+ else
57
+ wsdl_path = File.expand_path("../../../wsdl/#{api_version}.wsdl", __FILE__)
58
+ wsdl_path = "https://webservices.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl" unless File.exists? wsdl_path
59
+ end
60
+
61
+ attributes[:wsdl] ||= wsdl_path
38
62
  end
39
63
  end
40
64
 
@@ -106,5 +130,30 @@ module NetSuite
106
130
  end
107
131
  end
108
132
 
133
+ def read_timeout=(timeout)
134
+ attributes[:read_timeout] = timeout
135
+ end
136
+
137
+ def read_timeout(timeout = nil)
138
+ if timeout
139
+ self.read_timeout = timeout
140
+ else
141
+ attributes[:read_timeout] ||= 60
142
+ end
143
+ end
144
+
145
+ def log=(path)
146
+ attributes[:log] = path
147
+ end
148
+
149
+ def log(path = nil)
150
+ self.log = path if path
151
+ attributes[:log]
152
+ end
153
+
154
+ def logger
155
+ attributes[:logger] ||= NetSuite::XmlLogger.new (log && !log.empty?) ? log : STDOUT
156
+ end
157
+
109
158
  end
110
159
  end
@@ -0,0 +1,11 @@
1
+ module NetSuite
2
+ module Namespaces
3
+ module ActSched
4
+
5
+ def record_namespace
6
+ 'actSched'
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -41,6 +41,8 @@ module NetSuite
41
41
  :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor
42
42
 
43
43
  field :custom_field_list, CustomFieldList
44
+ field :bin_number_list, BinNumberList
45
+ field :pricing_matrix, PricingMatrix
44
46
 
45
47
  attr_reader :internal_id
46
48
  attr_accessor :external_id
@@ -0,0 +1,48 @@
1
+ module NetSuite
2
+ module Records
3
+ # TODO this is fairly messy: shouldn't mix multiple classes in one file
4
+ # might be possible to trash the GenericField as well
5
+
6
+ class GenericField
7
+ include Support::Attributes
8
+ include Support::Fields
9
+
10
+ def initialize(attributes = {})
11
+ self.attributes = attributes
12
+ end
13
+ end
14
+
15
+ class BinNumber < GenericField
16
+
17
+ end
18
+
19
+ class BinNumberList
20
+ include Support::Fields
21
+ include Namespaces::PlatformCore
22
+ # include Namespaces::ListAcct
23
+
24
+ fields :bin_number
25
+
26
+ def initialize(attributes = {})
27
+ initialize_from_attributes_hash(attributes)
28
+ end
29
+
30
+ def bin_number=(items)
31
+ case items
32
+ when Hash
33
+ self.bin_numbers << BinNumber.new(items)
34
+ when Array
35
+ items.each { |item| self.bin_numbers << BinNumber.new(item) }
36
+ end
37
+ end
38
+
39
+ def bin_numbers
40
+ @bin_numbers ||= []
41
+ end
42
+
43
+ def to_record
44
+ { "#{record_namespace}:item" => bin_numbers.map(&:to_record) }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ module NetSuite
2
+ module Records
3
+ class Contact
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::ListRel
9
+
10
+ actions :get, :add, :delete, :search
11
+
12
+ fields :salutation, :first_name, :middle_name, :last_name, :title, :phone, :fax, :email, :default_address,
13
+ :entity_id, :phonetic_name, :alt_email, :office_phone, :home_phone, :mobile_phone, :supervisor_phone,
14
+ :assistant_phone, :comments, :bill_pay, :is_private, :is_inactive
15
+
16
+ field :addressbook_list, CustomerAddressbookList
17
+ field :custom_field_list, CustomFieldList
18
+ # field :subscriptions_list, SubscriptionsList
19
+ # field :category_list, CategoryList
20
+
21
+ read_only_fields :last_modified_date, :date_created
22
+
23
+ record_refs :custom_form, :company, :subsidiary, :supervisor, :assistant, :image, :global_subscription_status
24
+
25
+ attr_reader :internal_id
26
+ attr_accessor :external_id
27
+
28
+ def initialize(attributes = {})
29
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
30
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
31
+ initialize_from_attributes_hash(attributes)
32
+ end
33
+
34
+ def to_record
35
+ rec = super
36
+ if rec["#{record_namespace}:customFieldList"]
37
+ rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList")
38
+ end
39
+ rec
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,52 @@
1
+ module NetSuite
2
+ module Records
3
+ class ContactList
4
+ include Namespaces::ActSched
5
+
6
+ def initialize(attributes = {})
7
+ # - the contact list on the NS GUI doesn't show the assigned contact which shows up in the XML
8
+ # - you can't add an arbitary number of contacts through the NS GUI
9
+
10
+ # TODO the contact list doesn't really work because of the strange XML below (2 assigned companies, one contact)
11
+
12
+ # <actSched:contactList>
13
+ # <actSched:contact>
14
+ # <actSched:company xmlns:platformCore="urn:core_2012_1.platform.webservices.netsuite.com" internalId="12345">
15
+ # <platformCore:name>10001 Another Customer</platformCore:name>
16
+ # </actSched:company>
17
+ # </actSched:contact>
18
+ # <actSched:contact>
19
+ # <actSched:company xmlns:platformCore="urn:core_2012_1.platform.webservices.netsuite.com" internalId="12346">
20
+ # <platformCore:name>31500 A Customer</platformCore:name>
21
+ # </actSched:company>
22
+ # <actSched:contact xmlns:platformCore="urn:core_2012_1.platform.webservices.netsuite.com" internalId="12347">
23
+ # <platformCore:name>A Person</platformCore:name>
24
+ # </actSched:contact>
25
+ # </actSched:contact>
26
+ # </actSched:contactList>
27
+
28
+ case attributes[:contact]
29
+ when Hash
30
+ contacts << Contact.new(attributes[:contact])
31
+ when Array
32
+ attributes[:contact].each { |contact| contacts << Contact.new(contact) }
33
+ end
34
+ end
35
+
36
+ def <<(contact)
37
+ @contacts << contact
38
+ end
39
+
40
+ def contacts
41
+ @contacts ||= []
42
+ end
43
+
44
+ def to_record
45
+ contacts.map do |contact|
46
+ { "#{record_namespace}:contact" => contact.to_record }
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -12,6 +12,10 @@ module NetSuite
12
12
  self.attributes = attributes
13
13
  end
14
14
 
15
+ def value
16
+ attributes[:value]
17
+ end
18
+
15
19
  def to_record
16
20
  hash_rec = attributes.inject({}) do |hash, (k,v)|
17
21
  kname = "#{record_namespace}:#{k.to_s.lower_camelcase}"
@@ -6,9 +6,9 @@ module NetSuite
6
6
  def initialize(attributes = {})
7
7
  case attributes[:custom_field]
8
8
  when Hash
9
- custom_fields << CustomField.new(attributes[:custom_field])
9
+ extract_custom_field(attributes[:custom_field])
10
10
  when Array
11
- attributes[:custom_field].each { |custom_field| custom_fields << CustomField.new(custom_field) }
11
+ attributes[:custom_field].each { |custom_field| extract_custom_field(custom_field) }
12
12
  end
13
13
 
14
14
  @custom_fields_assoc = Hash.new
@@ -40,6 +40,15 @@ module NetSuite
40
40
  }.join
41
41
  end
42
42
 
43
+ private
44
+ def extract_custom_field(custom_field_data)
45
+ # TODO this needs to be cleaned up & tested; very messy
46
+ if custom_field_data[:"@xsi:type"] == "platformCore:SelectCustomFieldRef"
47
+ custom_field_data[:value] = CustomRecordRef.new(custom_field_data.delete(:value))
48
+ end
49
+
50
+ custom_fields << CustomField.new(custom_field_data)
51
+ end
43
52
  end
44
53
  end
45
54
  end
@@ -8,6 +8,8 @@ module NetSuite
8
8
  attr_reader :internal_id
9
9
  attr_accessor :external_id, :type_id
10
10
 
11
+ fields :name
12
+
11
13
  def initialize(attributes_or_record = {})
12
14
  case attributes_or_record
13
15
  when Hash
@@ -7,7 +7,7 @@ module NetSuite
7
7
  include Support::Actions
8
8
  include Namespaces::ListRel
9
9
 
10
- actions :get, :add, :delete
10
+ actions :get, :add, :delete, :search
11
11
 
12
12
  fields :access_role, :account_number, :aging, :alt_email, :alt_name, :alt_phone, :bill_pay,
13
13
  :buying_reason, :buying_time_frame, :campaign_category, :category, :click_stream, :comments, :company_name,
@@ -42,7 +42,9 @@ module NetSuite
42
42
 
43
43
  field :pricing_matrix, PricingMatrix
44
44
  field :custom_field_list, CustomFieldList
45
-
45
+ field :bin_number_list, BinNumberList
46
+ field :pricing_matrix, PricingMatrix
47
+
46
48
  attr_reader :internal_id
47
49
  attr_accessor :external_id
48
50
 
@@ -9,13 +9,13 @@ module NetSuite
9
9
 
10
10
  actions :get, :initialize, :add, :delete
11
11
 
12
- fields :alt_handling_cost, :alt_shipping_cost, :balance, :bill_address,
12
+ fields :alt_handling_cost, :balance, :bill_address,
13
13
  :billing_schedule, :contrib_pct, :created_date, :currency_name, :custom_field_list,
14
14
  :deferred_revenue, :discount_amount, :discount_date, :discount_item, :discount_rate,
15
15
  :due_date, :email, :end_date, :est_gross_profit, :est_gross_profit_percent, :exchange_rate,
16
16
  :exclude_commission, :exp_cost_disc_amount, :exp_cost_disc_print, :exp_cost_disc_rate, :exp_cost_disc_tax_1_amt,
17
17
  :exp_cost_disc_taxable, :exp_cost_discount, :exp_cost_list, :exp_cost_tax_code, :exp_cost_tax_rate_1,
18
- :exp_cost_tax_rate_2, :fax, :fob, :gift_cert_applied, :gift_cert_redemption_list, :handling_cost, :handling_tax_1_rate,
18
+ :exp_cost_tax_rate_2, :fax, :fob, :gift_cert_redemption_list, :handling_tax_1_rate,
19
19
  :handling_tax_2_rate, :handling_tax_code, :is_taxable, :item_cost_disc_amount, :item_cost_disc_print,
20
20
  :item_cost_disc_rate, :item_cost_disc_tax_1_amt, :item_cost_disc_taxable, :item_cost_discount, :item_cost_list,
21
21
  :item_cost_tax_code, :item_cost_tax_rate_1, :item_cost_tax_rate_2, :item_list, :job, :last_modified_date,
@@ -24,7 +24,7 @@ module NetSuite
24
24
  :rev_rec_on_rev_commitment, :rev_rec_schedule, :rev_rec_start_date, :revenue_status, :sales_effective_date,
25
25
  :sales_group, :sales_team_list, :ship_address, :ship_date, :ship_group_list,
26
26
  :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :shipping_tax_code, :source, :start_date,
27
- :status, :subsidiary, :sync_partner_teams, :sync_sales_teams, :tax_2_total, :tax_rate,
27
+ :status, :subsidiary, :sync_partner_teams, :sync_sales_teams, :tax_2_total,
28
28
  :tax_total, :time_disc_amount, :time_disc_print, :time_disc_rate, :time_disc_tax_1_amt, :time_disc_taxable,
29
29
  :time_discount, :time_list, :time_tax_code, :time_tax_rate_1, :time_tax_rate_2, :to_be_emailed, :to_be_faxed,
30
30
  :to_be_printed, :total_cost_estimate, :tracking_numbers, :tran_date, :tran_id, :tran_is_vsoe_bundle,
@@ -35,7 +35,8 @@ module NetSuite
35
35
  field :item_list, InvoiceItemList
36
36
  field :custom_field_list, CustomFieldList
37
37
 
38
- read_only_fields :sub_total, :discount_total, :total, :recognized_revenue, :amount_remaining, :amount_paid
38
+ read_only_fields :sub_total, :discount_total, :total, :recognized_revenue, :amount_remaining, :amount_paid,
39
+ :alt_shipping_cost, :gift_cert_applied, :tax_rate, :handling_cost
39
40
 
40
41
  record_refs :account, :bill_address_list, :custom_form, :department, :entity, :klass,
41
42
  :posting_period, :ship_address_list, :terms, :location, :sales_rep, :tax_item, :created_from,
@@ -10,12 +10,14 @@ module NetSuite
10
10
  :defer_rev_rec, :description, :gift_cert_from, :gift_cert_message, :gift_cert_number, :gift_cert_recipient_email,
11
11
  :gift_cert_recipient_name, :gross_amt, :inventory_detail, :is_taxable, :item_is_fulfilled, :license_code, :line,
12
12
  :klass, :options, :order_line, :percent_complete, :quantity, :quantity_available, :quantity_fulfilled,
13
- :quantity_on_hand, :quantity_ordered, :quantity_remaining, :rate, :rev_rec_end_date, :rev_rec_start_date,
13
+ :quantity_on_hand, :quantity_ordered, :rate, :rev_rec_end_date, :rev_rec_start_date,
14
14
  :serial_numbers, :ship_group, :tax1_amt, :tax_rate1, :tax_rate2, :vsoe_allocation, :vsoe_amount, :vsoe_deferral,
15
15
  :vsoe_delivered, :vsoe_permit_discount, :vsoe_price
16
16
 
17
17
  field :custom_field_list, CustomFieldList
18
18
 
19
+ read_only_fields :quantity_remaining
20
+
19
21
  record_refs :department, :item, :job, :location, :price, :rev_rec_schedule, :ship_address, :ship_method, :tax_code, :units, :klass
20
22
 
21
23
  def initialize(attributes_or_record = {})
@@ -0,0 +1,7 @@
1
+ module NetSuite
2
+ module Records
3
+ class KitItem < InventoryItem
4
+
5
+ end
6
+ end
7
+ end
@@ -32,6 +32,7 @@ module NetSuite
32
32
 
33
33
  field :pricing_matrix, PricingMatrix
34
34
  field :custom_field_list, CustomFieldList
35
+ field :pricing_matrix, PricingMatrix
35
36
 
36
37
  attr_reader :internal_id
37
38
  attr_accessor :external_id
@@ -7,7 +7,7 @@ module NetSuite
7
7
  include Support::Actions
8
8
  include Namespaces::TranSales
9
9
 
10
- actions :get, :add, :initialize, :delete, :update
10
+ actions :get, :add, :initialize, :delete, :update, :search
11
11
 
12
12
  fields :alt_handling_cost, :alt_shipping_cost, :amount_paid, :amount_remaining, :auto_apply, :balance,
13
13
  :bill_address, :contrib_pct, :created_date, :currency_name, :deferred_revenue, :discount_rate, :email, :end_date,
@@ -0,0 +1,29 @@
1
+ module NetSuite
2
+ module Records
3
+ class Task
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::ActSched
9
+
10
+ actions :get, :add, :delete, :update
11
+
12
+ fields :title, :send_email, :message, :status, :access_level, :reminder_type,
13
+ :reminder_minutes, :start_date, :end_date, :due_date, :timed_event
14
+
15
+ field :contact_list, ContactList
16
+
17
+ record_refs :assigned, :owner, :company, :contact
18
+
19
+ attr_reader :internal_id
20
+ attr_accessor :external_id
21
+
22
+ def initialize(attributes = {})
23
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
24
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
25
+ initialize_from_attributes_hash(attributes)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module NetSuite
2
+ module Records
3
+ class Transaction
4
+ include Support::Fields
5
+ include Support::RecordRefs
6
+ include Support::Records
7
+ include Support::Actions
8
+ include Namespaces::TranSales
9
+
10
+ actions :get, :search, :search_more_with_id, :initialize, :add, :delete
11
+
12
+ attr_reader :internal_id
13
+ attr_accessor :external_id
14
+
15
+ def initialize(attributes = {})
16
+ @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id)
17
+ @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id)
18
+ initialize_from_attributes_hash(attributes)
19
+ end
20
+
21
+ def self.custom_soap_advanced_search_record_type
22
+ 'tranSales:TransactionSearchAdvanced'
23
+ end
24
+
25
+ def to_record
26
+ rec = super
27
+ if rec["#{record_namespace}:customFieldList"]
28
+ rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList")
29
+ end
30
+ rec
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -1,9 +1,10 @@
1
1
  module NetSuite
2
2
  class Response
3
- attr_accessor :body
3
+ attr_accessor :header, :body
4
4
 
5
5
  def initialize(attributes = {})
6
6
  @success = attributes[:success]
7
+ @header = attributes[:header]
7
8
  @body = attributes[:body]
8
9
  end
9
10
 
@@ -18,6 +18,10 @@ module NetSuite
18
18
  case name
19
19
  when :get
20
20
  self.send(:include, NetSuite::Actions::Get::Support)
21
+ when :search
22
+ self.send(:include, NetSuite::Actions::Search::Support)
23
+ when :search_more_with_id
24
+ self.send(:include, NetSuite::Actions::SearchMoreWithId::Support)
21
25
  when :add
22
26
  self.send(:include, NetSuite::Actions::Add::Support)
23
27
  when :delete
@@ -28,7 +28,11 @@ module NetSuite
28
28
  end
29
29
 
30
30
  define_method("#{name_sym}=") do |value|
31
- attributes[name_sym] = value.kind_of?(klass) ? value : klass.new(value)
31
+ if value.nil?
32
+ attributes.delete(name_sym)
33
+ else
34
+ attributes[name_sym] = value.kind_of?(klass) ? value : klass.new(value)
35
+ end
32
36
  end
33
37
  else
34
38
  define_method(name_sym) do
@@ -57,6 +61,12 @@ module NetSuite
57
61
  field name
58
62
  end
59
63
 
64
+ # a bit of trickery: this is for classes which inherit from other classes
65
+ # i.e. the AssemblyItem, KitItem, etc; this copies the superclass's fields over
66
+ def inherited(klass)
67
+ klass.instance_variable_set("@fields", self.fields)
68
+ klass.instance_variable_set("@read_only_fields", self.read_only_fields)
69
+ end
60
70
  end
61
71
 
62
72
  end
@@ -34,13 +34,18 @@ module NetSuite
34
34
  end
35
35
 
36
36
  def build_response
37
- Response.new(:success => success?, :body => response_body)
37
+ Response.new(:success => success?, header: response_header, :body => response_body)
38
38
  end
39
39
 
40
40
  def success?
41
41
  raise NotImplementedError, 'Please implement a #success? method'
42
42
  end
43
43
 
44
+ # Only care about headers in Search class for now
45
+ def response_header
46
+ nil
47
+ end
48
+
44
49
  def response_body
45
50
  raise NotImplementedError, 'Please implement a #response_body method'
46
51
  end
@@ -0,0 +1,67 @@
1
+ module NetSuite
2
+ module Support
3
+ class SearchResult
4
+ attr_accessor :response
5
+ attr_reader :total_records
6
+
7
+ # header from a basic customer search:
8
+
9
+ # <platformCore:searchResult xmlns:platformCore="urn:core_2012_1.platform.webservices.netsuite.com">
10
+ # <platformCore:status isSuccess="true"/>
11
+ # <platformCore:totalRecords>2770</platformCore:totalRecords>
12
+ # <platformCore:pageSize>5</platformCore:pageSize>
13
+ # <platformCore:totalPages>554</platformCore:totalPages>
14
+ # <platformCore:pageIndex>1</platformCore:pageIndex>
15
+ # <platformCore:searchId>WEBSERVICES_738944_SB2_03012013650784545962753432_28d96bd280</platformCore:searchId>
16
+
17
+ def initialize(response, result_class)
18
+ @response = response
19
+ @total_records = response.body[:total_records].to_i
20
+
21
+ if @total_records > 0
22
+ if @total_records == 1
23
+ [response.body[:record_list][:record]]
24
+ else
25
+ response.body[:record_list][:record]
26
+ end.each do |record|
27
+ results << result_class.new(record)
28
+ end
29
+ end
30
+
31
+ # search_results = []
32
+
33
+ # if !!response.body[:search_row_list] && !response.body[:search_row_list].empty?
34
+ # response.body[:search_row_list][:search_row].each do |record|
35
+ # search_result = NetSuite::Support::SearchResult.new(record)
36
+
37
+ # search_results << search_result
38
+ # end
39
+ # end
40
+
41
+ # search_id = response.header[:ns_id]
42
+ # page_index = response.body[:page_index]
43
+ # total_pages = response.body[:total_pages]
44
+
45
+ # response_hash[:search_id] = search_id
46
+ # response_hash[:page_index] = page_index
47
+ # response_hash[:total_pages] = total_pages
48
+ # response_hash[:search_results] = search_results
49
+ # puts response.body
50
+ # response_hash
51
+ end
52
+
53
+ def results
54
+ @results ||= []
55
+ end
56
+
57
+ def next_page
58
+
59
+ end
60
+
61
+ def all_pages
62
+
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module Netsuite
2
- VERSION = '0.0.49'
2
+ VERSION = '0.0.50'
3
3
  end
@@ -38,6 +38,14 @@ describe NetSuite::Configuration do
38
38
  config.wsdl.should match(/.*\/netsuite\/wsdl\/2011_2\.wsdl/)
39
39
  end
40
40
  end
41
+
42
+ context 'when the wsdl has not been set, but the API has been set' do
43
+ it 'should correctly return the full HTTP sandbox URL' do
44
+ config.api_version '2013_1'
45
+ config.sandbox false
46
+ config.wsdl.should eql('https://webservices.netsuite.com/wsdl/v2013_1_0/netsuite.wsdl')
47
+ end
48
+ end
41
49
  end
42
50
 
43
51
  describe '#auth_header' do
@@ -23,8 +23,9 @@ describe NetSuite::Records::NonInventorySaleItem do
23
23
  item.should have_field(field)
24
24
  end
25
25
 
26
- item.pricing_matrix.class.should == NetSuite::Records::PricingMatrix
26
+ # TODO there is a probably a more robust way to test this
27
27
  item.custom_field_list.class.should == NetSuite::Records::CustomFieldList
28
+ item.pricing_matrix.class.should == NetSuite::Records::PricingMatrix
28
29
  end
29
30
 
30
31
  it 'has the right record_refs' do
@@ -1,5 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe NetSuite::Support::RecordRefs do
4
- pending
4
+ let(:klass) { Class.new.send(:include, NetSuite::Support::Fields) }
5
+ let(:instance) { klass.new }
6
+
7
+ context "assigning record reference" do
8
+ it 'assigns a nil value for a field with a specified class' do
9
+ klass.field(:record_test, NetSuite::Records::RecordRef)
10
+ instance.record_test = nil
11
+ instance.attributes.has_key?(:record_test).should be_false
12
+ end
13
+ end
5
14
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: netsuite
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.49
5
+ version: 0.0.50
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ryan Moran
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-19 00:00:00.000000000 Z
13
+ date: 2013-04-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  version_requirements: !ruby/object:Gem::Requirement
@@ -112,10 +112,13 @@ files:
112
112
  - lib/netsuite/actions/delete.rb
113
113
  - lib/netsuite/actions/get.rb
114
114
  - lib/netsuite/actions/initialize.rb
115
+ - lib/netsuite/actions/search.rb
116
+ - lib/netsuite/actions/search_more_with_id.rb
115
117
  - lib/netsuite/actions/update.rb
116
118
  - lib/netsuite/configuration.rb
117
119
  - lib/netsuite/core_ext/string/lower_camelcase.rb
118
120
  - lib/netsuite/errors.rb
121
+ - lib/netsuite/namespaces/act_sched.rb
119
122
  - lib/netsuite/namespaces/list_acct.rb
120
123
  - lib/netsuite/namespaces/list_rel.rb
121
124
  - lib/netsuite/namespaces/platform_common.rb
@@ -128,7 +131,10 @@ files:
128
131
  - lib/netsuite/records/accounting_period.rb
129
132
  - lib/netsuite/records/assembly_item.rb
130
133
  - lib/netsuite/records/bill_address.rb
134
+ - lib/netsuite/records/bin_number_list.rb
131
135
  - lib/netsuite/records/classification.rb
136
+ - lib/netsuite/records/contact.rb
137
+ - lib/netsuite/records/contact_list.rb
132
138
  - lib/netsuite/records/credit_memo.rb
133
139
  - lib/netsuite/records/credit_memo_apply.rb
134
140
  - lib/netsuite/records/credit_memo_apply_list.rb
@@ -158,6 +164,7 @@ files:
158
164
  - lib/netsuite/records/journal_entry.rb
159
165
  - lib/netsuite/records/journal_entry_line.rb
160
166
  - lib/netsuite/records/journal_entry_line_list.rb
167
+ - lib/netsuite/records/kit_item.rb
161
168
  - lib/netsuite/records/location.rb
162
169
  - lib/netsuite/records/non_inventory_sale_item.rb
163
170
  - lib/netsuite/records/payment_method.rb
@@ -168,7 +175,9 @@ files:
168
175
  - lib/netsuite/records/sales_order_item.rb
169
176
  - lib/netsuite/records/sales_order_item_list.rb
170
177
  - lib/netsuite/records/ship_address.rb
178
+ - lib/netsuite/records/task.rb
171
179
  - lib/netsuite/records/term.rb
180
+ - lib/netsuite/records/transaction.rb
172
181
  - lib/netsuite/response.rb
173
182
  - lib/netsuite/support/actions.rb
174
183
  - lib/netsuite/support/attributes.rb
@@ -176,6 +185,7 @@ files:
176
185
  - lib/netsuite/support/record_refs.rb
177
186
  - lib/netsuite/support/records.rb
178
187
  - lib/netsuite/support/requests.rb
188
+ - lib/netsuite/support/search_result.rb
179
189
  - lib/netsuite/version.rb
180
190
  - lib/netsuite/xml_logger.rb
181
191
  - netsuite.gemspec