diff --git a/.gitignore b/.gitignore
index d87d4be66..653dfb7cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
.bundle
.config
.yardoc
+.idea/
Gemfile.lock
InstalledFiles
_yardoc
diff --git a/lib/netsuite.rb b/lib/netsuite.rb
index 4790e490f..44d8b528e 100644
--- a/lib/netsuite.rb
+++ b/lib/netsuite.rb
@@ -7,8 +7,15 @@
require 'netsuite/core_ext/string/lower_camelcase'
module NetSuite
- autoload :Configuration, 'netsuite/configuration'
- autoload :Response, 'netsuite/response'
+ autoload :Configuration, 'netsuite/configuration'
+ autoload :Response, 'netsuite/response'
+ autoload :Status, 'netsuite/status'
+
+ module Async
+ autoload :Status, 'netsuite/async/status'
+ autoload :WriteResponse, 'netsuite/async/write_response'
+ autoload :WriteResponseList, 'netsuite/async/write_response_list'
+ end
module Namespaces
autoload :ActSched, 'netsuite/namespaces/act_sched'
@@ -55,6 +62,7 @@ module Actions
autoload :UpsertList, 'netsuite/actions/upsert_list'
autoload :Search, 'netsuite/actions/search'
autoload :Login, 'netsuite/actions/login'
+ autoload :AsyncAddList, 'netsuite/actions/async_add_list'
end
module Records
diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb
new file mode 100644
index 000000000..e4428c34b
--- /dev/null
+++ b/lib/netsuite/actions/async_add_list.rb
@@ -0,0 +1,81 @@
+# https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/AsynchronousRequestProcessing.html
+module NetSuite
+ module Actions
+ class AsyncAddList
+ include Support::Requests
+
+ def initialize(objects)
+ @objects = objects
+ end
+
+ private
+
+ def request(credentials={})
+ NetSuite::Configuration.connection({element_form_default: :unqualified}, credentials).call(:async_add_list, message: request_body)
+ end
+
+ #
+ #
+ #
+ # Shutter Fly
+ # Shutter Fly, Inc
+ #
+ #
+ # Target
+ # Target
+ #
+ #
+ #
+ def request_body
+ attrs = @objects.map do |o|
+ hash = o.to_record.merge({
+ '@xsi:type' => o.record_type
+ })
+ if o.respond_to?(:external_id) && o.external_id
+ hash['@externalId'] = o.external_id
+ end
+ hash
+ end
+ { 'record' => attrs }
+ end
+
+ #
+ #
+ #
+ # ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685
+ # pending
+ # 0.0
+ # 0.0
+ #
+ #
+ #
+ def response_body
+ @response_body ||= begin
+ response_hash = @response.to_hash
+ response_hash[:async_add_list_response] ? response_hash[:async_add_list_response][:async_status_result] : nil
+ end
+ end
+
+ def success?
+ !response_body.nil?
+ end
+
+ module Support
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def async_add_list(objects = [], credentials = {})
+ objects_list = objects.map do |object|
+ object.kind_of?(self) ? object : self.new(object)
+ end
+ response = NetSuite::Actions::AsyncAddList.call([objects_list], credentials)
+ response.success? ? NetSuite::Async::Status.new(response.body) : false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/netsuite/async/status.rb b/lib/netsuite/async/status.rb
new file mode 100644
index 000000000..e388e69ac
--- /dev/null
+++ b/lib/netsuite/async/status.rb
@@ -0,0 +1,63 @@
+module NetSuite
+ module Async
+ class Status
+ include Support::Fields
+
+ read_only_fields :job_id, :status, :percent_completed, :est_remaining_duration
+
+ def initialize(attributes = {})
+ initialize_from_attributes_hash(attributes)
+ end
+
+ #
+ #
+ # ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685
+ #
+ #
+ #
+
+ def self.get(options = {}, credentials = {})
+ response = NetSuite::Configuration.connection(credentials).call(:check_async_status, :message => request_body(options))
+ new(response.to_hash[:check_async_status_response][:async_status_result])
+ end
+
+ def self.request_body(options)
+ {
+ 'platformMsgs:jobId' => { :content! => options[:job_id] }
+ }
+ end
+
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+
+ def finished?
+ ['failed', 'finished', 'finishedWithErrors'].include?(status)
+ end
+
+ def success?
+ status == "finished"
+ end
+
+ def errors?
+ status == "finishedWithErrors"
+ end
+
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/netsuite/async/write_response.rb b/lib/netsuite/async/write_response.rb
new file mode 100644
index 000000000..aebfb38c1
--- /dev/null
+++ b/lib/netsuite/async/write_response.rb
@@ -0,0 +1,18 @@
+module NetSuite
+ module Async
+ class WriteResponse
+
+ attr_reader :base_ref, :status
+
+ def initialize(write_result)
+ @status = NetSuite::Status.new(write_result[:status])
+ @base_ref = NetSuite::Records::RecordRef.new(write_result[:base_ref]) if write_result[:base_ref]
+ end
+
+ def success?
+ @status.success?
+ end
+
+ end
+ end
+end
diff --git a/lib/netsuite/async/write_response_list.rb b/lib/netsuite/async/write_response_list.rb
new file mode 100644
index 000000000..c0f8d3293
--- /dev/null
+++ b/lib/netsuite/async/write_response_list.rb
@@ -0,0 +1,44 @@
+# https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/AsynchronousRequestProcessing.html
+module NetSuite
+ module Async
+ class WriteResponseList
+
+ attr_reader :list, :status, :type
+
+ def initialize(async_result)
+ @type = async_result[:"@xsi:type"]
+ response_list = async_result[:write_response_list]
+ @status = NetSuite::Status.new(response_list[:status]) if response_list[:status]
+ responses = Array[response_list[:write_response]].flatten
+ @list = responses.map { |response| NetSuite::Async::WriteResponse.new(response) }
+ end
+
+ def self.get(options = {})
+ response = NetSuite::Configuration.connection({element_form_default: :unqualified}).call(:get_async_result, message: request_body(options))
+ self.new(response.to_hash[:get_async_result_response][:async_result])
+ end
+
+ def has_errors?
+ return true if @status && !@status.success?
+ @list.each do |result|
+ return true unless result.success?
+ end
+ false
+ end
+
+ #
+ #
+ # ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685
+ # 1
+ #
+ #
+ def self.request_body(options)
+ {
+ 'platformMsgs:jobId' => { :content! => options[:job_id] },
+ 'platformMsgs:pageIndex' => { :content! => options[:page_index] }
+ }
+ end
+
+ end
+ end
+end
diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb
index a5c67548e..1316016ab 100644
--- a/lib/netsuite/records/invoice.rb
+++ b/lib/netsuite/records/invoice.rb
@@ -7,7 +7,7 @@ class Invoice
include Support::Actions
include Namespaces::TranSales
- actions :get, :get_list, :initialize, :add, :delete, :upsert
+ actions :get, :get_list, :initialize, :add, :delete, :upsert, :async_add_list
fields :balance, :bill_address,
:billing_schedule, :contrib_pct, :created_date, :currency_name, :custom_field_list,
diff --git a/lib/netsuite/records/payment_method.rb b/lib/netsuite/records/payment_method.rb
index 8ae8dd090..9bcda0932 100644
--- a/lib/netsuite/records/payment_method.rb
+++ b/lib/netsuite/records/payment_method.rb
@@ -5,8 +5,7 @@ class PaymentMethod
include Support::RecordRefs
include Support::Actions
- actions :add, :delete, :get, :get_list, :search, :search_more_with_id,
- :update, :upsert, :upsert_list
+ actions :add, :delete, :get, :get_list, :search, :update, :upsert, :upsert_list
fields :credit_card, :express_checkout_arrangement, :is_debit_card, :is_inactive, :is_online, :name,
:pay_pal_email_address, :undep_funds, :use_express_checkout
diff --git a/lib/netsuite/status.rb b/lib/netsuite/status.rb
new file mode 100644
index 000000000..119d3a404
--- /dev/null
+++ b/lib/netsuite/status.rb
@@ -0,0 +1,18 @@
+module NetSuite
+ class StatusDetail < NetSuite::Error; end
+
+ class Status
+
+ attr_reader :is_success, :details
+
+ def initialize(status)
+ @is_success = status[:@is_success] == 'true'
+ @details = status[:status_detail] ? Array[status[:status_detail]].flatten.map { |d| NetSuite::StatusDetail.new(d) } : []
+ end
+
+ def success?
+ @is_success
+ end
+
+ end
+end
diff --git a/lib/netsuite/support/actions.rb b/lib/netsuite/support/actions.rb
index c26a95475..ac13c963d 100644
--- a/lib/netsuite/support/actions.rb
+++ b/lib/netsuite/support/actions.rb
@@ -28,8 +28,6 @@ def action(name)
self.send(:include, NetSuite::Actions::GetSelectValue::Support)
when :search
self.send(:include, NetSuite::Actions::Search::Support)
- when :search_more_with_id
- self.send(:include, NetSuite::Actions::SearchMoreWithId::Support)
when :add
self.send(:include, NetSuite::Actions::Add::Support)
when :upsert
@@ -42,6 +40,8 @@ def action(name)
self.send(:include, NetSuite::Actions::Update::Support)
when :initialize
self.send(:include, NetSuite::Actions::Initialize::Support)
+ when :async_add_list
+ self.send(:include, NetSuite::Actions::AsyncAddList::Support)
else
raise "Unknown action: #{name.inspect}"
end
diff --git a/spec/netsuite/actions/async_add_list_spec.rb b/spec/netsuite/actions/async_add_list_spec.rb
new file mode 100644
index 000000000..dcf3139cc
--- /dev/null
+++ b/spec/netsuite/actions/async_add_list_spec.rb
@@ -0,0 +1,96 @@
+require 'spec_helper'
+
+describe NetSuite::Actions::AsyncAddList do
+ before { savon.mock! }
+ after { savon.unmock! }
+
+ context 'Invoices' do
+ context 'one invoice' do
+ let(:invoices) do
+ [
+ NetSuite::Records::Invoice.new(
+ entity: NetSuite::Records::Customer.new(internal_id: 1),
+ item_list: NetSuite::Records::InvoiceItemList.new(item: {item: NetSuite::Records::RecordRef.new(internal_id: 2), amount: 3}))
+ ]
+ end
+
+ before do
+ savon.expects(:async_add_list).with(:message => {
+ "record"=> [{
+ :attributes! => {"tranSales:entity" => {"internalId" => 1, "type" => "customer"}},
+ "tranSales:entity" => {},
+ "tranSales:itemList" => {
+ "tranSales:item" => [{
+ :attributes! => {"tranSales:item" => {"internalId" => 2}},
+ "tranSales:item" => {},
+ "tranSales:amount" => 3
+ }]
+ },
+ "@xsi:type" => "tranSales:Invoice"
+ }]
+ }).returns(File.read('spec/support/fixtures/async_add_list/async_add_list_one_invoice.xml'))
+ end
+
+ it 'makes a valid request to the NetSuite API' do
+ NetSuite::Actions::AsyncAddList.call([invoices])
+ end
+
+ it 'returns a valid Response object' do
+ response = NetSuite::Actions::AsyncAddList.call([invoices])
+ expect(response).to be_kind_of(NetSuite::Response)
+ expect(response).to be_success
+ end
+ end
+ end
+
+ context 'two invoices' do
+ let(:invoices) do
+ [
+ NetSuite::Records::Invoice.new(
+ entity: NetSuite::Records::Customer.new(internal_id: 1),
+ item_list: NetSuite::Records::InvoiceItemList.new(item: {item: NetSuite::Records::RecordRef.new(internal_id: 2), amount: 3})),
+ NetSuite::Records::Invoice.new(
+ entity: NetSuite::Records::Customer.new(internal_id: 2),
+ item_list: NetSuite::Records::InvoiceItemList.new(item: {item: NetSuite::Records::RecordRef.new(internal_id: 3), amount: 4})),
+ ]
+ end
+
+ before do
+ savon.expects(:async_add_list).with(:message => {
+ "record"=> [{
+ :attributes! => {"tranSales:entity" => {"internalId" => 1, "type" => "customer"}},
+ "tranSales:entity" => {},
+ "tranSales:itemList" => {
+ "tranSales:item" => [{
+ :attributes! => {"tranSales:item" => {"internalId" => 2}},
+ "tranSales:item" => {},
+ "tranSales:amount" => 3
+ }]
+ },
+ "@xsi:type" => "tranSales:Invoice"
+ }, {
+ :attributes! => {"tranSales:entity" => {"internalId" => 2, "type" => "customer"}},
+ "tranSales:entity" => {},
+ "tranSales:itemList" => {
+ "tranSales:item" => [{
+ :attributes! => {"tranSales:item" => {"internalId" => 3}},
+ "tranSales:item" => {},
+ "tranSales:amount" => 4
+ }]
+ },
+ "@xsi:type" => "tranSales:Invoice"
+ }]
+ }).returns(File.read('spec/support/fixtures/async_add_list/async_add_list_one_invoice.xml'))
+ end
+
+ it 'makes a valid request to the NetSuite API' do
+ NetSuite::Actions::AsyncAddList.call([invoices])
+ end
+
+ it 'returns a valid Response object' do
+ response = NetSuite::Actions::AsyncAddList.call([invoices])
+ expect(response).to be_kind_of(NetSuite::Response)
+ expect(response).to be_success
+ end
+ end
+end
diff --git a/spec/netsuite/actions/login_spec.rb b/spec/netsuite/actions/login_spec.rb
index 4be372456..2f860ab0a 100644
--- a/spec/netsuite/actions/login_spec.rb
+++ b/spec/netsuite/actions/login_spec.rb
@@ -1,9 +1,10 @@
require 'spec_helper'
describe NetSuite::Actions::Login do
- it 'properly executes a login call' do
- savon.mock!
+ before(:all) { savon.mock! }
+ after(:all) { savon.unmock! }
+ it 'properly executes a login call' do
message = {"platformMsgs:passport"=>{"platformCore:email"=>"email", "platformCore:password"=>"password", "platformCore:account"=>"1234", "platformCore:role"=>234}}
savon.expects(:login).with(:message => message).returns(File.read('spec/support/fixtures/login.xml'))
diff --git a/spec/netsuite/async/status_spec.rb b/spec/netsuite/async/status_spec.rb
new file mode 100644
index 000000000..105a0b6ae
--- /dev/null
+++ b/spec/netsuite/async/status_spec.rb
@@ -0,0 +1,93 @@
+require 'spec_helper'
+
+describe NetSuite::Async::Status do
+ before(:all) { savon.mock! }
+ after(:all) { savon.unmock! }
+
+ describe 'AsyncStatus' do
+ context 'retrieving pending job status' do
+ before do
+ message = {
+ "platformMsgs:jobId" => {:content! => "PENDING_JOB_ID"}
+ }
+ savon.expects(:check_async_status).with(:message => message).returns(File.read('spec/support/fixtures/async_get_status/async_get_status_pending.xml'))
+ end
+
+ it 'returns a valid AsyncStatus object' do
+ status = NetSuite::Async::Status.get(job_id: 'PENDING_JOB_ID')
+ expect(status).to be_kind_of(NetSuite::Async::Status)
+ end
+
+ it 'returns an AsyncStatus that has all the right fields' do
+ status = NetSuite::Async::Status.get(job_id: 'PENDING_JOB_ID')
+ [:job_id, :status, :percent_completed, :est_remaining_duration].each do |attribute|
+ expect(status.respond_to?(attribute)).to be_truthy
+ end
+ end
+
+ it 'returns an AsyncStatus where finished? is false' do
+ status = NetSuite::Async::Status.get(job_id: 'PENDING_JOB_ID')
+ expect(status.finished?).to be_falsey
+ end
+
+ it 'returns an AsyncStatus where errors? is false' do
+ status = NetSuite::Async::Status.get(job_id: 'PENDING_JOB_ID')
+ expect(status.errors?).to be_falsey
+ end
+
+ it 'returns an AsyncStatus where success? is false' do
+ status = NetSuite::Async::Status.get(job_id: 'PENDING_JOB_ID')
+ expect(status.success?).to be_falsey
+ end
+ end
+ end
+
+ context 'retrieving finished job status' do
+ before do
+ message = {
+ "platformMsgs:jobId" => {:content! => "FINISHED_JOB_ID"}
+ }
+ savon.expects(:check_async_status).with(:message => message).returns(File.read('spec/support/fixtures/async_get_status/async_get_status_finished.xml'))
+ end
+
+ it 'returns an AsyncStatus where finished? is true' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_JOB_ID')
+ expect(status.finished?).to be_truthy
+ end
+
+ it 'returns an AsyncStatus where errors? is false' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_JOB_ID')
+ expect(status.errors?).to be_falsey
+ end
+
+ it 'returns an AsyncStatus where success? is true' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_JOB_ID')
+ expect(status.success?).to be_truthy
+ end
+ end
+
+ context 'retrieving finished with errors job status' do
+ before do
+ message = {
+ "platformMsgs:jobId" => {:content! => "FINISHED_WITH_ERRORS_JOB_ID"}
+ }
+ savon.expects(:check_async_status).with(:message => message).returns(File.read('spec/support/fixtures/async_get_status/async_get_status_finished_with_errors.xml'))
+ end
+
+ it 'returns an AsyncStatus where finished? is true' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_WITH_ERRORS_JOB_ID')
+ expect(status.finished?).to be_truthy
+ end
+
+ it 'returns an AsyncStatus where errors? is false' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_WITH_ERRORS_JOB_ID')
+ expect(status.errors?).to be_truthy
+ end
+
+ it 'returns an AsyncStatus where success? is true' do
+ status = NetSuite::Async::Status.get(job_id: 'FINISHED_WITH_ERRORS_JOB_ID')
+ expect(status.success?).to be_falsey
+ end
+ end
+end
+
diff --git a/spec/netsuite/async/write_response_list_spec.rb b/spec/netsuite/async/write_response_list_spec.rb
new file mode 100644
index 000000000..727240a0a
--- /dev/null
+++ b/spec/netsuite/async/write_response_list_spec.rb
@@ -0,0 +1,115 @@
+require 'spec_helper'
+
+describe NetSuite::Async::WriteResponseList do
+ before(:all) { savon.mock! }
+ after(:all) { savon.unmock! }
+
+ let(:options) do
+ { job_id: 'SOME_JOB_ID', page_index: 1 }
+ end
+
+ let(:message) do
+ {
+ "platformMsgs:jobId" => { :content! => "SOME_JOB_ID" },
+ "platformMsgs:pageIndex" => { :content! => 1 }
+ }
+ end
+
+ context 'Invoices' do
+ context 'results for AsyncAddList single invoice' do
+
+ before do
+ savon.expects(:get_async_result).with(:message => message).returns(File.read('spec/support/fixtures/async_write_results/single_invoice.xml'))
+ end
+
+ it 'returns a valid AsyncWriteResults object with the correct type' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results).to be_kind_of(NetSuite::Async::WriteResponseList)
+ expect(results.type).to eql('AsyncAddListResult')
+ end
+
+ it 'returns an AsyncWriteResults object that has all the right attributes' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ [:status, :list].each do |attribute|
+ expect(results.respond_to?(attribute)).to be_truthy
+ end
+ end
+
+ it 'returns an AsyncWriteResults object with no overall status' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.status).to be_nil
+ end
+
+ it 'returns an AsyncWriteResults object where has_errors return false' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.has_errors?).to be_falsey
+ end
+
+ it 'returns an AsyncWriteResults object with a single successful result' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.list).to be_kind_of(Array)
+ expect(results.list.length).to eql(1)
+ result = results.list[0]
+ expect(result).to be_kind_of(NetSuite::Async::WriteResponse)
+ expect(result.success?).to be_truthy
+ expect(result.base_ref.internal_id).to eql('internal id')
+ end
+ end
+
+ context 'result for AsyncAddList single invalid invoice' do
+ before do
+ savon.expects(:get_async_result).with(:message => message).returns(File.read('spec/support/fixtures/async_write_results/single_invalid_invoice.xml'))
+ end
+
+ it 'returns an AsyncWriteResults object with no overall status' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.status).to be_nil
+ end
+
+ it 'returns an AsyncWriteResults object where has_errors return true' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.has_errors?).to be_truthy
+ end
+
+ it 'returns an AsyncWriteResults object with a single non-successful result' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.list.length).to eql(1)
+ expect(results.list[0].success?).to be_falsey
+ status = results.list[0].status
+ expect(status).to be_kind_of(NetSuite::Status)
+ expect(status.details).to be_kind_of(Array)
+ expect(status.details.length).to eql(1)
+ detail = status.details[0]
+ expect(detail).to be_kind_of(NetSuite::StatusDetail)
+ expect(detail.code).to eq('INVALID_KEY_OR_REF')
+ expect(detail.message).to eq('Invalid item reference key 123 for entity 456.')
+ end
+ end
+
+ context 'result for AsyncAddList two invoices, one invalid' do
+ before do
+ savon.expects(:get_async_result).with(:message => message).returns(File.read('spec/support/fixtures/async_write_results/two_invoices_one_invalid.xml'))
+ end
+
+ it 'returns an AsyncWriteResults object with no overall status' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.status).to be_nil
+ end
+
+ it 'returns an AsyncWriteResults object where has_errors return true' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.has_errors?).to be_truthy
+ end
+
+ it 'returns an AsyncWriteResults object with one successful and one non-successful result' do
+ results = NetSuite::Async::WriteResponseList.get(options)
+ expect(results.list.length).to eql(2)
+ expect(results.list[0].success?).to be_truthy
+ expect(results.list[1].success?).to be_falsey
+ detail = results.list[1].status.details[0]
+ expect(detail.code).to eq('INVALID_KEY_OR_REF')
+ expect(detail.message).to eq('Invalid item reference key 123 for entity 456.')
+ end
+ end
+ end
+end
diff --git a/spec/netsuite/status_spec.rb b/spec/netsuite/status_spec.rb
new file mode 100644
index 000000000..b7c01e062
--- /dev/null
+++ b/spec/netsuite/status_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe NetSuite::Status do
+ let(:success_status) do
+ NetSuite::Status.new(:@is_success => "true")
+ end
+
+ let(:error_status) do
+ NetSuite::Status.new(
+ :status_detail => { :code=>"SOME_ERROR_CODE", :message=>"Some error message.", :@type=>"ERROR" },
+ :@is_success => "false"
+ )
+ end
+
+ let(:warnings_status) do
+ NetSuite::Status.new(
+ :status_detail => [
+ { :code=>"SOME_WARNING_CODE_1", :message=>"Some warning message.", :@type=>"WARNING" },
+ { :code=>"SOME_WARNING_CODE_2", :message=>"Some other warning message.", :@type=>"WARNING" }
+ ],
+ :@is_success => "true"
+ )
+ end
+
+ describe '#initialize' do
+ it 'sets the status so that success? works properly' do
+ expect(success_status.success?).to be_truthy
+ expect(error_status.success?).to be_falsey
+ end
+
+ it 'handle missing status details' do
+ expect(success_status.details).to be_empty
+ end
+
+ it 'creates the status details when available' do
+ details = error_status.details
+ expect(details).to be_kind_of(Array)
+ expect(details.length).to eql(1)
+ expect(details[0]).to be_kind_of(NetSuite::StatusDetail)
+ expect(details[0].code).to eql('SOME_ERROR_CODE')
+ expect(details[0].message).to eql('Some error message.')
+ end
+
+ it 'handles multiple status details' do
+ details = warnings_status.details
+ expect(details).to be_kind_of(Array)
+ expect(details.length).to eql(2)
+ expect(details[0].code).to eql('SOME_WARNING_CODE_1')
+ expect(details[0].message).to eql('Some warning message.')
+ expect(details[1].code).to eql('SOME_WARNING_CODE_2')
+ expect(details[1].message).to eql('Some other warning message.')
+ end
+ end
+end
+
diff --git a/spec/support/fixtures/async_add_list/async_add_list_one_invoice.xml b/spec/support/fixtures/async_add_list/async_add_list_one_invoice.xml
new file mode 100644
index 000000000..7535d4d4e
--- /dev/null
+++ b/spec/support/fixtures/async_add_list/async_add_list_one_invoice.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ ASYNCWEBSERVICES_3319168_02262015941097136894317791_4c4e2a55
+ pending
+ 0.0
+ 0.0
+
+
+
+
diff --git a/spec/support/fixtures/async_get_status/async_get_status_finished.xml b/spec/support/fixtures/async_get_status/async_get_status_finished.xml
new file mode 100644
index 000000000..09b96e616
--- /dev/null
+++ b/spec/support/fixtures/async_get_status/async_get_status_finished.xml
@@ -0,0 +1,17 @@
+
+
+
+ WEBSERVICES_3319168_02272015876751983208856794_e775e644b3ee5
+
+
+
+
+
+ FINISHED_JOB_ID
+ finished
+ 100.0
+ 0.0
+
+
+
+
diff --git a/spec/support/fixtures/async_get_status/async_get_status_finished_with_errors.xml b/spec/support/fixtures/async_get_status/async_get_status_finished_with_errors.xml
new file mode 100644
index 000000000..80178d6f9
--- /dev/null
+++ b/spec/support/fixtures/async_get_status/async_get_status_finished_with_errors.xml
@@ -0,0 +1,17 @@
+
+
+
+ WEBSERVICES_3319168_022720158761379161393517551_b61393231d61
+
+
+
+
+
+ FINISHED_WITH_ERRORS_JOB_ID
+ finishedWithErrors
+ 100.0
+ 0.0
+
+
+
+
diff --git a/spec/support/fixtures/async_get_status/async_get_status_pending.xml b/spec/support/fixtures/async_get_status/async_get_status_pending.xml
new file mode 100644
index 000000000..f28579ec5
--- /dev/null
+++ b/spec/support/fixtures/async_get_status/async_get_status_pending.xml
@@ -0,0 +1,17 @@
+
+
+
+ WEBSERVICES_3319168_022720158806426472138387911_a661c9e629be
+
+
+
+
+
+ PENDING_JOB_ID
+ pending
+ 0.0
+ 0.0
+
+
+
+
diff --git a/spec/support/fixtures/async_write_results/single_invalid_invoice.xml b/spec/support/fixtures/async_write_results/single_invalid_invoice.xml
new file mode 100644
index 000000000..2b0a32760
--- /dev/null
+++ b/spec/support/fixtures/async_write_results/single_invalid_invoice.xml
@@ -0,0 +1,23 @@
+
+
+
+ ASYNCWEBSERVICES_3319168_022720158735415691298135860_6b1c30a
+
+
+
+
+
+
+
+
+
+ INVALID_KEY_OR_REF
+ Invalid item reference key 123 for entity 456.
+
+
+
+
+
+
+
+
diff --git a/spec/support/fixtures/async_write_results/single_invoice.xml b/spec/support/fixtures/async_write_results/single_invoice.xml
new file mode 100644
index 000000000..c0d8989d7
--- /dev/null
+++ b/spec/support/fixtures/async_write_results/single_invoice.xml
@@ -0,0 +1,19 @@
+
+
+
+ ASYNCWEBSERVICES_3319168_022720158682169801739034155_856ac4f
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spec/support/fixtures/async_write_results/two_invoices_one_invalid.xml b/spec/support/fixtures/async_write_results/two_invoices_one_invalid.xml
new file mode 100644
index 000000000..b45b9ef9e
--- /dev/null
+++ b/spec/support/fixtures/async_write_results/two_invoices_one_invalid.xml
@@ -0,0 +1,28 @@
+
+
+
+ ASYNCWEBSERVICES_3319168_02272015862228930236966352_e70989c2
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INVALID_KEY_OR_REF
+ Invalid item reference key 123 for entity 456.
+
+
+
+
+
+
+
+
+