Skip to content

Commit

Permalink
Added AsyncAddList
Browse files Browse the repository at this point in the history
  • Loading branch information
prburke committed Mar 4, 2015
1 parent 5bc69ea commit 266833f
Show file tree
Hide file tree
Showing 22 changed files with 734 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.bundle
.config
.yardoc
.idea/
Gemfile.lock
InstalledFiles
_yardoc
Expand Down
12 changes: 10 additions & 2 deletions lib/netsuite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down
81 changes: 81 additions & 0 deletions lib/netsuite/actions/async_add_list.rb
Original file line number Diff line number Diff line change
@@ -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

# <soap:Body>
# <asyncAddList>
# <record xsi:type="listRel:Customer" externalId="ext1">
# <listRel:entityId>Shutter Fly</listRel:entityId>
# <listRel:companyName>Shutter Fly, Inc</listRel:companyName>
# </record>
# <record xsi:type="listRel:Customer" externalId="ext2">
# <listRel:entityId>Target</listRel:entityId>
# <listRel:companyName>Target</listRel:companyName>
# </record>
# </asyncAddList>
# </soap:Body>
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

#<soapenv:Body>
# <asyncAddListResponse xmlns="urn:messages_2_5.platform.webservices.netsuite.com">
# <asyncStatusResult xmlns="urn:core_2_5.platform.webservices.netsuite.com">
# <jobId>ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685</jobId>
# <status>pending</status>
# <percentCompleted>0.0</percentCompleted>
# <estRemainingDuration>0.0</estRemainingDuration>
# </asyncStatusResult>
# </asyncAddListResponse>
#</soapenv:Body>
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
63 changes: 63 additions & 0 deletions lib/netsuite/async/status.rb
Original file line number Diff line number Diff line change
@@ -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

#<soap:Body>
# <platformMsgs:checkAsyncStatus>
# <platformMsgs:jobId>ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685
# </platformMsgs:jobId>
# </platformMsgs:checkAsyncStatus>
#</soap:Body>

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

#<complexType name="AsyncStatusResult">
# <sequence>
# <element name="jobId" type="xsd:string"/>
# <element name="status" type="platformCoreTyp:AsyncStatusType"/>
# <element name="percentCompleted" type="xsd:double"/>
# <element name="estRemainingDuration" type="xsd:double"/>
#</sequence>
#</complexType>

#<simpleType name="AsyncStatusType">
# <restriction base="{http://www.w3.org/2001/XMLSchema}string">
# <enumeration value="failed"/>
# <enumeration value="finishedWithErrors"/>
# <enumeration value="pending"/>
# <enumeration value="processing"/>
# <enumeration value="finished"/>
# </restriction>
#</simpleType>

def finished?
['failed', 'finished', 'finishedWithErrors'].include?(status)
end

def success?
status == "finished"
end

def errors?
status == "finishedWithErrors"
end

end
end
end
18 changes: 18 additions & 0 deletions lib/netsuite/async/write_response.rb
Original file line number Diff line number Diff line change
@@ -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
44 changes: 44 additions & 0 deletions lib/netsuite/async/write_response_list.rb
Original file line number Diff line number Diff line change
@@ -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

#<soap:Body>
# <platformMsgs:getAsyncResult>
# <platformMsgs:jobId>ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685</platformMsgs:jobId>
# <platformMsgs:pageIndex>1</platformMsgs:pageIndex>
# </platformMsgs:getAsyncResult>
#</soap:Body>
def self.request_body(options)
{
'platformMsgs:jobId' => { :content! => options[:job_id] },
'platformMsgs:pageIndex' => { :content! => options[:page_index] }
}
end

end
end
end
2 changes: 1 addition & 1 deletion lib/netsuite/records/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions lib/netsuite/records/payment_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions lib/netsuite/status.rb
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions lib/netsuite/support/actions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
96 changes: 96 additions & 0 deletions spec/netsuite/actions/async_add_list_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 266833f

Please sign in to comment.