Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added AsyncAddList to Invoice #169

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 && [email protected]?
@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] || 1 }
}
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