From cf1338ce625fdb66d27609f274f2ef3ca9d4b6c3 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 5 Nov 2019 10:27:39 -0600 Subject: [PATCH 01/62] [CLOUD-737-attach-functionality] WHY: previously could not utilize soap action attach This adds the attach basic reference functionality into the gem --- Gemfile | 1 + lib/netsuite.rb | 2 + lib/netsuite/actions/add.rb | 1 - lib/netsuite/actions/attach.rb | 87 +++++++++++++++++++ .../records/attach_basic_reference.rb | 20 +++++ lib/netsuite/support/actions.rb | 2 + spec/netsuite/actions/attach_spec.rb | 82 +++++++++++++++++ .../records/attach_basic_reference_spec.rb | 38 ++++++++ .../fixtures/attach/attach_file_to_bill.xml | 16 ++++ .../attach/attach_file_to_bill_error.xml | 20 +++++ 10 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 lib/netsuite/actions/attach.rb create mode 100644 lib/netsuite/records/attach_basic_reference.rb create mode 100644 spec/netsuite/actions/attach_spec.rb create mode 100644 spec/netsuite/records/attach_basic_reference_spec.rb create mode 100644 spec/support/fixtures/attach/attach_file_to_bill.xml create mode 100644 spec/support/fixtures/attach/attach_file_to_bill_error.xml diff --git a/Gemfile b/Gemfile index ac23ef3eb..5f9f9197a 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gem 'simplecov', :require => false gem 'pry-nav' gem 'pry-rescue' +gem 'pry' # optional dependency for more accurate timezone conversion gem 'tzinfo', '1.2.5' diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 0e28e5711..8fd4fd7c1 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -49,6 +49,7 @@ module Support module Actions autoload :Add, 'netsuite/actions/add' + autoload :Attach, 'netsuite/actions/attach' autoload :Delete, 'netsuite/actions/delete' autoload :DeleteList, 'netsuite/actions/delete_list' autoload :Get, 'netsuite/actions/get' @@ -74,6 +75,7 @@ module Records autoload :Account, 'netsuite/records/account' autoload :AccountingPeriod, 'netsuite/records/accounting_period' autoload :Address, 'netsuite/records/address' + autoload :AttachBasicReference, 'netsuite/records/attach_basic_reference' autoload :BaseRefList, 'netsuite/records/base_ref_list' autoload :BillAddress, 'netsuite/records/bill_address' autoload :BillingSchedule, 'netsuite/records/billing_schedule' diff --git a/lib/netsuite/actions/add.rb b/lib/netsuite/actions/add.rb index 4cc352661..dbf42c165 100644 --- a/lib/netsuite/actions/add.rb +++ b/lib/netsuite/actions/add.rb @@ -73,7 +73,6 @@ def errors module Support def add(credentials={}) response = NetSuite::Actions::Add.call([self], credentials) - @errors = response.errors if response.success? diff --git a/lib/netsuite/actions/attach.rb b/lib/netsuite/actions/attach.rb new file mode 100644 index 000000000..d7af3f4cd --- /dev/null +++ b/lib/netsuite/actions/attach.rb @@ -0,0 +1,87 @@ +module NetSuite + module Actions + class Attach + include Support::Requests + + attr_reader :response_hash + + def initialize(object=nil) + @object = object + end + + private + + def request(credentials={}) + NetSuite::Configuration.connection({}, credentials).call(:attach, :message => request_body) + end + + #please note, reference is spelled referece and is documented that way in NetSuite's documentation + # + # + # + # + # + # + # + # + + def request_body + hash = { + 'platformMsgs:attachReferece' => { + :content! => @object.to_record, + '@xsi:type' => @object.record_type + } + } + #not crazy about this solution but not sure how else to get the 'xsi:type' var in the hash + hash["platformMsgs:attachReferece"][:content!][:attributes!]["platformCore:attachTo"]["xsi:type"] = "platformCore:RecordRef" + hash["platformMsgs:attachReferece"][:content!][:attributes!]["platformCore:attachedRecord"]["xsi:type"] = "platformCore:RecordRef" + + hash + end + + def success? + @success ||= response_hash[:status][:@is_success] == 'true' + end + + def response_body + @response_body ||= response_hash[:base_ref] + end + + def response_errors + if response_hash[:status] && response_hash[:status][:status_detail] + @response_errors ||= errors + end + end + + def response_hash + @response_hash ||= @response.to_hash[:attach_response][:write_response] + end + + def errors + error_obj = response_hash[:status][:status_detail] + error_obj = [error_obj] if error_obj.class == Hash + error_obj.map do |error| + NetSuite::Error.new(error) + end + end + + + module Support + def attach(credentials={}) + response = NetSuite::Actions::Attach.call([self], credentials) + + @errors = response.errors + + if response.success? + @internal_id = response.body[:@internal_id] + true + else + false + end + end + end + + + end + end +end diff --git a/lib/netsuite/records/attach_basic_reference.rb b/lib/netsuite/records/attach_basic_reference.rb new file mode 100644 index 000000000..f52d2569d --- /dev/null +++ b/lib/netsuite/records/attach_basic_reference.rb @@ -0,0 +1,20 @@ +module NetSuite + module Records + class AttachBasicReference + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::PlatformCore + + actions :attach + + record_refs :attach_to, :attached_record + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + + end + end +end diff --git a/lib/netsuite/support/actions.rb b/lib/netsuite/support/actions.rb index 19d62c552..29617272a 100644 --- a/lib/netsuite/support/actions.rb +++ b/lib/netsuite/support/actions.rb @@ -46,6 +46,8 @@ def action(name) self.send(:include, NetSuite::Actions::UpdateList::Support) when :initialize self.send(:include, NetSuite::Actions::Initialize::Support) + when :attach + self.send(:include, NetSuite::Actions::Attach::Support) else raise "Unknown action: #{name.inspect}" end diff --git a/spec/netsuite/actions/attach_spec.rb b/spec/netsuite/actions/attach_spec.rb new file mode 100644 index 000000000..79f01a9e0 --- /dev/null +++ b/spec/netsuite/actions/attach_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe NetSuite::Actions::Attach do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + + context "AttachBasicReference" do + let(:attach_basic_reference) do + NetSuite::Records::AttachBasicReference.new(:attach_to => {internal_id: "11111", type: "VendorBill"}, :attached_record => {internal_id: "22222", type: "File"}) + end + + before do + savon.expects(:attach).with(:message => { + 'platformMsgs:attachReferece' => { + :content! => { + :attributes! => { + "platformCore:attachTo" => { + "internalId"=>"11111", + "type"=>"vendorBill", "xsi:type"=>"platformCore:RecordRef" + }, + "platformCore:attachedRecord"=> { + "internalId"=>"22222", + "type"=>"file", + "xsi:type"=>"platformCore:RecordRef" + } + }, + "platformCore:attachTo"=>{}, + "platformCore:attachedRecord"=>{} + }, + "@xsi:type"=>"platformCore:AttachBasicReference" + } + }).returns(File.read('spec/support/fixtures/attach/attach_file_to_bill.xml')) + end + + + it "makes a valid request to the NetSuite API" do + NetSuite::Actions::Attach.call([attach_basic_reference]) + end + + it "returns a valid Response object" do + response = NetSuite::Actions::Attach.call([attach_basic_reference]) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end + + context "when not successful" do + before do + savon.expects(:attach).with(:message => { + 'platformMsgs:attachReferece' => { + :content! => { + :attributes! => { + "platformCore:attachTo" => { + "internalId"=>"11111", + "type"=>"vendorBill", "xsi:type"=>"platformCore:RecordRef" + }, + "platformCore:attachedRecord"=> { + "internalId"=>"22222", + "type"=>"file", + "xsi:type"=>"platformCore:RecordRef" + } + }, + "platformCore:attachTo"=>{}, + "platformCore:attachedRecord"=>{} + }, + "@xsi:type"=>"platformCore:AttachBasicReference" + } + }).returns(File.read('spec/support/fixtures/attach/attach_file_to_bill_error.xml')) + end + + it 'provides an error method on the object with details about the error' do + #i'm not sure why the only way to get the errors is to attach twice + attach_basic_reference.attach + attach_basic_reference.attach + error = attach_basic_reference.errors.first + expect(error).to be_kind_of(NetSuite::Error) + expect(error.type).to eq('ERROR') + expect(error.code).to eq('USER_ERROR') + expect(error.message).to eq('Invalid Attachment record combination') + end + end + end +end diff --git a/spec/netsuite/records/attach_basic_reference_spec.rb b/spec/netsuite/records/attach_basic_reference_spec.rb new file mode 100644 index 000000000..72d2ff034 --- /dev/null +++ b/spec/netsuite/records/attach_basic_reference_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe NetSuite::Records::AttachBasicReference do + let(:attach_basic_reference) { NetSuite::Records::AttachBasicReference.new } + + it "has all the right record refs" do + [:attach_to, :attached_record].each do |record_ref| + expect(attach_basic_reference).to have_record_ref(record_ref) + end + end + + describe '#attach' do + let(:test_data) { {:attach_to => {internal_id: "11111", type: "VendorBill"}, :attached_record => {internal_id: "22222", type: "File"} } } + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '11111' }) } + + it "returns true" do + attach_basic_reference = NetSuite::Records::AttachBasicReference.new(test_data) + + expect(NetSuite::Actions::Attach).to receive(:call).with([attach_basic_reference], {}).and_return(response) + expect(attach_basic_reference.attach).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + attach_basic_reference = NetSuite::Records::AttachBasicReference.new(test_data) + + expect(NetSuite::Actions::Attach).to receive(:call).with([attach_basic_reference], {}).and_return(response) + expect(attach_basic_reference.attach).to be_falsey + end + end + + end + +end diff --git a/spec/support/fixtures/attach/attach_file_to_bill.xml b/spec/support/fixtures/attach/attach_file_to_bill.xml new file mode 100644 index 000000000..77bbbddba --- /dev/null +++ b/spec/support/fixtures/attach/attach_file_to_bill.xml @@ -0,0 +1,16 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + + + + + + diff --git a/spec/support/fixtures/attach/attach_file_to_bill_error.xml b/spec/support/fixtures/attach/attach_file_to_bill_error.xml new file mode 100644 index 000000000..0c0aa47d5 --- /dev/null +++ b/spec/support/fixtures/attach/attach_file_to_bill_error.xml @@ -0,0 +1,20 @@ + + + + + WEBSERVICES_5102954_SB1_110820191277209614860972177_6400640b + + + + + + + + USER_ERROR + Invalid Attachment record combination + + + + + + From 2b61c8387d34a67a2f1e3df87f54107e796674c6 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Mon, 18 Nov 2019 08:12:17 -0600 Subject: [PATCH 02/62] [hotfix-CLOUD-737] Why: When adding a file from a workflow, even though it will sometimes be 'succuessful' it was still returning a 500 to the platform This change addresses the need by: made an update to the gem to return true/200 if a file is created and to return the file name if it is successfully created so we can query file by that attribute to create attachment Ticket [CLOUD-737] --- lib/netsuite/actions/add.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/actions/add.rb b/lib/netsuite/actions/add.rb index dbf42c165..3cda9a9e2 100644 --- a/lib/netsuite/actions/add.rb +++ b/lib/netsuite/actions/add.rb @@ -74,10 +74,15 @@ module Support def add(credentials={}) response = NetSuite::Actions::Add.call([self], credentials) @errors = response.errors - + if response.success? - @internal_id = response.body[:@internal_id] - true + if response.body.class == Nori::StringIOFile + @original_filename = response.body.original_filename + true + else + @internal_id = response.body[:@internal_id] + true + end else false end From f4e02c9f4f55b317b712e80782698db74fd3c35e Mon Sep 17 00:00:00 2001 From: reginad1 Date: Mon, 18 Nov 2019 11:29:03 -0600 Subject: [PATCH 03/62] [HOTFIX-CLOUD-737-add-action-for-file] Why: * no nested if else statements! This change addresses the need by: * learned about try Ticket * [CLOUD-] --- lib/netsuite/actions/add.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/netsuite/actions/add.rb b/lib/netsuite/actions/add.rb index 3cda9a9e2..60fa8198f 100644 --- a/lib/netsuite/actions/add.rb +++ b/lib/netsuite/actions/add.rb @@ -76,13 +76,8 @@ def add(credentials={}) @errors = response.errors if response.success? - if response.body.class == Nori::StringIOFile - @original_filename = response.body.original_filename - true - else - @internal_id = response.body[:@internal_id] - true - end + @internal_id = response.body.dig(:@internal_id) unless response.body.class == Nori::StringIOFile + true else false end From 022a6e69eac16074e6869c490da46944d4430084 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Fri, 31 Jan 2020 13:04:20 -0600 Subject: [PATCH 04/62] [CLD-597-intercompany-updates] *WHY The sales order record did not have the intercompany transaction field or the intercompany status field *This addresses the need by Adding those fields to the sales order record -caveat: I tried to test this with multiple payloads provided by the automation engineer but have yet to get a successful post. I have communicated the two errors we are getting, either a permission error or wrong enity for record depending on how the payload is formatted. The automation engineer is checking with customer, so I'm not sure if we want to wait to merge this in until the errors have been confirmed or not. [CLD-597] --- lib/netsuite/records/sales_order.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/records/sales_order.rb b/lib/netsuite/records/sales_order.rb index 8b6059e47..3fdb2d23e 100644 --- a/lib/netsuite/records/sales_order.rb +++ b/lib/netsuite/records/sales_order.rb @@ -18,7 +18,7 @@ class SalesOrder :start_date, :status, :sync_partner_teams, :sync_sales_teams, :tax2_total, :tax_rate, :to_be_emailed, :to_be_faxed, :to_be_printed, :total_cost_estimate, :tran_date, :tran_id, :tran_is_vsoe_bundle, :vat_reg_num, :linked_tracking_numbers, :vsoe_auto_calc, :quantity, :bill_city, :bill_state, :ship_city, :ship_state, :cost_estimate, - :amount, :is_ship_address, :auth_code, :pn_ref_num, :is_multi_ship_to + :amount, :is_ship_address, :auth_code, :pn_ref_num, :is_multi_ship_to, :interco_status # NOTE API >= 2014_2 only field :shipping_address, Address @@ -39,7 +39,7 @@ class SalesOrder record_refs :account, :bill_address_list, :created_from, :currency, :custom_form, :department, :discount_item, :entity, :gift_cert, :handling_tax_code, :job, :klass, :lead_source, :location, :message_sel, :opportunity, :partner, :posting_period, :promo_code, - :sales_group, :sales_rep, :ship_method, :shipping_tax_code, :subsidiary, :terms, :tax_item, :payment_method, :ship_address_list + :sales_group, :sales_rep, :ship_method, :shipping_tax_code, :subsidiary, :terms, :tax_item, :payment_method, :ship_address_list, :interco_transaction attr_reader :internal_id attr_accessor :external_id From e4dcb3148b7a14b13f24f4a523175c0a003c5739 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Thu, 30 Jan 2020 14:12:38 -0600 Subject: [PATCH 05/62] [CLD-571-expense-report] Why: *The expense report object did not exist in the netsuite ruby gem or in our connector This change addresses the need by: *updating the gem and connector to include the expense report object. This ticket is dependent on the pr for branch cld-571 in the netsuite ruby connector Ticket * [CLD-571] --- lib/netsuite.rb | 3 ++ lib/netsuite/records/expense_report.rb | 50 +++++++++++++++++++ .../records/expense_report_expense.rb | 38 ++++++++++++++ .../records/expense_report_expense_list.rb | 9 ++++ 4 files changed, 100 insertions(+) create mode 100644 lib/netsuite/records/expense_report.rb create mode 100644 lib/netsuite/records/expense_report_expense.rb create mode 100644 lib/netsuite/records/expense_report_expense_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 8fd4fd7c1..fa85a1bbf 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -160,6 +160,9 @@ module Records autoload :Duration, 'netsuite/records/duration' autoload :Employee, 'netsuite/records/employee' autoload :EntityCustomField, 'netsuite/records/entity_custom_field' + autoload :ExpenseReport, 'netsuite/records/expense_report' + autoload :ExpenseReportExpense, 'netsuite/records/expense_report_expense' + autoload :ExpenseReportExpenseList, 'netsuite/records/expense_report_expense_list' autoload :File, 'netsuite/records/file' autoload :GiftCertificate, 'netsuite/records/gift_certificate' autoload :GiftCertificateItem, 'netsuite/records/gift_certificate_item' diff --git a/lib/netsuite/records/expense_report.rb b/lib/netsuite/records/expense_report.rb new file mode 100644 index 000000000..8cf7b5619 --- /dev/null +++ b/lib/netsuite/records/expense_report.rb @@ -0,0 +1,50 @@ +module NetSuite + module Records + class ExpenseReport + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::TranEmp + + actions :add, :get, :search, :update + + fields :accounting_approval, :advance, :amount, :complete, :created_date, :due_date, :last_modified_date, :memo, :status, :supervisor_approval, :tax1_amt, :tax2_amt, :total, :tran_date, :train_id, :use_multi_currency + + # todo + # field :accounting_book_detail_list, AccountingBookDetailList + field :custom_field_list, CustomFieldList + field :expense_list, ExpenseReportExpenseList + + + record_refs :account, :approval_status, :klass, :custom_form, :department, :entity, :location, :next_approver, :posting_period, :subsidiary + + attr_reader :internal_id + attr_accessor :external_id + attr_accessor :search_joins + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec + end + + def self.search_class_name + "Transaction" + end + + def self.search_class_namespace + 'tranEmp' + end + + end + end +end diff --git a/lib/netsuite/records/expense_report_expense.rb b/lib/netsuite/records/expense_report_expense.rb new file mode 100644 index 000000000..e81ea0af5 --- /dev/null +++ b/lib/netsuite/records/expense_report_expense.rb @@ -0,0 +1,38 @@ +module NetSuite + module Records + class ExpenseReportExpense + include Support::Fields + include Support::RecordRefs + include Support::Records + include Namespaces::TranEmp + + fields :amount, :exchange_rate, :expense_date, :foreign_amount, :gross_amt, :is_billable, :is_non_reimburable, :line, :memo, :quantity, :rate, :receipt, :ref_number, :tax1_amt, :tax_rate1, :tax_rate2 + + field :custom_field_list + + record_refs :category, :klass, :currency, :customer, :department, :location, :tax_code + + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec + end + + end + end +end diff --git a/lib/netsuite/records/expense_report_expense_list.rb b/lib/netsuite/records/expense_report_expense_list.rb new file mode 100644 index 000000000..f875f3753 --- /dev/null +++ b/lib/netsuite/records/expense_report_expense_list.rb @@ -0,0 +1,9 @@ +module NetSuite + module Records + class ExpenseReportExpenseList < Support::Sublist + include Namespaces::TranEmp + + sublist :expense, ExpenseReportExpense + end + end +end From 439e87184b77a4f9e60a27434db6f7f56a4ddd8c Mon Sep 17 00:00:00 2001 From: reginad1 Date: Mon, 17 Feb 2020 09:29:39 -0600 Subject: [PATCH 06/62] [CLD-659-sales-order-lines] *Why: Inventory subsidiary and inventory location were not present fields on the sales order line item *This change addresses the need by: Added those two fields --- lib/netsuite/records/sales_order_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/sales_order_item.rb b/lib/netsuite/records/sales_order_item.rb index 0b659a5ea..9a5d4661d 100644 --- a/lib/netsuite/records/sales_order_item.rb +++ b/lib/netsuite/records/sales_order_item.rb @@ -21,7 +21,7 @@ class SalesOrderItem field :custom_field_list, CustomFieldList - record_refs :department, :item, :job, :klass, :location, :price, :rev_rec_schedule, :tax_code, :units + record_refs :department, :item, :job, :klass, :location, :price, :rev_rec_schedule, :tax_code, :units, :inventory_location, :inventory_subsidiary def initialize(attributes_or_record = {}) case attributes_or_record From fe66da5004ed68a4ddde2cea0f64a5a7ef03f333 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Mon, 24 Feb 2020 13:08:54 -0600 Subject: [PATCH 07/62] [CLD-669-vendorcredit-record-refs] *Why: The vendor credit object in the gem previously had record reference fields defined differently than the majority of the other objects in the gem. Because of this, when we call '.record_refs' in the connector, it was erroring *This addresses the change by: Adding in the record ref support and redefined how the record reference fields are defined. [CLD-669] --- lib/netsuite/records/vendor_credit.rb | 13 ++----------- lib/netsuite/records/vendor_credit_expense.rb | 11 +++-------- lib/netsuite/records/vendor_credit_item.rb | 17 +++++++---------- 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/lib/netsuite/records/vendor_credit.rb b/lib/netsuite/records/vendor_credit.rb index 02b844dd4..6209e6d6c 100644 --- a/lib/netsuite/records/vendor_credit.rb +++ b/lib/netsuite/records/vendor_credit.rb @@ -15,17 +15,8 @@ class VendorCredit :currency_name, :tran_date, :exchange_rate, :memo - field :custom_form, RecordRef - field :account, RecordRef - field :bill_address_list, RecordRef - field :created_from, RecordRef - field :entity, RecordRef - field :currency, RecordRef - field :posting_period, RecordRef - field :department, RecordRef - field :klass, RecordRef - field :location, RecordRef - field :subsidiary, RecordRef + record_refs :custom_form, :account, :bill_address_list, :created_from, :entity, :currency, :post_period, :department, :klass, :location, :subsidiary + field :billing_address, Address field :expense_list, VendorCreditExpenseList field :item_list, VendorCreditItemList diff --git a/lib/netsuite/records/vendor_credit_expense.rb b/lib/netsuite/records/vendor_credit_expense.rb index 6c2261b93..9e3635649 100644 --- a/lib/netsuite/records/vendor_credit_expense.rb +++ b/lib/netsuite/records/vendor_credit_expense.rb @@ -2,6 +2,7 @@ module NetSuite module Records class VendorCreditExpense include Support::Fields + include Support::RecordRefs include Support::Records include Namespaces::TranPurch @@ -12,16 +13,10 @@ class VendorCreditExpense :amortization_end_date, :amortization_residual - field :category, RecordRef - field :taxCode, RecordRef - field :account, RecordRef - field :department, RecordRef - field :klass, RecordRef - field :amortizationSched, RecordRef - field :location, RecordRef - field :customer, RecordRef field :custom_field_list, CustomFieldList + record_refs :account, :category, :customer, :department, :item, :location, :units, :tax_code + def initialize(attributes = {}) initialize_from_attributes_hash(attributes) end diff --git a/lib/netsuite/records/vendor_credit_item.rb b/lib/netsuite/records/vendor_credit_item.rb index 19f2a6920..d50742829 100644 --- a/lib/netsuite/records/vendor_credit_item.rb +++ b/lib/netsuite/records/vendor_credit_item.rb @@ -2,6 +2,7 @@ module NetSuite module Records class VendorCreditItem include Support::Fields + include Support::RecordRefs include Support::Records include Namespaces::TranPurch @@ -14,16 +15,12 @@ class VendorCreditItem :amortization_end_date, :amortization_residual - field :item, RecordRef - field :units, RecordRef - field :department, RecordRef - field :customer, RecordRef - field :location, RecordRef - field :tax_code, RecordRef - field :serial_numbers_list, RecordRefList - field :inventory_detail, InventoryDetail - field :custom_field_list, CustomFieldList - field :options, CustomFieldList + field :serial_numbers_list, RecordRefList + field :inventory_detail, InventoryDetail + field :custom_field_list, CustomFieldList + field :options, CustomFieldList + + record_refs :item, :units, :department, :customer, :location, :tax_code def initialize(attributes = {}) initialize_from_attributes_hash(attributes) From 330ffa6b367ab02c57ed23ac1445ff6a5ef07e8f Mon Sep 17 00:00:00 2001 From: reginad1 Date: Fri, 13 Mar 2020 12:20:08 -0500 Subject: [PATCH 08/62] [CLD-725-expenses-on-purchaseorders] Why: *The purchase order expenses were not supported within the gem, so they were being returned in the soap response but not in the json response returned by the gem. With this object missing, it would not have allowed posting a purchase order with an expense list either. This change addresses the need by: *Added the purchase order expense list record and the purchase order expense record Ticket * [CLD-725] --- lib/netsuite.rb | 2 + lib/netsuite/records/purchase_order.rb | 1 + .../records/purchase_order_expense.rb | 37 +++++++++++++++++++ .../records/purchase_order_expense_list.rb | 11 ++++++ 4 files changed, 51 insertions(+) create mode 100644 lib/netsuite/records/purchase_order_expense.rb create mode 100644 lib/netsuite/records/purchase_order_expense_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index fa85a1bbf..99ebf1fd2 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -240,6 +240,8 @@ module Records autoload :PromotionsList, 'netsuite/records/promotions_list' autoload :Promotions, 'netsuite/records/promotions' autoload :PurchaseOrder, 'netsuite/records/purchase_order' + autoload :PurchaseOrderExpenseList, 'netsuite/records/purchase_order_expense_list' + autoload :PurchaseOrderExpense, 'netsuite/records/purchase_order_expense' autoload :PurchaseOrderItemList, 'netsuite/records/purchase_order_item_list' autoload :PurchaseOrderItem, 'netsuite/records/purchase_order_item' autoload :Roles, 'netsuite/records/roles' diff --git a/lib/netsuite/records/purchase_order.rb b/lib/netsuite/records/purchase_order.rb index fe5c0d12d..63fc18102 100644 --- a/lib/netsuite/records/purchase_order.rb +++ b/lib/netsuite/records/purchase_order.rb @@ -20,6 +20,7 @@ class PurchaseOrder field :shipping_address, Address field :custom_field_list, CustomFieldList field :item_list, PurchaseOrderItemList + field :expense_list, PurchaseOrderExpenseList # TODO custom lists # :ship_address_list diff --git a/lib/netsuite/records/purchase_order_expense.rb b/lib/netsuite/records/purchase_order_expense.rb new file mode 100644 index 000000000..d04be63c9 --- /dev/null +++ b/lib/netsuite/records/purchase_order_expense.rb @@ -0,0 +1,37 @@ +module NetSuite + module Records + class PurchaseOrderExpense + include Support::Fields + include Support::RecordRefs + include Support::Records + include Namespaces::TranPurch + + fields :amount, :gross_amt, :is_billable, :is_closed, :line, :memo, :tax1_amt, :tax_amount, :tax_details_reference, :tax_rate1, :tax_rate2 + + field :custom_field_list, CustomFieldList + + record_refs :account, :category, :klass, :created_from, :customer, :department, :linked_order_list, :location, :tax_code + + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec + end + end + end +end diff --git a/lib/netsuite/records/purchase_order_expense_list.rb b/lib/netsuite/records/purchase_order_expense_list.rb new file mode 100644 index 000000000..4411698aa --- /dev/null +++ b/lib/netsuite/records/purchase_order_expense_list.rb @@ -0,0 +1,11 @@ +module NetSuite + module Records + class PurchaseOrderExpenseList < Support::Sublist + include Namespaces::TranPurch + + sublist :expense, PurchaseOrderExpense + + alias :expenses :expense + end + end +end From 7fbe5b2cb04c2c01f6c675b5358085aa10183053 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 17 Mar 2020 11:41:37 -0500 Subject: [PATCH 09/62] [CLD-737-item-receipt-expenses] Why: *There was not support for expense lines to show up on item receipts in Netsuite This change addresses the need by: *added in the item receipt expense list and item receipt expense models to the gem Ticket * [CLD-737] --- lib/netsuite.rb | 2 ++ lib/netsuite/records/item_receipt.rb | 1 + lib/netsuite/records/item_receipt_expense.rb | 36 +++++++++++++++++++ .../records/item_receipt_expense_list.rb | 11 ++++++ 4 files changed, 50 insertions(+) create mode 100644 lib/netsuite/records/item_receipt_expense.rb create mode 100644 lib/netsuite/records/item_receipt_expense_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 99ebf1fd2..8be6824e2 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -200,6 +200,8 @@ module Records autoload :ItemMember, 'netsuite/records/item_member' autoload :ItemMemberList, 'netsuite/records/item_member_list' autoload :ItemReceipt, 'netsuite/records/item_receipt' + autoload :ItemReceiptExpenseList, 'netsuite/records/item_receipt_expense_list' + autoload :ItemReceiptExpense, 'netsuite/records/item_receipt_expense' autoload :ItemReceiptItemList, 'netsuite/records/item_receipt_item_list' autoload :ItemReceiptItem, 'netsuite/records/item_receipt_item' autoload :ItemVendor, 'netsuite/records/item_vendor' diff --git a/lib/netsuite/records/item_receipt.rb b/lib/netsuite/records/item_receipt.rb index 798b2b70c..5638e3243 100644 --- a/lib/netsuite/records/item_receipt.rb +++ b/lib/netsuite/records/item_receipt.rb @@ -22,6 +22,7 @@ class ItemReceipt # :landed_costs_list field :item_list, ItemReceiptItemList + field :expense_list, ItemReceiptExpenseList field :custom_field_list, CustomFieldList attr_reader :internal_id diff --git a/lib/netsuite/records/item_receipt_expense.rb b/lib/netsuite/records/item_receipt_expense.rb new file mode 100644 index 000000000..a5633fe80 --- /dev/null +++ b/lib/netsuite/records/item_receipt_expense.rb @@ -0,0 +1,36 @@ +module NetSuite + module Records + class ItemReceiptExpense + include Support::Fields + include Support::RecordRefs + include Support::Records + include Namespaces::TranPurch + + fields :account, :amount, :line, :mark_received, :memo, :order_line + + field :options, CustomFieldList + field :custom_field_list, CustomFieldList + + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec + end + end + end +end diff --git a/lib/netsuite/records/item_receipt_expense_list.rb b/lib/netsuite/records/item_receipt_expense_list.rb new file mode 100644 index 000000000..74ed27909 --- /dev/null +++ b/lib/netsuite/records/item_receipt_expense_list.rb @@ -0,0 +1,11 @@ +module NetSuite + module Records + class ItemReceiptExpenseList < Support::Sublist + include Namespaces::TranPurch + + sublist :expense, ItemReceiptExpense + + alias :expenses :expense + end + end +end From 0423790e92f1b2dfd8dce32e83b7b2ad37aa8b7a Mon Sep 17 00:00:00 2001 From: reginad1 Date: Wed, 25 Mar 2020 11:04:26 -0500 Subject: [PATCH 10/62] [CLD-756-Add-Expense-Categories] Why: *expense categories were needed for posting an expense report This change addresses the need by: *adding in the expense category record to support searching for expense category Ticket * [CLD-756] --- lib/netsuite.rb | 3 ++ lib/netsuite/records/expense_category.rb | 40 +++++++++++++++++++ lib/netsuite/records/expense_category_rate.rb | 28 +++++++++++++ .../records/expense_category_rates_list.rb | 9 +++++ 4 files changed, 80 insertions(+) create mode 100644 lib/netsuite/records/expense_category.rb create mode 100644 lib/netsuite/records/expense_category_rate.rb create mode 100644 lib/netsuite/records/expense_category_rates_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 8be6824e2..f409ae902 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -160,6 +160,9 @@ module Records autoload :Duration, 'netsuite/records/duration' autoload :Employee, 'netsuite/records/employee' autoload :EntityCustomField, 'netsuite/records/entity_custom_field' + autoload :ExpenseCategory, 'netsuite/records/expense_category' + autoload :ExpenseCategoryRate, 'netsuite/records/expense_category_rate' + autoload :ExpenseCategoryRatesList, 'netsuite/records/expense_category_rates_list' autoload :ExpenseReport, 'netsuite/records/expense_report' autoload :ExpenseReportExpense, 'netsuite/records/expense_report_expense' autoload :ExpenseReportExpenseList, 'netsuite/records/expense_report_expense_list' diff --git a/lib/netsuite/records/expense_category.rb b/lib/netsuite/records/expense_category.rb new file mode 100644 index 000000000..39ecd9149 --- /dev/null +++ b/lib/netsuite/records/expense_category.rb @@ -0,0 +1,40 @@ +module NetSuite + module Records + class ExpenseCategory + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::ListAcct + + actions :add, :get, :search, :update + + fields :default_rate, :description, :is_inactive, :name, :rate_required + + field :custom_field_list, CustomFieldList + field :rates_list, ExpenseCategoryRatesList + + record_refs :custom_form, :expense_acct + + attr_reader :internal_id + attr_accessor :external_id + attr_accessor :search_joins + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec + end + + + end + end +end diff --git a/lib/netsuite/records/expense_category_rate.rb b/lib/netsuite/records/expense_category_rate.rb new file mode 100644 index 000000000..7169029aa --- /dev/null +++ b/lib/netsuite/records/expense_category_rate.rb @@ -0,0 +1,28 @@ +module NetSuite + module Records + class ExpenseCategoryRate + include Support::Fields + include Support::RecordRefs + include Support::Records + include Namespaces::ListAcct + + fields :currency, :default_rate + + record_refs :subsidiary + + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + end + end +end diff --git a/lib/netsuite/records/expense_category_rates_list.rb b/lib/netsuite/records/expense_category_rates_list.rb new file mode 100644 index 000000000..fbcaf2e7e --- /dev/null +++ b/lib/netsuite/records/expense_category_rates_list.rb @@ -0,0 +1,9 @@ +module NetSuite + module Records + class ExpenseCategoryRatesList < Support::Sublist + include Namespaces::ListAcct + + sublist :expense_category, ExpenseCategoryRate + end + end +end From 3a3c747215ddd56a8ac36fa4753ef8a2ca4145b4 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 21 Apr 2020 09:29:04 -0500 Subject: [PATCH 11/62] [CLD-882-large-response] *Why: We were experiencing 500s when making certain requests to netsuite and needed to accomodate them *How: Increased the timeout when configuring the savon client [CLD-882] --- lib/netsuite/configuration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 20acf88df..3d395be08 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -323,7 +323,7 @@ def read_timeout(timeout = nil) if timeout self.read_timeout = timeout else - attributes[:read_timeout] ||= 60 + attributes[:read_timeout] ||= 120 end end From 811e421e8e63130217a08b14fddd6570f1878fb6 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 21 Apr 2020 15:05:55 -0500 Subject: [PATCH 12/62] pry --- lib/netsuite/actions/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index e5f8420dd..cb6915a75 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -30,7 +30,7 @@ def request(credentials={}) h end ) - + binding.pry NetSuite::Configuration .connection({ soap_header: preferences }, credentials) .call (@options.has_key?(:search_id)? :search_more_with_id : :search), :message => request_body From 3d0f98404b21cbf6f9acc2b3f6abf1d78c7854b1 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 21 Apr 2020 15:17:10 -0500 Subject: [PATCH 13/62] remove pry --- lib/netsuite/actions/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index cb6915a75..e5f8420dd 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -30,7 +30,7 @@ def request(credentials={}) h end ) - binding.pry + NetSuite::Configuration .connection({ soap_header: preferences }, credentials) .call (@options.has_key?(:search_id)? :search_more_with_id : :search), :message => request_body From 1a2045e684b9d83bbc3a6f05fac61885b227ce34 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 21 Apr 2020 15:49:05 -0500 Subject: [PATCH 14/62] pry --- lib/netsuite/support/search_result.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index 901c46edf..ef423a079 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -104,6 +104,7 @@ def results end def results_in_batches + binding.pry return if self.total_records.zero? while @response.body[:total_pages] != @response.body[:page_index] From e188a5d1bb4ef5d925fb0c634ec195ba6efe7727 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 21 Apr 2020 17:30:57 -0500 Subject: [PATCH 15/62] remove pry --- lib/netsuite/support/search_result.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index ef423a079..901c46edf 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -104,7 +104,6 @@ def results end def results_in_batches - binding.pry return if self.total_records.zero? while @response.body[:total_pages] != @response.body[:page_index] From e20132ac963c83d92051dcb01804ba2167fb2adc Mon Sep 17 00:00:00 2001 From: reginad1 Date: Sat, 2 May 2020 12:39:10 -0500 Subject: [PATCH 16/62] [CLD-878-support-later-version] *Why: The gem previously supported versions up to 2018 but later versions were not supported *How: Updated the netsuite savon config to set the wsdl and the endpoint level [CLD-878] --- lib/netsuite/configuration.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 3d395be08..83131de80 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -27,6 +27,7 @@ def connection(params={}, credentials={}) log_level: log_level, log: !silent, # turn off logging entirely if configured }.update(params)) + client.wsdl.endpoint = client.wsdl.endpoint.to_s.sub('//webservices.netsuite.com/', "//#{wsdl_domain}/") cache_wsdl(client) return client end From c36ebba286ac298756799c13851d0d20780d890d Mon Sep 17 00:00:00 2001 From: reginad1 Date: Mon, 11 May 2020 12:53:56 -0500 Subject: [PATCH 17/62] [CLD-917-vendor-credit-klass] *Why: Earlier versions of netsuite did not have the field class on the vendor credit expense line level or the vendor credit item line level *This addresses the need by: Added the class field to both the vendor credit expense record class and the vendor credit item record class. Added the methods to those classes required for setting the record references appropriately [CLD-917] --- lib/netsuite/records/vendor_credit_expense.rb | 23 ++++++++++++++++--- lib/netsuite/records/vendor_credit_item.rb | 23 ++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/netsuite/records/vendor_credit_expense.rb b/lib/netsuite/records/vendor_credit_expense.rb index 9e3635649..41929a551 100644 --- a/lib/netsuite/records/vendor_credit_expense.rb +++ b/lib/netsuite/records/vendor_credit_expense.rb @@ -15,10 +15,27 @@ class VendorCreditExpense field :custom_field_list, CustomFieldList - record_refs :account, :category, :customer, :department, :item, :location, :units, :tax_code + record_refs :account, :category, :customer, :department, :item, :location, :units, :tax_code, :klass - def initialize(attributes = {}) - initialize_from_attributes_hash(attributes) + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec end end diff --git a/lib/netsuite/records/vendor_credit_item.rb b/lib/netsuite/records/vendor_credit_item.rb index d50742829..df2bd5062 100644 --- a/lib/netsuite/records/vendor_credit_item.rb +++ b/lib/netsuite/records/vendor_credit_item.rb @@ -20,10 +20,27 @@ class VendorCreditItem field :custom_field_list, CustomFieldList field :options, CustomFieldList - record_refs :item, :units, :department, :customer, :location, :tax_code + record_refs :item, :units, :department, :customer, :location, :tax_code, :klass - def initialize(attributes = {}) - initialize_from_attributes_hash(attributes) + def initialize(attributes_or_record = {}) + case attributes_or_record + when Hash + initialize_from_attributes_hash(attributes_or_record) + when self.class + initialize_from_record(attributes_or_record) + end + end + + def initialize_from_record(record) + self.attributes = record.send(:attributes) + end + + def to_record + rec = super + if rec["#{record_namespace}:customFieldList"] + rec["#{record_namespace}:customFieldList!"] = rec.delete("#{record_namespace}:customFieldList") + end + rec end end From ce4b0fb176aba7ba5016243e6d0de07669cd6cb3 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Mon, 18 May 2020 14:20:54 -0500 Subject: [PATCH 18/62] [CLD-918] Added custom fields to Account class. --- lib/netsuite/records/account.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/netsuite/records/account.rb b/lib/netsuite/records/account.rb index b749f9596..13acb8743 100644 --- a/lib/netsuite/records/account.rb +++ b/lib/netsuite/records/account.rb @@ -16,6 +16,8 @@ class Account field :subsidiary_list, RecordRefList + field :custom_field_list, CustomFieldList + attr_reader :internal_id attr_accessor :external_id attr_accessor :search_joins From b3f65d15e4f679793211e459479de195262939d2 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Tue, 8 Sep 2020 14:52:40 -0500 Subject: [PATCH 19/62] [CLD-1157-expense-accounts-added] Why: *Expense accounts were not being added to response for specific item types This change addresses the need by: *added the record reference expense account Ticket * [CLD-1157] --- lib/netsuite/records/gift_certificate_item.rb | 2 +- lib/netsuite/records/lot_numbered_assembly_item.rb | 2 +- lib/netsuite/records/non_inventory_purchase_item.rb | 2 +- lib/netsuite/records/non_inventory_resale_item.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/netsuite/records/gift_certificate_item.rb b/lib/netsuite/records/gift_certificate_item.rb index beb52f11b..cffa66a64 100644 --- a/lib/netsuite/records/gift_certificate_item.rb +++ b/lib/netsuite/records/gift_certificate_item.rb @@ -64,7 +64,7 @@ class GiftCertificateItem field :custom_field_list, CustomFieldList record_refs :klass, :custom_form, :department, :income_account, - :issue_product, :location, :parent, :sales_tax_code, :tax_schedule + :issue_product, :liability_account, :location, :parent, :sales_tax_code, :tax_schedule attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/lot_numbered_assembly_item.rb b/lib/netsuite/records/lot_numbered_assembly_item.rb index 67c7d07f3..4623a404b 100644 --- a/lib/netsuite/records/lot_numbered_assembly_item.rb +++ b/lib/netsuite/records/lot_numbered_assembly_item.rb @@ -34,7 +34,7 @@ class LotNumberedAssemblyItem record_refs :alternate_demand_source_item, :asset_account, :bill_exch_rate_variance_acct, :bill_price_variance_acct, :bill_qty_variance_acct, :billing_schedule, :cogs_account, :cost_category, :custom_form, :deferred_revenue_account, - :demand_source, :department, :expense_account, :gain_loss_account, :income_account, :issue_product, :klass, :location, + :demand_source, :department, :dropship_expense_account, :gain_loss_account, :income_account, :issue_product, :klass, :location, :parent, :preferred_location, :pricing_group, :purchase_price_variance_acct, :purchase_tax_code, :purchase_unit, :quantity_pricing_schedule, :rev_rec_schedule, :sale_unit, :sales_tax_code, :ship_package, :soft_descriptor, :stock_unit, :store_display_image, :store_display_thumbnail, :store_item_template, :supply_lot_sizing_method, diff --git a/lib/netsuite/records/non_inventory_purchase_item.rb b/lib/netsuite/records/non_inventory_purchase_item.rb index f321910aa..dcd76c8be 100644 --- a/lib/netsuite/records/non_inventory_purchase_item.rb +++ b/lib/netsuite/records/non_inventory_purchase_item.rb @@ -25,7 +25,7 @@ class NonInventoryPurchaseItem :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units - record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :income_account, + record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :expense_account, :income_account, :issue_product, :item_options_list, :klass, :location, :parent, :pricing_group, :purchase_tax_code, :quantity_pricing_schedule, :rev_rec_schedule, :sale_unit, :sales_tax_code, :ship_package, :store_display_image, :store_display_thumbnail, :store_item_template, :tax_schedule, :units_type diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index 0628c8c6a..cbfab0f9e 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -25,7 +25,7 @@ class NonInventoryResaleItem :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units - record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :income_account, + record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :expense_account, :income_account, :issue_product, :item_options_list, :klass, :location, :parent, :pricing_group, :purchase_tax_code, :quantity_pricing_schedule, :rev_rec_schedule, :sale_unit, :sales_tax_code, :ship_package, :store_display_image, :store_display_thumbnail, :store_item_template, :tax_schedule, :units_type, :expense_account From e27f85887d89fab42a1d96f1edc5e0004b721792 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Thu, 24 Sep 2020 09:21:31 -0500 Subject: [PATCH 20/62] [CLD-1220-service-purchase-item-endpoint] Why: *Service Purchase Item support was not available in gem and endpoint is being used in a workflow that we are hoping to switch to the ruby connector This change addresses the need by: *Added service purchase item record support Ticket * [CLD-1220] --- lib/netsuite.rb | 1 + lib/netsuite/records/service_purchase_item.rb | 34 +++++++++++++++++++ lib/netsuite/utilities.rb | 1 + 3 files changed, 36 insertions(+) create mode 100644 lib/netsuite/records/service_purchase_item.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index f409ae902..987e2a3dc 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -264,6 +264,7 @@ module Records autoload :SalesOrderItemList, 'netsuite/records/sales_order_item_list' autoload :SalesRole, 'netsuite/records/sales_role' autoload :SalesTaxItem, 'netsuite/records/sales_tax_item' + autoload :ServicePurchaseItem, 'netsuite/records/service_purchase_item' autoload :ServiceResaleItem, 'netsuite/records/service_resale_item' autoload :ServiceSaleItem, 'netsuite/records/service_sale_item' autoload :SerializedAssemblyItem, 'netsuite/records/serialized_assembly_item' diff --git a/lib/netsuite/records/service_purchase_item.rb b/lib/netsuite/records/service_purchase_item.rb new file mode 100644 index 000000000..fab343de1 --- /dev/null +++ b/lib/netsuite/records/service_purchase_item.rb @@ -0,0 +1,34 @@ +module NetSuite + module Records + class ServicePurchaseItem + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::ListAcct + + actions :get, :get_list, :add, :delete, :search, :upsert + + fields :amortization_period, :available_to_partners, :cost, :cost_units, :created_date, :currency, :display_name, :generate_accrurals, :include_children, :is_fulfillable, :is_inactive, :is_taxable, :item_id, :last_modified_date, :manufacturing_charge_item, :purchase_description, :purchase_order_amount, :purchase_order_quantity, :purchase_order_quantity_diff, :receipt_amount, :receipt_quantity, :receipt_quantity_diff, :residual, :upc_code, :vendor_name + + record_refs :klass, :cost_category, :custom_form, :department, :expense_account, :issue_product, :location, :parent, :purchase_tax_code, :sales_tax_code, :tax_schedule, :units_type + + field :custom_field_list, CustomFieldList + field :subsidiary_list, RecordRefList + + + attr_reader :internal_id + attr_accessor :external_id + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + + def self.search_class_name + "Item" + end + end + end +end diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index c0b0f2d91..9fa3b6b65 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -169,6 +169,7 @@ def get_item(ns_item_internal_id, opts = {}) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::NonInventoryResaleItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::DiscountItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::OtherChargeSaleItem, ns_item_internal_id, opts) + ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::ServicePurchaseItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::ServiceSaleItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::GiftCertificateItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::KitItem, ns_item_internal_id, opts) From c3145a6b6efdebee65bdf6910b70e4e1fc8d0e44 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Tue, 6 Oct 2020 13:59:33 -0500 Subject: [PATCH 21/62] CLD-1154 Improve error messaging Why: * Current implementation often results in 500 Internal Server Errors with no additional information This change addresses the need by: * Passing NetSuite error messages through to connector in the case of RecordNotFound Ticket * [CLD-1154] --- lib/netsuite/actions/get.rb | 13 ++++++++++++- lib/netsuite/actions/get_select_value.rb | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/actions/get.rb b/lib/netsuite/actions/get.rb index 6674ef0c9..f1e32ad50 100644 --- a/lib/netsuite/actions/get.rb +++ b/lib/netsuite/actions/get.rb @@ -56,6 +56,17 @@ def response_hash @response_hash = @response.body[:get_response][:read_response] end + def response_errors + if response_hash[:status] && response_hash[:status][:status_detail] + @response_errors ||= errors + end + end + + def errors + error_obj = response_hash.dig(:status,:status_detail) + OpenStruct.new(status: 404, status_detail: error_obj) + end + module Support def self.included(base) @@ -71,7 +82,7 @@ def get(options = {}, credentials = {}) if response.success? new(response.body) else - raise RecordNotFound, "#{self} with OPTIONS=#{options.inspect} could not be found" + raise RecordNotFound, "#{self} with OPTIONS=#{options.inspect} could not be found, NetSuite message: #{response.errors.status_detail[:message]}" end end diff --git a/lib/netsuite/actions/get_select_value.rb b/lib/netsuite/actions/get_select_value.rb index f4938f7b2..2e20960f5 100644 --- a/lib/netsuite/actions/get_select_value.rb +++ b/lib/netsuite/actions/get_select_value.rb @@ -47,7 +47,6 @@ def get_select_value(options = {}, credentials={}) } response = NetSuite::Actions::GetSelectValue.call([self, message], credentials) - if response.success? new(response.body) else From a89db03fd47dd0d50c465255d5711d9ac160b3ee Mon Sep 17 00:00:00 2001 From: reginad1 Date: Wed, 28 Oct 2020 13:41:53 -0500 Subject: [PATCH 22/62] [CLD-1276-fix-typo] Why: *There was a typo in the expense report record file that had tran_id as train_id making it so that variable could not be passed in or returned via the connector This change addresses the need by: *resolved the typo Ticket * [CLD-1276] --- lib/netsuite/actions/search.rb | 1 - lib/netsuite/records/expense_report.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index e5f8420dd..e39f5b98c 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -30,7 +30,6 @@ def request(credentials={}) h end ) - NetSuite::Configuration .connection({ soap_header: preferences }, credentials) .call (@options.has_key?(:search_id)? :search_more_with_id : :search), :message => request_body diff --git a/lib/netsuite/records/expense_report.rb b/lib/netsuite/records/expense_report.rb index 8cf7b5619..76724693b 100644 --- a/lib/netsuite/records/expense_report.rb +++ b/lib/netsuite/records/expense_report.rb @@ -9,7 +9,7 @@ class ExpenseReport actions :add, :get, :search, :update - fields :accounting_approval, :advance, :amount, :complete, :created_date, :due_date, :last_modified_date, :memo, :status, :supervisor_approval, :tax1_amt, :tax2_amt, :total, :tran_date, :train_id, :use_multi_currency + fields :accounting_approval, :advance, :amount, :complete, :created_date, :due_date, :last_modified_date, :memo, :status, :supervisor_approval, :tax1_amt, :tax2_amt, :total, :tran_date, :tran_id, :use_multi_currency # todo # field :accounting_book_detail_list, AccountingBookDetailList From 4251842aabcea848f08a03260dd096be71aa2135 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Thu, 19 Nov 2020 12:04:45 -0600 Subject: [PATCH 23/62] [CLD-1324-update-global-config] Why: *needed to update the way wsdl is set when using new auth method This change addresses the need by: *updated the configuration to utilize the credentials hash Ticket * [CLD-1324] --- lib/netsuite/actions/add.rb | 2 +- lib/netsuite/actions/search.rb | 1 + lib/netsuite/configuration.rb | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/actions/add.rb b/lib/netsuite/actions/add.rb index 60fa8198f..6405aceaf 100644 --- a/lib/netsuite/actions/add.rb +++ b/lib/netsuite/actions/add.rb @@ -74,7 +74,7 @@ module Support def add(credentials={}) response = NetSuite::Actions::Add.call([self], credentials) @errors = response.errors - + if response.success? @internal_id = response.body.dig(:@internal_id) unless response.body.class == Nori::StringIOFile true diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index e39f5b98c..e5f8420dd 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -30,6 +30,7 @@ def request(credentials={}) h end ) + NetSuite::Configuration .connection({ soap_header: preferences }, credentials) .call (@options.has_key?(:search_id)? :search_more_with_id : :search), :message => request_body diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 83131de80..76d7072a8 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -15,6 +15,8 @@ def attributes end def connection(params={}, credentials={}) + check_credentials(credentials) + client = Savon.client({ wsdl: cached_wsdl || wsdl, read_timeout: read_timeout, @@ -32,6 +34,23 @@ def connection(params={}, credentials={}) return client end + def check_credentials(creds) + if !creds.blank? + set_attributes(creds) + end + end + + def set_attributes(credentials) + account(credentials[:account]) + consumer_key(credentials[:consumer_key]) + consumer_secret(credentials[:consumer_secret]) + token_id(credentials[:token_id]) + token_secret(credentials[:token_secret]) + api_version(credentials[:api_version]) + wsdl_domain(credentials[:wsdl_domain]) + soap_header(credentials[:soap_header]) + end + def filters(list = nil) if list self.filters = list From d410beeae1ff74adea3842581f1cfdf8bdcfb582 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Thu, 17 Dec 2020 12:50:26 -0600 Subject: [PATCH 24/62] [L3-39-add-accounting_period_fields] --- lib/netsuite/records/accounting_period.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/accounting_period.rb b/lib/netsuite/records/accounting_period.rb index 5dd04b346..afae5305f 100644 --- a/lib/netsuite/records/accounting_period.rb +++ b/lib/netsuite/records/accounting_period.rb @@ -8,7 +8,7 @@ class AccountingPeriod actions :get, :get_list, :add, :delete, :upsert, :search - fields :allow_non_gl_changes, :end_date, :is_adjust, :is_quarter, :is_year, :period_name, :start_date + fields :allow_non_gl_changes, :end_date, :is_adjust, :is_quarter, :is_year, :period_name, :start_date, :all_locked, :ap_locked, :ar_locked, :closed, :closed_on_date, :payroll_locked record_refs :parent From cdc3e506ff3aaf279a2c0768bfd06ab83996e354 Mon Sep 17 00:00:00 2001 From: reginad1 Date: Fri, 22 Jan 2021 11:49:33 -0600 Subject: [PATCH 25/62] update readme to include Cloudsnap additions --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index fbddf116e..298e85f25 100644 --- a/README.md +++ b/README.md @@ -591,3 +591,23 @@ states.to_array.first[:get_all_response][:get_all_result][:record_list][:record] # About SuiteSync [SuiteSync, the Stripe-NetSuite integration](http://suitesync.io) uses this gem and funds the majority of it's development and maintenance. + + + + +# Cloudsnap Additions + +I generally refer to the Netsuite Schema Browser as a source of truth over the actions, records, and fields that you see in this gem. That documentation can be found here: https://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2018_1/schema/record/account.html?mode=package + +**One note is to be mindful of the version that you are looking at in the schema browser and the version that you are using when you configure the netsuite credentials. + +### Actions +attach.rb--> lib/netsuite/actions/attach.rb +Based on the Netsuite Schema documentation, we added in the attach action functionality. This is primarily used to attach records considered File Cabinate + + +### Records +If you see the record in the netsuite schema browser, you can easily add it to the records in this gem. Use the fields and sub lists mentioned in the Netsuite schema browser to build out the record file following the same format as the other record files. + +### Other Cloudsnap Changes +We made a few changes to the configuration.rb file. The check credentials method and set attributes methods were added to support the updated way of passing credentials. In the connection method, we also added the ability to set the wsdl and the endpoint level for the Savon client that is configured. This was required to connect to Netsuite api versions 2020+ From 67a0215a7be879cc182be2b8598dfe8481a57752 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Fri, 5 Mar 2021 15:39:57 -0600 Subject: [PATCH 26/62] fix multiselect bug --- lib/netsuite/records/custom_field_list.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/records/custom_field_list.rb b/lib/netsuite/records/custom_field_list.rb index 81a7cc555..8e6150956 100644 --- a/lib/netsuite/records/custom_field_list.rb +++ b/lib/netsuite/records/custom_field_list.rb @@ -113,12 +113,15 @@ def extract_custom_field(custom_field_data) if type == "platformCore:SelectCustomFieldRef" attrs[:value] = CustomRecordRef.new(custom_field_data[:value]) elsif type == 'platformCore:MultiSelectCustomFieldRef' - attrs[:value] = custom_field_data[:value].map do |entry| - CustomRecordRef.new(entry) + # if only one value of multiselect is selected it will be a hash, not an array + if attrs[:value].is_a?(Array) + attrs[:value] = custom_field_data[:value].map { |entry| CustomRecordRef.new(entry) } + else + attrs[:value] = CustomRecordRef.new(custom_field_data[:value]) end end - custom_fields << CustomField.new(attrs) + end end From 4f0cc2cb5dce12c6255441f19ebd462e22ff0db0 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Wed, 7 Apr 2021 16:09:03 -0500 Subject: [PATCH 27/62] added employee address records --- lib/netsuite.rb | 2 + lib/netsuite/records/employee.rb | 1 + lib/netsuite/records/employee_addressbook.rb | 65 +++++++++++++++++++ .../records/employee_addressbook_list.rb | 12 ++++ 4 files changed, 80 insertions(+) create mode 100644 lib/netsuite/records/employee_addressbook.rb create mode 100644 lib/netsuite/records/employee_addressbook_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 987e2a3dc..5d8c7a785 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -158,6 +158,8 @@ module Records autoload :DescriptionItem, 'netsuite/records/description_item' autoload :DiscountItem, 'netsuite/records/discount_item' autoload :Duration, 'netsuite/records/duration' + autoload :EmployeeAddressbookList, 'netsuite/records/employee_addressbook_list' + autoload :EmployeeAddressbook, 'netsuite/records/employee_addressbook' autoload :Employee, 'netsuite/records/employee' autoload :EntityCustomField, 'netsuite/records/entity_custom_field' autoload :ExpenseCategory, 'netsuite/records/expense_category' diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index 5b59cbc71..10510a499 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -22,6 +22,7 @@ class Employee record_refs :currency, :department, :location, :subsidiary, :employee_type, :employee_status, :supervisor field :custom_field_list, CustomFieldList + field :addressbook_list, EmployeeAddressbookList field :roles_list, RoleList attr_reader :internal_id diff --git a/lib/netsuite/records/employee_addressbook.rb b/lib/netsuite/records/employee_addressbook.rb new file mode 100644 index 000000000..1baa25feb --- /dev/null +++ b/lib/netsuite/records/employee_addressbook.rb @@ -0,0 +1,65 @@ +module NetSuite + module Records + class EmployeeAddressbook + include Support::Fields + include Support::Records + include Namespaces::ListEmp + + # address implementation changed + # https://github.com/NetSweet/netsuite/pull/213 + + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2015_1/schema/other/customeraddressbook.html?mode=package + + fields :default_shipping, :default_billing, :is_residential, :label, :internal_id + + # NOTE API < 2014_2 + fields :attention, :addressee, :phone, :addr1, :addr2, :addr3, :city, :zip, :override, :state + field :country, NetSuite::Support::Country + read_only_fields :addr_text + + # NOTE API >= 2014_2 + field :addressbook_address, NetSuite::Records::Address + + def initialize(attributes_or_record = {}) + case attributes_or_record + when self.class + initialize_from_record(attributes_or_record) + when Hash + attributes_or_record = attributes_or_record[:addressbook] if attributes_or_record[:addressbook] + initialize_from_attributes_hash(attributes_or_record) + end + end + + def initialize_from_record(obj) + if NetSuite::Configuration.api_version < "2014_2" + self.default_shipping = obj.default_shipping + self.default_billing = obj.default_billing + self.is_residential = obj.is_residential + self.label = obj.label + self.attention = obj.attention + self.addressee = obj.addressee + self.phone = obj.phone + self.addr1 = obj.addr1 + self.addr2 = obj.addr2 + self.addr3 = obj.addr3 + self.city = obj.city + self.zip = obj.zip + self.country = obj.country + self.addr_text = obj.addr_text + self.override = obj.override + self.state = obj.state + self.internal_id = obj.internal_id + else + self.addressbook_address = obj.addressbook_address + self.default_billing = obj.default_billing + self.default_shipping = obj.default_shipping + self.internal_id = obj.internal_id + self.is_residential = obj.is_residential + self.label = obj.label + end + end + + end + end + end + \ No newline at end of file diff --git a/lib/netsuite/records/employee_addressbook_list.rb b/lib/netsuite/records/employee_addressbook_list.rb new file mode 100644 index 000000000..2ef2f3036 --- /dev/null +++ b/lib/netsuite/records/employee_addressbook_list.rb @@ -0,0 +1,12 @@ +module NetSuite + module Records + class EmployeeAddressbookList < Support::Sublist + include Namespaces::ListEmp + + sublist :addressbook, EmployeeAddressbook + + alias :addressbooks :addressbook + end + end + end + \ No newline at end of file From 1ac62f8a974a841b5e4d0308e8288ac96e28c27e Mon Sep 17 00:00:00 2001 From: Jimin Huh Date: Mon, 12 Apr 2021 20:47:02 -0500 Subject: [PATCH 28/62] added default address field on employee class --- lib/netsuite/records/employee.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index 10510a499..e544a6168 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -17,7 +17,7 @@ class Employee :bill_pay, :comments, :date_created, :direct_deposit, :entity_id, :password, :password2, :expense_limit, :fax, :is_job_resource, :job_description, :labor_cost, :last_modified_date, :mobile_phone, :pay_frequency, :phonetic_name, :purchase_order_approval_limit, :purchase_order_approver, :purchase_order_limit, :release_date, - :resident_status, :salutation, :social_security_number, :visa_exp_date, :visa_type + :resident_status, :salutation, :social_security_number, :visa_exp_date, :visa_type, :default_address record_refs :currency, :department, :location, :subsidiary, :employee_type, :employee_status, :supervisor From 6227de512cf0278c4cb123aeaccca082e31a4269 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Wed, 23 Jun 2021 12:08:32 -0500 Subject: [PATCH 29/62] Initial commit WIP --- lib/netsuite.rb | 2 + lib/netsuite/records/employee.rb | 7 + lib/netsuite/records/name.rb | 23 +++ lib/netsuite/records/null_field_list.rb | 207 ++++++++++++++++++++++++ lib/netsuite/support/attributes.rb | 11 +- 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 lib/netsuite/records/name.rb create mode 100644 lib/netsuite/records/null_field_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 5d8c7a785..c5e60390a 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -229,6 +229,8 @@ module Records autoload :NonInventoryResaleItem, 'netsuite/records/non_inventory_resale_item' autoload :Note, 'netsuite/records/note' autoload :NoteType, 'netsuite/records/note_type' + autoload :Name, 'netsuite/records/name' + autoload :NullFieldList, 'netsuite/records/null_field_list' autoload :Opportunity, 'netsuite/records/opportunity' autoload :OpportunityItem, 'netsuite/records/opportunity_item' autoload :OpportunityItemList, 'netsuite/records/opportunity_item_list' diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index e544a6168..092376ce2 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -24,6 +24,7 @@ class Employee field :custom_field_list, CustomFieldList field :addressbook_list, EmployeeAddressbookList field :roles_list, RoleList + field :null_field_list, NullFieldList attr_reader :internal_id attr_accessor :external_id @@ -32,12 +33,18 @@ def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) initialize_from_attributes_hash(attributes) + # @name = [] end def self.search_class_name 'Employee' end + # def name=(name) + # binding.pry + # @null_field_list << name + # end + end end end diff --git a/lib/netsuite/records/name.rb b/lib/netsuite/records/name.rb new file mode 100644 index 000000000..0cc9222ac --- /dev/null +++ b/lib/netsuite/records/name.rb @@ -0,0 +1,23 @@ +module NetSuite + module Records + class Name + include Support::Fields + include Support::Records + #include Namespaces::PlatformCore + + attr_accessor :attributes + + def initialize(attributes = {}) + binding.pry + @value = attributes.delete(:value) || attributes.delete(:@value) + @type = attributes.delete(:type) || attributes.delete(:"@xsi:type") + self.attributes = attributes + end + + def value + attributes[:value] + end + + end + end +end diff --git a/lib/netsuite/records/null_field_list.rb b/lib/netsuite/records/null_field_list.rb new file mode 100644 index 000000000..a60cde405 --- /dev/null +++ b/lib/netsuite/records/null_field_list.rb @@ -0,0 +1,207 @@ + +module NetSuite + module Records + class NullFieldList #< Support::Sublist + #include Support::Records + include Support::Fields + include Namespaces::PlatformCore + + field :name, Name + + #alias :names :name + + #fields :name + + def initialize(attributes={}) + binding.pry + @name = attributes#[:name] + end + + def name + @name + end + + end + end +end +# module NetSuite +# module Records +# class NullFieldList +# include Support::Fields +# include Namespaces::PlatformCore + +# field :name + +# def initialize(attributes = {}) +# binding.pry +# case attributes[:name] +# when Hash +# extract_name(attributes[:name]) +# when Array +# attributes[:name].each { |name| extract_name(name) } +# end + +# @names_assoc = Hash.new +# names.each do |name| + +# if reference_id = name.send(reference_id_type) +# @names_assoc[reference_id.to_sym] = name +# end +# end +# end + +# def names +# @names ||= [] +# end + +# def delete_name(field) +# names.delete_if do |c| +# c.send(reference_id_type) && +# c.send(reference_id_type).to_sym == field +# end + +# @names_assoc.delete(field) +# end + +# def method_missing(sym, *args, &block) +# # read null field if already set +# if @names_assoc.include?(sym) +# return @names_assoc[sym] +# end + +# # write null field +# if sym.to_s.end_with?('=') +# field_name = sym.to_s[0..-2] +# delete_name(field_name.to_sym) +# return create_name(field_name, args.first) +# end + +# super(sym, *args, &block) +# end + +# def respond_to?(sym, include_private = false) +# return true if @names_assoc.include?(sym) +# super +# end + +# def to_record +# binding.pry +# { +# "#{record_namespace}:name" => names.map do |name| +# # if name.value.respond_to?(:to_record) +# # name_value = name.value.to_record +# # elsif name.value.is_a?(Array) +# # name_value = name.value.map(&:to_record) +# # else +# name_value = name.value.to_s +# # end +# binding.pry +# base = { +# "platformCore:value" => name_value, +# '@xsi:type' => name.type +# } + +# # TODO this is broken in > 2013_1; need to conditionally change the synax here +# # if NetSuite::Configuration.api_version < "2013_2" + +# # if name.internal_id +# # base['@internalId'] = name.internal_id +# # end + +# # binding.pry +# # if name.script_id +# # base['@scriptId'] = name.script_id +# # end + +# base +# end +# } +# end + +# private + +# def reference_id_type +# @reference_id_type ||= Configuration.api_version >= '2013_2' ? :script_id : :internal_id +# end + +# def extract_name(name_data) +# binding.pry +# # if name_data.kind_of?(Name) +# # binding.pry +# names << name_data +# # else +# # binding.pry +# # attrs = name_data.clone +# # type = (name_data[:"@xsi:type"] || name_data[:type]) + +# # if type == "platformCore:SelectNullFieldRef" +# # attrs[:value] = NullRecordRef.new(name_data[:value]) +# # elsif type == 'platformCore:MultiSelectNullFieldRef' +# # # if only one value of multiselect is selected it will be a hash, not an array +# # if attrs[:value].is_a?(Array) +# # attrs[:value] = name_data[:value].map { |entry| NullRecordRef.new(entry) } +# # else +# # attrs[:value] = NullRecordRef.new(name_data[:value]) +# # end +# # end +# # names << Name.new(attrs) + +# #end +# end + +# def create_name(reference_id, field_value) +# # all null fields need types; infer type based on class sniffing +# field_type = case +# when field_value.is_a?(Array) +# 'MultiSelectNullFieldRef' +# when field_value.is_a?(Hash), +# field_value.is_a?(NetSuite::Records::NullRecordRef) +# 'SelectNullFieldRef' +# when field_value.is_a?(DateTime), +# field_value.is_a?(Time), +# field_value.is_a?(Date) +# 'DateNullFieldRef' +# when field_value.is_a?(FalseClass), +# field_value.is_a?(TrueClass) +# 'BooleanNullFieldRef' +# else +# 'StringNullFieldRef' +# end + +# # TODO seems like DateTime doesn't need the iso8601 call +# # not sure if this is specific to my env though + +# name_value = case +# when field_value.is_a?(Hash) +# NullRecordRef.new(field_value) +# when field_value.is_a?(Date) +# field_value.to_datetime.iso8601 +# when field_value.is_a?(Time) +# field_value.iso8601 +# when field_value.is_a?(Array) +# # sniff the first element of the array; if an int or string then assume internalId +# # and create record refs pointing to the given IDs + +# if !field_value.empty? && (field_value.first.is_a?(String) || field_value.first.kind_of?(Integer)) +# field_value.map do |v| +# NetSuite::Records::NullRecordRef.new(internal_id: v) +# end +# else +# field_value +# end +# else +# field_value +# end + +# name = Name.new( +# reference_id_type => reference_id, +# :value => name_value, +# :type => "#{record_namespace}:#{field_type}" +# ) + +# names << name +# @names_assoc[reference_id.to_sym] = name +# end +# end +# end +# end diff --git a/lib/netsuite/support/attributes.rb b/lib/netsuite/support/attributes.rb index 6d1e29825..1bc14d5b3 100644 --- a/lib/netsuite/support/attributes.rb +++ b/lib/netsuite/support/attributes.rb @@ -12,7 +12,16 @@ def attributes=(attributes) def initialize_from_attributes_hash(attributes = {}) attributes.select { |k,v| self.class.fields.include?(k) }.each do |k,v| - send("#{k}=", v) + # if k.to_s == "null_field_list" # new + # v.each do |name| + # binding.pry + # send("name=", name) + # end + # else + #send("#{k}=", v) + binding.pry + send("#{k}=", k.to_s == "null_field_list" ? v.name : v) + # end end self.klass = attributes[:class] if attributes[:class] end From d8ff8800515122b6e2a36867c241d2929566f228 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Wed, 30 Jun 2021 15:06:57 -0500 Subject: [PATCH 30/62] removed commented fields, using NullFieldList class --- lib/netsuite/records/employee.rb | 6 - lib/netsuite/records/null_field_list.rb | 200 +----------------------- lib/netsuite/support/attributes.rb | 11 +- 3 files changed, 5 insertions(+), 212 deletions(-) diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index 092376ce2..28b97bc9a 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -33,18 +33,12 @@ def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) initialize_from_attributes_hash(attributes) - # @name = [] end def self.search_class_name 'Employee' end - # def name=(name) - # binding.pry - # @null_field_list << name - # end - end end end diff --git a/lib/netsuite/records/null_field_list.rb b/lib/netsuite/records/null_field_list.rb index a60cde405..5984357d5 100644 --- a/lib/netsuite/records/null_field_list.rb +++ b/lib/netsuite/records/null_field_list.rb @@ -1,207 +1,15 @@ - module NetSuite module Records - class NullFieldList #< Support::Sublist - #include Support::Records + class NullFieldList include Support::Fields - include Namespaces::PlatformCore - - field :name, Name + include Support::Records - #alias :names :name - - #fields :name + fields :name def initialize(attributes={}) - binding.pry - @name = attributes#[:name] - end - - def name - @name + initialize_from_attributes_hash(attributes) end end end end -# module NetSuite -# module Records -# class NullFieldList -# include Support::Fields -# include Namespaces::PlatformCore - -# field :name - -# def initialize(attributes = {}) -# binding.pry -# case attributes[:name] -# when Hash -# extract_name(attributes[:name]) -# when Array -# attributes[:name].each { |name| extract_name(name) } -# end - -# @names_assoc = Hash.new -# names.each do |name| - -# if reference_id = name.send(reference_id_type) -# @names_assoc[reference_id.to_sym] = name -# end -# end -# end - -# def names -# @names ||= [] -# end - -# def delete_name(field) -# names.delete_if do |c| -# c.send(reference_id_type) && -# c.send(reference_id_type).to_sym == field -# end - -# @names_assoc.delete(field) -# end - -# def method_missing(sym, *args, &block) -# # read null field if already set -# if @names_assoc.include?(sym) -# return @names_assoc[sym] -# end - -# # write null field -# if sym.to_s.end_with?('=') -# field_name = sym.to_s[0..-2] -# delete_name(field_name.to_sym) -# return create_name(field_name, args.first) -# end - -# super(sym, *args, &block) -# end - -# def respond_to?(sym, include_private = false) -# return true if @names_assoc.include?(sym) -# super -# end - -# def to_record -# binding.pry -# { -# "#{record_namespace}:name" => names.map do |name| -# # if name.value.respond_to?(:to_record) -# # name_value = name.value.to_record -# # elsif name.value.is_a?(Array) -# # name_value = name.value.map(&:to_record) -# # else -# name_value = name.value.to_s -# # end -# binding.pry -# base = { -# "platformCore:value" => name_value, -# '@xsi:type' => name.type -# } - -# # TODO this is broken in > 2013_1; need to conditionally change the synax here -# # if NetSuite::Configuration.api_version < "2013_2" - -# # if name.internal_id -# # base['@internalId'] = name.internal_id -# # end - -# # binding.pry -# # if name.script_id -# # base['@scriptId'] = name.script_id -# # end - -# base -# end -# } -# end - -# private - -# def reference_id_type -# @reference_id_type ||= Configuration.api_version >= '2013_2' ? :script_id : :internal_id -# end - -# def extract_name(name_data) -# binding.pry -# # if name_data.kind_of?(Name) -# # binding.pry -# names << name_data -# # else -# # binding.pry -# # attrs = name_data.clone -# # type = (name_data[:"@xsi:type"] || name_data[:type]) - -# # if type == "platformCore:SelectNullFieldRef" -# # attrs[:value] = NullRecordRef.new(name_data[:value]) -# # elsif type == 'platformCore:MultiSelectNullFieldRef' -# # # if only one value of multiselect is selected it will be a hash, not an array -# # if attrs[:value].is_a?(Array) -# # attrs[:value] = name_data[:value].map { |entry| NullRecordRef.new(entry) } -# # else -# # attrs[:value] = NullRecordRef.new(name_data[:value]) -# # end -# # end -# # names << Name.new(attrs) - -# #end -# end - -# def create_name(reference_id, field_value) -# # all null fields need types; infer type based on class sniffing -# field_type = case -# when field_value.is_a?(Array) -# 'MultiSelectNullFieldRef' -# when field_value.is_a?(Hash), -# field_value.is_a?(NetSuite::Records::NullRecordRef) -# 'SelectNullFieldRef' -# when field_value.is_a?(DateTime), -# field_value.is_a?(Time), -# field_value.is_a?(Date) -# 'DateNullFieldRef' -# when field_value.is_a?(FalseClass), -# field_value.is_a?(TrueClass) -# 'BooleanNullFieldRef' -# else -# 'StringNullFieldRef' -# end - -# # TODO seems like DateTime doesn't need the iso8601 call -# # not sure if this is specific to my env though - -# name_value = case -# when field_value.is_a?(Hash) -# NullRecordRef.new(field_value) -# when field_value.is_a?(Date) -# field_value.to_datetime.iso8601 -# when field_value.is_a?(Time) -# field_value.iso8601 -# when field_value.is_a?(Array) -# # sniff the first element of the array; if an int or string then assume internalId -# # and create record refs pointing to the given IDs - -# if !field_value.empty? && (field_value.first.is_a?(String) || field_value.first.kind_of?(Integer)) -# field_value.map do |v| -# NetSuite::Records::NullRecordRef.new(internal_id: v) -# end -# else -# field_value -# end -# else -# field_value -# end - -# name = Name.new( -# reference_id_type => reference_id, -# :value => name_value, -# :type => "#{record_namespace}:#{field_type}" -# ) - -# names << name -# @names_assoc[reference_id.to_sym] = name -# end -# end -# end -# end diff --git a/lib/netsuite/support/attributes.rb b/lib/netsuite/support/attributes.rb index 1bc14d5b3..6d1e29825 100644 --- a/lib/netsuite/support/attributes.rb +++ b/lib/netsuite/support/attributes.rb @@ -12,16 +12,7 @@ def attributes=(attributes) def initialize_from_attributes_hash(attributes = {}) attributes.select { |k,v| self.class.fields.include?(k) }.each do |k,v| - # if k.to_s == "null_field_list" # new - # v.each do |name| - # binding.pry - # send("name=", name) - # end - # else - #send("#{k}=", v) - binding.pry - send("#{k}=", k.to_s == "null_field_list" ? v.name : v) - # end + send("#{k}=", v) end self.klass = attributes[:class] if attributes[:class] end From bb7f976e4d9974837164f249886413dc44bef2ae Mon Sep 17 00:00:00 2001 From: Mike Good Date: Tue, 13 Jul 2021 10:58:19 -0500 Subject: [PATCH 31/62] Why: * netsuite gem lacked support for null_field_list This change addresses the need by: * Added null_field_lest record * added nullFieldList fields to applicable objects * Added check for nullFieldList element and code to swap namespace Ticket * [CLD-1835] --- lib/netsuite.rb | 1 - lib/netsuite/actions/update.rb | 6 +++++ lib/netsuite/records/contact.rb | 1 + lib/netsuite/records/credit_memo.rb | 1 + lib/netsuite/records/customer.rb | 1 + lib/netsuite/records/customer_payment.rb | 1 + lib/netsuite/records/expense_report.rb | 2 +- lib/netsuite/records/inventory_adjustment.rb | 1 + lib/netsuite/records/invoice.rb | 1 + lib/netsuite/records/item_fulfillment.rb | 1 + lib/netsuite/records/item_receipt.rb | 1 + lib/netsuite/records/journal_entry.rb | 1 + lib/netsuite/records/name.rb | 23 -------------------- lib/netsuite/records/null_field_list.rb | 3 +++ lib/netsuite/records/purchase_order.rb | 1 + lib/netsuite/records/sales_order.rb | 1 + lib/netsuite/records/time_bill.rb | 1 + lib/netsuite/records/transfer_order.rb | 1 + lib/netsuite/records/vendor.rb | 1 + lib/netsuite/records/vendor_bill.rb | 1 + lib/netsuite/records/vendor_credit.rb | 1 + lib/netsuite/records/vendor_payment.rb | 1 + 22 files changed, 27 insertions(+), 25 deletions(-) delete mode 100644 lib/netsuite/records/name.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index c5e60390a..4da8aef85 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -229,7 +229,6 @@ module Records autoload :NonInventoryResaleItem, 'netsuite/records/non_inventory_resale_item' autoload :Note, 'netsuite/records/note' autoload :NoteType, 'netsuite/records/note_type' - autoload :Name, 'netsuite/records/name' autoload :NullFieldList, 'netsuite/records/null_field_list' autoload :Opportunity, 'netsuite/records/opportunity' autoload :OpportunityItem, 'netsuite/records/opportunity_item' diff --git a/lib/netsuite/actions/update.rb b/lib/netsuite/actions/update.rb index 37e822349..a7b261682 100644 --- a/lib/netsuite/actions/update.rb +++ b/lib/netsuite/actions/update.rb @@ -36,6 +36,12 @@ def request_body hash['platformMsgs:record']['@platformMsgs:externalId'] = updated_record.external_id end + inner = hash.dig("platformMsgs:record", :content!) + if inner.keys.grep(/(.*):nullFieldList?/).any? + null_field_key = inner.keys.grep(/(.*):nullFieldList?/) + hash["platformMsgs:record"][:content!]["platformCore:nullFieldList"] = hash["platformMsgs:record"][:content!].delete null_field_key[0] + end + hash end diff --git a/lib/netsuite/records/contact.rb b/lib/netsuite/records/contact.rb index 2934453f0..eb963ddb0 100644 --- a/lib/netsuite/records/contact.rb +++ b/lib/netsuite/records/contact.rb @@ -17,6 +17,7 @@ class Contact field :custom_field_list, CustomFieldList # field :subscriptions_list, SubscriptionsList # field :category_list, CategoryList + field :null_field_list, NullFieldList read_only_fields :last_modified_date, :date_created diff --git a/lib/netsuite/records/credit_memo.rb b/lib/netsuite/records/credit_memo.rb index b9999c869..444109af1 100644 --- a/lib/netsuite/records/credit_memo.rb +++ b/lib/netsuite/records/credit_memo.rb @@ -23,6 +23,7 @@ class CreditMemo field :item_list, CreditMemoItemList field :apply_list, CreditMemoApplyList field :ship_group_list, SalesOrderShipGroupList + field :null_field_list, NullFieldList # field :bill_address_list, field :transaction_bill_address, BillAddress diff --git a/lib/netsuite/records/customer.rb b/lib/netsuite/records/customer.rb index 055088713..b08ee4a85 100644 --- a/lib/netsuite/records/customer.rb +++ b/lib/netsuite/records/customer.rb @@ -35,6 +35,7 @@ class Customer field :partners_list, CustomerPartnersList field :subscriptions_list, CustomerSubscriptionsList field :sales_team_list, CustomerSalesTeamList + field :null_field_list, NullFieldList read_only_fields :balance, :consol_balance, :deposit_balance, :consol_deposit_balance, :overdue_balance, :consol_overdue_balance, :unbilled_orders, :consol_unbilled_orders diff --git a/lib/netsuite/records/customer_payment.rb b/lib/netsuite/records/customer_payment.rb index 9baab81fc..7ff356040 100644 --- a/lib/netsuite/records/customer_payment.rb +++ b/lib/netsuite/records/customer_payment.rb @@ -17,6 +17,7 @@ class CustomerPayment field :custom_field_list, CustomFieldList field :apply_list, CustomerPaymentApplyList + field :null_field_list, NullFieldList read_only_fields :applied, :balance, :pending, :total, :unapplied diff --git a/lib/netsuite/records/expense_report.rb b/lib/netsuite/records/expense_report.rb index 76724693b..55b4644c4 100644 --- a/lib/netsuite/records/expense_report.rb +++ b/lib/netsuite/records/expense_report.rb @@ -15,7 +15,7 @@ class ExpenseReport # field :accounting_book_detail_list, AccountingBookDetailList field :custom_field_list, CustomFieldList field :expense_list, ExpenseReportExpenseList - + field :null_field_list, NullFieldList record_refs :account, :approval_status, :klass, :custom_form, :department, :entity, :location, :next_approver, :posting_period, :subsidiary diff --git a/lib/netsuite/records/inventory_adjustment.rb b/lib/netsuite/records/inventory_adjustment.rb index 74cc61a5b..97fc54686 100644 --- a/lib/netsuite/records/inventory_adjustment.rb +++ b/lib/netsuite/records/inventory_adjustment.rb @@ -13,6 +13,7 @@ class InventoryAdjustment field :inventory_list, InventoryAdjustmentInventoryList field :custom_field_list, CustomFieldList + field :null_field_list, NullFieldList record_refs :account, :adj_location, :customer, :posting_period, :location, :department, :subsidiary, :custom_form, :klass diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 99ea37250..743632c61 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -38,6 +38,7 @@ class Invoice field :custom_field_list, CustomFieldList field :shipping_address, Address field :billing_address, Address + field :null_field_list, NullFieldList read_only_fields :sub_total, :discount_total, :total, :recognized_revenue, :amount_remaining, :amount_paid, :alt_shipping_cost, :gift_cert_applied, :handling_cost, :alt_handling_cost diff --git a/lib/netsuite/records/item_fulfillment.rb b/lib/netsuite/records/item_fulfillment.rb index fd5e691d3..8e892bbf5 100644 --- a/lib/netsuite/records/item_fulfillment.rb +++ b/lib/netsuite/records/item_fulfillment.rb @@ -27,6 +27,7 @@ class ItemFulfillment field :item_list, ItemFulfillmentItemList field :package_list, ItemFulfillmentPackageList field :custom_field_list, CustomFieldList + field :null_field_list, NullFieldList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/item_receipt.rb b/lib/netsuite/records/item_receipt.rb index 5638e3243..ff5b0a577 100644 --- a/lib/netsuite/records/item_receipt.rb +++ b/lib/netsuite/records/item_receipt.rb @@ -24,6 +24,7 @@ class ItemReceipt field :item_list, ItemReceiptItemList field :expense_list, ItemReceiptExpenseList field :custom_field_list, CustomFieldList + field :null_field_list, NullFieldList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/journal_entry.rb b/lib/netsuite/records/journal_entry.rb index 30504e445..4c44a046e 100644 --- a/lib/netsuite/records/journal_entry.rb +++ b/lib/netsuite/records/journal_entry.rb @@ -14,6 +14,7 @@ class JournalEntry field :custom_field_list, CustomFieldList field :line_list, JournalEntryLineList + field :null_field_list, NullFieldList record_refs :created_from, :currency, :custom_form, :department, :klass, :location, :parent_expense_alloc, :posting_period, :subsidiary, :to_subsidiary diff --git a/lib/netsuite/records/name.rb b/lib/netsuite/records/name.rb deleted file mode 100644 index 0cc9222ac..000000000 --- a/lib/netsuite/records/name.rb +++ /dev/null @@ -1,23 +0,0 @@ -module NetSuite - module Records - class Name - include Support::Fields - include Support::Records - #include Namespaces::PlatformCore - - attr_accessor :attributes - - def initialize(attributes = {}) - binding.pry - @value = attributes.delete(:value) || attributes.delete(:@value) - @type = attributes.delete(:type) || attributes.delete(:"@xsi:type") - self.attributes = attributes - end - - def value - attributes[:value] - end - - end - end -end diff --git a/lib/netsuite/records/null_field_list.rb b/lib/netsuite/records/null_field_list.rb index 5984357d5..c970a4904 100644 --- a/lib/netsuite/records/null_field_list.rb +++ b/lib/netsuite/records/null_field_list.rb @@ -3,6 +3,9 @@ module Records class NullFieldList include Support::Fields include Support::Records + include Namespaces::PlatformCore + + attr_accessor :type fields :name diff --git a/lib/netsuite/records/purchase_order.rb b/lib/netsuite/records/purchase_order.rb index 63fc18102..ff880987f 100644 --- a/lib/netsuite/records/purchase_order.rb +++ b/lib/netsuite/records/purchase_order.rb @@ -21,6 +21,7 @@ class PurchaseOrder field :custom_field_list, CustomFieldList field :item_list, PurchaseOrderItemList field :expense_list, PurchaseOrderExpenseList + field :null_field_list, NullFieldList # TODO custom lists # :ship_address_list diff --git a/lib/netsuite/records/sales_order.rb b/lib/netsuite/records/sales_order.rb index 3fdb2d23e..53f09f8b2 100644 --- a/lib/netsuite/records/sales_order.rb +++ b/lib/netsuite/records/sales_order.rb @@ -33,6 +33,7 @@ class SalesOrder field :gift_cert_redemption_list, GiftCertRedemptionList field :ship_group_list, SalesOrderShipGroupList field :promotions_list, PromotionsList + field :null_field_list, NullFieldList read_only_fields :applied, :discount_total, :sub_total, :tax_total, :total, :unapplied, :est_gross_profit_percent diff --git a/lib/netsuite/records/time_bill.rb b/lib/netsuite/records/time_bill.rb index bad36d2f3..ae0ed6174 100644 --- a/lib/netsuite/records/time_bill.rb +++ b/lib/netsuite/records/time_bill.rb @@ -14,6 +14,7 @@ class TimeBill field :custom_field_list, CustomFieldList field :hours, Duration + field :null_field_list, NullFieldList record_refs :employee, :customer, :case_task_event, :payroll_item, :workplace, :item, :department, :location, :price, :subsidiary, :temporary_local_jurisdiction, :temporary_state_jurisdiction diff --git a/lib/netsuite/records/transfer_order.rb b/lib/netsuite/records/transfer_order.rb index db43ce630..691734197 100644 --- a/lib/netsuite/records/transfer_order.rb +++ b/lib/netsuite/records/transfer_order.rb @@ -21,6 +21,7 @@ class TransferOrder field :custom_field_list, CustomFieldList field :item_list, TransferOrderItemList + field :null_field_list, NullFieldList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/vendor.rb b/lib/netsuite/records/vendor.rb index e1491c6b1..ac3546842 100644 --- a/lib/netsuite/records/vendor.rb +++ b/lib/netsuite/records/vendor.rb @@ -24,6 +24,7 @@ class Vendor field :custom_field_list, CustomFieldList # TODO should change name to VendorAddressBookList field :addressbook_list, CustomerAddressbookList + field :null_field_list, NullFieldList read_only_fields :balance_primary, :balance, :last_modified_date, :unbilled_orders, :unbilled_orders_primary diff --git a/lib/netsuite/records/vendor_bill.rb b/lib/netsuite/records/vendor_bill.rb index cebd7de7e..8d3438ae7 100644 --- a/lib/netsuite/records/vendor_bill.rb +++ b/lib/netsuite/records/vendor_bill.rb @@ -17,6 +17,7 @@ class VendorBill field :expense_list, VendorBillExpenseList field :item_list, VendorBillItemList field :purchase_order_list, RecordRefList + field :null_field_list, NullFieldList read_only_fields :status diff --git a/lib/netsuite/records/vendor_credit.rb b/lib/netsuite/records/vendor_credit.rb index 6209e6d6c..b33243554 100644 --- a/lib/netsuite/records/vendor_credit.rb +++ b/lib/netsuite/records/vendor_credit.rb @@ -22,6 +22,7 @@ class VendorCredit field :item_list, VendorCreditItemList field :apply_list, VendorCreditApplyList field :custom_field_list, CustomFieldList + field :null_field_list, NullFieldList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/vendor_payment.rb b/lib/netsuite/records/vendor_payment.rb index dbf08cbf7..073f74517 100644 --- a/lib/netsuite/records/vendor_payment.rb +++ b/lib/netsuite/records/vendor_payment.rb @@ -16,6 +16,7 @@ class VendorPayment field :apply_list, VendorPaymentApplyList field :custom_field_list, CustomFieldList + field :null_field_list, NullFieldList record_refs :account, :ap_acct, :currency, :custom_form, :department, :entity, :klass, :location, :posting_period, :subsidiary, :void_journal From 3643f51b6eb2cf18d14a306cd1acf20da07609ef Mon Sep 17 00:00:00 2001 From: timothyjb Date: Wed, 28 Jul 2021 10:40:33 -0400 Subject: [PATCH 32/62] return-netsuite-error-for-search-action-failures Why currently, if the response is not successful, it just returns `false` but does not give any insight into what made it not successful. Solution Retrun a NetSuite::Error which will contain the error message --- lib/netsuite/actions/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index e5f8420dd..0e319175b 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -244,7 +244,7 @@ def search(options = { }, credentials={}) if response.success? NetSuite::Support::SearchResult.new(response, self, credentials) else - false + NetSuite::Error.new(response.body[:status][:status_detail]) end end end From b6c885a2953d15f302848afb3f6184b3c874ef35 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Mon, 9 Aug 2021 12:50:53 -0500 Subject: [PATCH 33/62] added missing fields and actions --- lib/netsuite/records/currency.rb | 2 +- lib/netsuite/records/expense_report.rb | 2 +- lib/netsuite/records/expense_report_expense.rb | 2 +- lib/netsuite/records/journal_entry.rb | 6 +++--- lib/netsuite/records/journal_entry_line.rb | 6 ++++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/netsuite/records/currency.rb b/lib/netsuite/records/currency.rb index 53b58800b..d83f1bb34 100644 --- a/lib/netsuite/records/currency.rb +++ b/lib/netsuite/records/currency.rb @@ -10,7 +10,7 @@ class Currency # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/currency.html - actions :get, :get_list, :get_all, :add, :update, :upsert, :upsert_list, :delete + actions :get, :get_list, :get_all, :add, :update, :upsert, :upsert_list, :delete, :search fields :name, :symbol, :is_base_currency, :is_inactive, :override_currency_format, :display_symbol, :symbol_placement, :locale, :formatSample, :exchangeRate, :fx_rate_update_timezone, :incl_in_fx_rate_updates, :currency_precision diff --git a/lib/netsuite/records/expense_report.rb b/lib/netsuite/records/expense_report.rb index 55b4644c4..de2c56db4 100644 --- a/lib/netsuite/records/expense_report.rb +++ b/lib/netsuite/records/expense_report.rb @@ -7,7 +7,7 @@ class ExpenseReport include Support::Actions include Namespaces::TranEmp - actions :add, :get, :search, :update + actions :add, :get, :get_list, :search, :update fields :accounting_approval, :advance, :amount, :complete, :created_date, :due_date, :last_modified_date, :memo, :status, :supervisor_approval, :tax1_amt, :tax2_amt, :total, :tran_date, :tran_id, :use_multi_currency diff --git a/lib/netsuite/records/expense_report_expense.rb b/lib/netsuite/records/expense_report_expense.rb index e81ea0af5..af9a6ac0d 100644 --- a/lib/netsuite/records/expense_report_expense.rb +++ b/lib/netsuite/records/expense_report_expense.rb @@ -10,7 +10,7 @@ class ExpenseReportExpense field :custom_field_list - record_refs :category, :klass, :currency, :customer, :department, :location, :tax_code + record_refs :category, :klass, :currency, :customer, :department, :location, :tax_code, :exp_media_item def initialize(attributes_or_record = {}) case attributes_or_record diff --git a/lib/netsuite/records/journal_entry.rb b/lib/netsuite/records/journal_entry.rb index 4c44a046e..481b92e6f 100644 --- a/lib/netsuite/records/journal_entry.rb +++ b/lib/netsuite/records/journal_entry.rb @@ -7,17 +7,17 @@ class JournalEntry include Support::Actions include Namespaces::TranGeneral - actions :get, :get_list, :add, :delete, :search, :upsert + actions :get, :get_list, :add, :delete, :search, :upsert, :update fields :approved, :created_date, :exchange_rate, :last_modified_date, :memo, :reversal_date, :reversal_defer, :reversal_entry, - :tran_date, :tran_id + :tran_date, :tran_id, :is_book_specific field :custom_field_list, CustomFieldList field :line_list, JournalEntryLineList field :null_field_list, NullFieldList record_refs :created_from, :currency, :custom_form, :department, :klass, :location, :parent_expense_alloc, - :posting_period, :subsidiary, :to_subsidiary + :posting_period, :subsidiary, :to_subsidiary, :accounting_book attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/journal_entry_line.rb b/lib/netsuite/records/journal_entry_line.rb index a8dbe1c2d..764c1f9e2 100644 --- a/lib/netsuite/records/journal_entry_line.rb +++ b/lib/netsuite/records/journal_entry_line.rb @@ -6,9 +6,11 @@ class JournalEntryLine include Support::Records include Namespaces::TranGeneral - fields :credit, :debit, :eliminate, :end_date, :gross_amt, :memo, :residual, :start_date, :tax1_amt, :tax_rate1 + fields :credit, :debit, :eliminate, :end_date, :gross_amt, :memo, :residual, :start_date, :tax1_amt, :tax_rate1, :line + field :custom_field_list, CustomFieldList - record_refs :account, :department, :entity, :klass, :location, :schedule, :schedule_num, :tax1_acct, :tax_code + + record_refs :account, :department, :entity, :klass, :location, :schedule, :schedule_num, :tax1_acct, :tax_code, :revenue_recognition_rule def initialize(attributes = {}) initialize_from_attributes_hash(attributes) From 18268f882d2d8352ac3a019f4ae94e308ce159ac Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Tue, 10 Aug 2021 12:24:23 -0500 Subject: [PATCH 34/62] added tests --- .../records/expense_report_expense.rb | 2 +- .../expense_report_expense_list_spec.rb | 60 ++++++++ .../records/expense_report_expense_spec.rb | 26 ++++ spec/netsuite/records/expense_report_spec.rb | 134 ++++++++++++++++++ .../records/journal_entry_line_spec.rb | 2 +- spec/netsuite/records/journal_entry_spec.rb | 4 +- 6 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 spec/netsuite/records/expense_report_expense_list_spec.rb create mode 100644 spec/netsuite/records/expense_report_expense_spec.rb create mode 100644 spec/netsuite/records/expense_report_spec.rb diff --git a/lib/netsuite/records/expense_report_expense.rb b/lib/netsuite/records/expense_report_expense.rb index af9a6ac0d..26a6be350 100644 --- a/lib/netsuite/records/expense_report_expense.rb +++ b/lib/netsuite/records/expense_report_expense.rb @@ -8,7 +8,7 @@ class ExpenseReportExpense fields :amount, :exchange_rate, :expense_date, :foreign_amount, :gross_amt, :is_billable, :is_non_reimburable, :line, :memo, :quantity, :rate, :receipt, :ref_number, :tax1_amt, :tax_rate1, :tax_rate2 - field :custom_field_list + field :custom_field_list, CustomFieldList record_refs :category, :klass, :currency, :customer, :department, :location, :tax_code, :exp_media_item diff --git a/spec/netsuite/records/expense_report_expense_list_spec.rb b/spec/netsuite/records/expense_report_expense_list_spec.rb new file mode 100644 index 000000000..50fc6f209 --- /dev/null +++ b/spec/netsuite/records/expense_report_expense_list_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe NetSuite::Records::ExpenseReportExpense do + let(:expense) { NetSuite::Records::ExpenseReportExpense.new } + + it 'has all the right fields' do + [ + :amount, :exchange_rate, :expense_date, :foreign_amount, :gross_amt, :is_billable, :is_non_reimburable, + :line, :memo, :quantity, :rate, :receipt, :ref_number, :tax1_amt, :tax_rate1, :tax_rate2 + ].each do |field| + expect(expense).to have_field(field) + end + end + + it 'has all the right record refs' do + [ + :category, :klass, :currency, :customer, :department, :location, :tax_code, :exp_media_item + ].each do |record_ref| + expect(expense).to have_record_ref(record_ref) + end + end + + describe '#custom_field_list' do + it 'can be set from attributes' do + attributes = { + :custom_field => { + :amount => 10, + :internal_id => 'custfield_amount' + } + } + expense.custom_field_list = attributes + expect(expense.custom_field_list).to be_kind_of(NetSuite::Records::CustomFieldList) + expect(expense.custom_field_list.custom_fields.length).to eql(1) + end + + it 'can be set from a CustomFieldList object' do + custom_field_list = NetSuite::Records::CustomFieldList.new + expense.custom_field_list = custom_field_list + expect(expense.custom_field_list).to eql(custom_field_list) + end + end + + describe '#to_record' do + let(:expense) { NetSuite::Records::ExpenseReportExpense.new(:memo => 'This is a memo', :is_billable => true) } + + it 'returns a hash of attributes that can be used in a SOAP request' do + expect(expense.to_record).to eql({ + 'tranEmp:memo' => 'This is a memo', + 'tranEmp:isBillable' => true + }) + end + end + + describe '#record_type' do + it 'returns a string type for the record to be used in a SOAP request' do + expect(expense.record_type).to eql('tranEmp:ExpenseReportExpense') + end + end + +end diff --git a/spec/netsuite/records/expense_report_expense_spec.rb b/spec/netsuite/records/expense_report_expense_spec.rb new file mode 100644 index 000000000..b8f76a97e --- /dev/null +++ b/spec/netsuite/records/expense_report_expense_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe NetSuite::Records::ExpenseReportExpenseList do + let(:list) { NetSuite::Records::ExpenseReportExpenseList.new } + + it 'has a custom_fields attribute' do + expect(list.expense).to be_kind_of(Array) + end + + describe '#to_record' do + before do + list.expense << NetSuite::Records::ExpenseReportExpense.new(:memo => 'This is a memo') + end + + it 'can represent itself as a SOAP record' do + record = + { + 'tranEmp:expense' => [{ + 'tranEmp:memo' => 'This is a memo' + }] + } + expect(list.to_record).to eql(record) + end + end + +end diff --git a/spec/netsuite/records/expense_report_spec.rb b/spec/netsuite/records/expense_report_spec.rb new file mode 100644 index 000000000..dfcc1d29b --- /dev/null +++ b/spec/netsuite/records/expense_report_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' + +describe NetSuite::Records::ExpenseReport do + let(:entry) { NetSuite::Records::ExpenseReport.new } + + it 'has all the right fields' do + [ + :accounting_approval, :advance, :amount, :complete, :created_date, + :due_date, :last_modified_date, :memo, :status, :supervisor_approval, + :tax1_amt, :tax2_amt, :total, :tran_date, :tran_id, :use_multi_currency + ].each do |field| + expect(entry).to have_field(field) + end + end + + it 'has all the right record refs' do + [ + :account, :approval_status, :klass, :custom_form, :department, :entity, + :location, :next_approver, :posting_period, :subsidiary + ].each do |record_ref| + expect(entry).to have_record_ref(record_ref) + end + end + + describe '#custom_field_list' do + it 'can be set from attributes' do + attributes = { + :custom_field => { + :amount => 10, + :script_id => 'custfield_amount' + } + } + entry.custom_field_list = attributes + expect(entry.custom_field_list).to be_kind_of(NetSuite::Records::CustomFieldList) + expect(entry.custom_field_list.custom_fields.length).to eql(1) + expect(entry.custom_field_list.custfield_amount.attributes[:amount]).to eq(10) + end + + it 'can be set from a CustomFieldList object' do + custom_field_list = NetSuite::Records::CustomFieldList.new + entry.custom_field_list = custom_field_list + expect(entry.custom_field_list).to eql(custom_field_list) + end + end + + describe '#expense_list' do + it 'can be set from attributes' do + attributes = { + :expense => { + + } + } + entry.expense_list = attributes + expect(entry.expense_list).to be_kind_of(NetSuite::Records::ExpenseReportExpenseList) + expect(entry.expense_list.expense.length).to eql(1) + end + + it 'can be set from a ExpenseReportExpenseList object' do + expense_list = NetSuite::Records::ExpenseReportExpenseList.new + entry.expense_list = expense_list + expect(entry.expense_list).to eql(expense_list) + end + end + + describe '.get' do + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :accounting_approval => true }) } + + it 'returns a ExpenseReport instance populated with the data from the response object' do + expect(NetSuite::Actions::Get).to receive(:call).with([NetSuite::Records::ExpenseReport, {:external_id => 1}], {}).and_return(response) + expense = NetSuite::Records::ExpenseReport.get(:external_id => 1) + expect(expense).to be_kind_of(NetSuite::Records::ExpenseReport) + expect(expense.accounting_approval).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'raises a RecordNotFound exception' do + binding.pry + expect(NetSuite::Actions::Get).to receive(:call).with([NetSuite::Records::ExpenseReport, {:external_id => 1}], {}).and_return(response) + expect { + NetSuite::Records::ExpenseReport.get(:external_id => 1) + }.to raise_error(NetSuite::RecordNotFound, + /NetSuite::Records::ExpenseReport with OPTIONS=(.*) could not be found/) + end + end + end + + describe '#add' do + let(:entry) { NetSuite::Records::ExpenseReport.new(:approved => true) } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + expect(NetSuite::Actions::Add).to receive(:call). + with([entry], {}). + and_return(response) + expect(entry.add).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + expect(NetSuite::Actions::Add).to receive(:call). + with([entry], {}). + and_return(response) + expect(entry.add).to be_falsey + end + end + end + + describe '#to_record' do + let(:entry) { NetSuite::Records::ExpenseReport.new(:tran_id => '1234', :accounting_approval => true) } + + it 'returns a hash of attributes that can be used in a SOAP request' do + expect(entry.to_record).to eql({ + 'tranEmp:tranId' => '1234', + 'tranEmp:accountingApproval' => true + }) + end + end + + describe '#record_type' do + it 'returns a string type for the record to be used in a SOAP request' do + expect(entry.record_type).to eql('tranEmp:ExpenseReport') + end + end + +end diff --git a/spec/netsuite/records/journal_entry_line_spec.rb b/spec/netsuite/records/journal_entry_line_spec.rb index 37809fa72..c46f2e056 100644 --- a/spec/netsuite/records/journal_entry_line_spec.rb +++ b/spec/netsuite/records/journal_entry_line_spec.rb @@ -13,7 +13,7 @@ it 'has all the right record refs' do [ - :account, :department, :entity, :klass, :location, :schedule, :schedule_num, :tax1_acct, :tax_code + :account, :department, :entity, :klass, :location, :schedule, :schedule_num, :tax1_acct, :tax_code, :revenue_recognition_rule ].each do |record_ref| expect(line).to have_record_ref(record_ref) end diff --git a/spec/netsuite/records/journal_entry_spec.rb b/spec/netsuite/records/journal_entry_spec.rb index 48d014e05..b2a038b99 100644 --- a/spec/netsuite/records/journal_entry_spec.rb +++ b/spec/netsuite/records/journal_entry_spec.rb @@ -6,7 +6,7 @@ it 'has all the right fields' do [ :approved, :created_date, :exchange_rate, :last_modified_date, :reversal_date, - :reversal_defer, :reversal_entry, :tran_date, :tran_id + :reversal_defer, :reversal_entry, :tran_date, :tran_id, :is_book_specific ].each do |field| expect(entry).to have_field(field) end @@ -15,7 +15,7 @@ it 'has all the right record refs' do [ :created_from, :currency, :custom_form, :department, :klass, :location, :parent_expense_alloc, :posting_period, - :subsidiary, :to_subsidiary + :subsidiary, :to_subsidiary, :accounting_book ].each do |record_ref| expect(entry).to have_record_ref(record_ref) end From fc632994126d67cc9853f609467f8565714940f0 Mon Sep 17 00:00:00 2001 From: timothyjb Date: Wed, 8 Sep 2021 13:05:24 -0400 Subject: [PATCH 35/62] CD-712-have-inventory_detail-use-the-InventoryDetail-class-in-vendor-bill Why The `:inventory_detail` attribute should point to a spesific class `InventoryDetail` Solution Move `:inventory_detail` from `fields` to `field` and list the class name --- lib/netsuite/records/vendor_bill_item.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/records/vendor_bill_item.rb b/lib/netsuite/records/vendor_bill_item.rb index 40ec3daec..f890a7db0 100644 --- a/lib/netsuite/records/vendor_bill_item.rb +++ b/lib/netsuite/records/vendor_bill_item.rb @@ -7,13 +7,14 @@ class VendorBillItem include Namespaces::TranPurch fields :amortization_end_date, :amortization_residual, :amortiz_start_date, :bin_numbers, :bill_variance_status, - :description, :expiration_date, :gross_amt, :inventory_detail, :is_billable, :landed_cost, :line, + :description, :expiration_date, :gross_amt, :is_billable, :landed_cost, :line, :order_doc, :order_line, :quantity, :serial_numbers, :tax_rate_1, :tax_rate_2, :tax_1_amt, :vendor_name, :rate field :bill_receipts_list, RecordRefList field :custom_field_list, CustomFieldList field :options, CustomFieldList + field :inventory_detail, InventoryDetail read_only_fields :amount From 38d3e0295036f6acc4f6e32f946adf05545afb37 Mon Sep 17 00:00:00 2001 From: Timothy Barkley Date: Mon, 24 Jan 2022 14:26:19 -0500 Subject: [PATCH 36/62] return-error-object-for-get-failure --- lib/netsuite/actions/get.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/actions/get.rb b/lib/netsuite/actions/get.rb index f1e32ad50..f76190b8d 100644 --- a/lib/netsuite/actions/get.rb +++ b/lib/netsuite/actions/get.rb @@ -82,7 +82,10 @@ def get(options = {}, credentials = {}) if response.success? new(response.body) else - raise RecordNotFound, "#{self} with OPTIONS=#{options.inspect} could not be found, NetSuite message: #{response.errors.status_detail[:message]}" + NetSuite::Error.new( + code: response.errors.status_detail[:code], + message: response.errors.status_detail[:message] + ) end end From e85ed1c1c17efcc6343387bab7af5ce72d0059b4 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 26 Jan 2022 21:12:07 -0500 Subject: [PATCH 37/62] add-record-ItemOptionCustomField Adding ItemOptionCustomField to the record namespace --- lib/netsuite.rb | 1 + .../records/item_option_custom_field.rb | 52 +++++++++++++++++++ .../records/item_option_custom_field_spec.rb | 27 ++++++++++ 3 files changed, 80 insertions(+) create mode 100644 lib/netsuite/records/item_option_custom_field.rb create mode 100644 spec/netsuite/records/item_option_custom_field_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 4da8aef85..65ab9a614 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -196,6 +196,7 @@ module Records autoload :Invoice, 'netsuite/records/invoice' autoload :InvoiceItem, 'netsuite/records/invoice_item' autoload :InvoiceItemList, 'netsuite/records/invoice_item_list' + autoload :ItemOptionCustomField, 'netsuite/records/item_option_custom_field' autoload :ItemFulfillment, 'netsuite/records/item_fulfillment' autoload :ItemFulfillmentItem, 'netsuite/records/item_fulfillment_item' autoload :ItemFulfillmentItemList, 'netsuite/records/item_fulfillment_item_list' diff --git a/lib/netsuite/records/item_option_custom_field.rb b/lib/netsuite/records/item_option_custom_field.rb new file mode 100644 index 000000000..97631ce95 --- /dev/null +++ b/lib/netsuite/records/item_option_custom_field.rb @@ -0,0 +1,52 @@ +module NetSuite + module Records + class ItemOptionCustomField + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::SetupCustom + + actions :get, :get_list, :add, :delete, :update, :upsert, :upsert_list + + # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2017_1/schema/record/ItemOptionCustomField.html + fields( + :access_level, + :col_all_items, + :col_kit_item, + :col_opportunity, + :col_option_label, + :col_purchase, + :col_sale, + :col_store, + :col_store_hidden, + :col_transfer_order, + :default_checked, + :default_value, + :description, + :display_height, + :display_width, + :help, + :is_formula, + :is_mandatory, + :label, + :link_text, + :max_length, + :max_value, + :min_value, + :store_value + ) + + record_refs :owner, :source_list, :select_record_type, :source_filter_by, :source_from, :search_default, :search_compare_field, :insert_before, :default_selection + + attr_reader :internal_id + attr_accessor :external_id + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + end + end +end diff --git a/spec/netsuite/records/item_option_custom_field_spec.rb b/spec/netsuite/records/item_option_custom_field_spec.rb new file mode 100644 index 000000000..f6de0eb0a --- /dev/null +++ b/spec/netsuite/records/item_option_custom_field_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe NetSuite::Records::ItemOptionCustomField do + + describe ".get" do + let(:response) do + NetSuite::Response.new( + success: true, + body: { + label: "Value of Label", + } + ) + end + + it "returns a ItemOptionCustomField instance with populated fields" do + expect(NetSuite::Actions::Get) + .to receive(:call) + .with([NetSuite::Records::ItemOptionCustomField, internal_id: 1], {}) + .and_return(response) + + record = NetSuite::Records::ItemOptionCustomField.get(internal_id: 1) + + expect(record.label).to eql("Value of Label") + end + end + +end \ No newline at end of file From d06a39970b81f13dd70ba4fcff4b57e04e8fc943 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 7 Feb 2022 17:53:08 -0500 Subject: [PATCH 38/62] add-more-refs-to-custom-record-type Why to give more include more detail from the xml to the end user --- lib/netsuite/records/custom_record_type.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/netsuite/records/custom_record_type.rb b/lib/netsuite/records/custom_record_type.rb index 355ca73f3..fb0581d75 100644 --- a/lib/netsuite/records/custom_record_type.rb +++ b/lib/netsuite/records/custom_record_type.rb @@ -15,6 +15,9 @@ class CustomRecordType :show_owner_on_list, :use_permissions record_ref :owner + record_ref :forms_list + record_ref :permissions_list + record_ref :custom_field_list attr_reader :internal_id attr_accessor :external_id From c5eaef091f3edbbfe4bed9b383897cbc1095dd59 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 11 Feb 2022 11:30:06 -0500 Subject: [PATCH 39/62] updates-to-record-ref Why update the BaseRefList class to include additional fields --- lib/netsuite/actions/get_select_value.rb | 6 +++++- lib/netsuite/records/base_ref_list.rb | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/actions/get_select_value.rb b/lib/netsuite/actions/get_select_value.rb index 2e20960f5..f9e2f7477 100644 --- a/lib/netsuite/actions/get_select_value.rb +++ b/lib/netsuite/actions/get_select_value.rb @@ -25,7 +25,11 @@ def success? end def response_body - @response_body ||= response_hash[:base_ref_list] + @response_body ||= { + total_records: response_hash[:total_records], + total_pages: response_hash[:total_pages], + base_ref: response_hash[:base_ref_list][:base_ref] + } end def response_hash diff --git a/lib/netsuite/records/base_ref_list.rb b/lib/netsuite/records/base_ref_list.rb index c7d56a155..fd131f509 100644 --- a/lib/netsuite/records/base_ref_list.rb +++ b/lib/netsuite/records/base_ref_list.rb @@ -8,6 +8,8 @@ class BaseRefList < Support::Sublist actions :get_select_value + fields :total_pages, :total_records + sublist :base_ref, RecordRef alias :base_refs :base_ref From 4f0166926e05ae9003f6d18ea6a95e170c8f8fa9 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 14 Mar 2022 17:02:59 -0400 Subject: [PATCH 40/62] add-more-attributes-to-TransactionColumnCustomField add more sttributes to class: `:source_list, :select_record_type, :source_filter_by` --- lib/netsuite/records/transaction_column_custom_field.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/transaction_column_custom_field.rb b/lib/netsuite/records/transaction_column_custom_field.rb index 3f3b2eadd..a882e2e00 100644 --- a/lib/netsuite/records/transaction_column_custom_field.rb +++ b/lib/netsuite/records/transaction_column_custom_field.rb @@ -44,7 +44,7 @@ class TransactionColumnCustomField :script_id ) - record_refs :owner + record_refs :owner, :source_list, :select_record_type, :source_filter_by attr_reader :internal_id attr_accessor :external_id From e041094e637a7739adb94bd62e28ed23b1d8ad44 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 17 Mar 2022 09:41:35 -0400 Subject: [PATCH 41/62] CD-2148-add-custom-segments-class Adding class for CustomSegment Add additional action to TransactionColumnCustomField `:get_select_value` --- lib/netsuite.rb | 1 + lib/netsuite/records/custom_segment.rb | 33 +++++++++++++++++++ .../transaction_column_custom_field.rb | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 lib/netsuite/records/custom_segment.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 65ab9a614..69aeeb9e2 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -105,6 +105,7 @@ module Records autoload :CustomField, 'netsuite/records/custom_field' autoload :CustomFieldList, 'netsuite/records/custom_field_list' autoload :CustomList, 'netsuite/records/custom_list' + autoload :CustomSegment, 'netsuite/records/custom_segment' autoload :CustomRecord, 'netsuite/records/custom_record' autoload :CustomRecordRef, 'netsuite/records/custom_record_ref' autoload :CustomRecordType, 'netsuite/records/custom_record_type' diff --git a/lib/netsuite/records/custom_segment.rb b/lib/netsuite/records/custom_segment.rb new file mode 100644 index 000000000..23fbf620c --- /dev/null +++ b/lib/netsuite/records/custom_segment.rb @@ -0,0 +1,33 @@ +module NetSuite + module Records + class CustomSegment + include Support::Fields + include Support::Records + include Support::Actions + include Namespaces::SetupCustom + + actions :get + + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/record/customsegment.html + fields :label, + :script_id, + :record_script_id, + :record_type, + :field_type, + :is_inactive, + :show_in_list, + :has_lg_impact, + :is_mandatory + + + attr_reader :internal_id + attr_accessor :external_id + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + end + end +end diff --git a/lib/netsuite/records/transaction_column_custom_field.rb b/lib/netsuite/records/transaction_column_custom_field.rb index a882e2e00..ad4285b12 100644 --- a/lib/netsuite/records/transaction_column_custom_field.rb +++ b/lib/netsuite/records/transaction_column_custom_field.rb @@ -7,7 +7,7 @@ class TransactionColumnCustomField include Support::Actions include Namespaces::SetupCustom - actions :get, :get_list, :add, :delete, :update, :upsert, :upsert_list + actions :get, :get_list, :add, :delete, :update, :upsert, :upsert_list, :get_select_value # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2017_1/schema/record/transactioncolumncustomfield.html fields( From 720d9685793b9abed4c31b56462a92b5459bbfd2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 17 Mar 2022 14:12:59 -0400 Subject: [PATCH 42/62] CD-2148-add-more-record_ref-for-TransactionColumnCustomField add `:source_from, :custom_segment, :role_access_list` for TransactionColumnCustomField response --- lib/netsuite/records/transaction_column_custom_field.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/transaction_column_custom_field.rb b/lib/netsuite/records/transaction_column_custom_field.rb index ad4285b12..4e2e7ae3b 100644 --- a/lib/netsuite/records/transaction_column_custom_field.rb +++ b/lib/netsuite/records/transaction_column_custom_field.rb @@ -44,7 +44,7 @@ class TransactionColumnCustomField :script_id ) - record_refs :owner, :source_list, :select_record_type, :source_filter_by + record_refs :owner, :source_list, :select_record_type, :source_filter_by, :source_from, :custom_segment, :role_access_list attr_reader :internal_id attr_accessor :external_id From ae536df14d2533e12863b3e15295c10a772c73d2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 17 Mar 2022 15:34:29 -0400 Subject: [PATCH 43/62] CD-2148-return-warnings-for-GetSelectValue Why There are times whe the response body is totally different. Need to account for both of those situations --- lib/netsuite/actions/get_select_value.rb | 9 +++++++-- lib/netsuite/records/base_ref_list.rb | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/actions/get_select_value.rb b/lib/netsuite/actions/get_select_value.rb index f9e2f7477..6a7cf0daf 100644 --- a/lib/netsuite/actions/get_select_value.rb +++ b/lib/netsuite/actions/get_select_value.rb @@ -25,10 +25,15 @@ def success? end def response_body - @response_body ||= { + @response_body ||= build_response_hash + end + + def build_response_hash + return response_hash if response_hash[:base_ref_list].blank? + { total_records: response_hash[:total_records], total_pages: response_hash[:total_pages], - base_ref: response_hash[:base_ref_list][:base_ref] + base_ref: response_hash.dig(:base_ref_list, :base_ref) } end diff --git a/lib/netsuite/records/base_ref_list.rb b/lib/netsuite/records/base_ref_list.rb index fd131f509..2212c9fcc 100644 --- a/lib/netsuite/records/base_ref_list.rb +++ b/lib/netsuite/records/base_ref_list.rb @@ -8,7 +8,7 @@ class BaseRefList < Support::Sublist actions :get_select_value - fields :total_pages, :total_records + fields :total_pages, :total_records, :status sublist :base_ref, RecordRef From cba0a8efb1379a6c49dd611bc235ce0bcce244c6 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 21 Mar 2022 10:04:36 -0400 Subject: [PATCH 44/62] updates-to-get-list-action Why Need to modify the response to the get_list action to include error messages --- lib/netsuite/actions/get_list.rb | 21 ++++++++++++--------- lib/netsuite/records/custom_segment.rb | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/netsuite/actions/get_list.rb b/lib/netsuite/actions/get_list.rb index 2fc18105f..dde5efc72 100644 --- a/lib/netsuite/actions/get_list.rb +++ b/lib/netsuite/actions/get_list.rb @@ -65,8 +65,8 @@ def response_body end def success? - # each returned record has its own status; - if @options[:allow_incomplete] + # each returned record has its own status; + if @options[:allow_incomplete] @success ||= !response_body.detect { |r| r[:status][:@is_success] == 'true' }.nil? else @success ||= response_body.detect { |r| r[:status][:@is_success] != 'true' }.nil? @@ -82,14 +82,17 @@ module ClassMethods def get_list(options = { }, credentials={}) response = NetSuite::Actions::GetList.call([self, options], credentials) - if response.success? - response.body.inject([]) do |arr, record| - arr << new(record[:record]) unless record[:status][:@is_success] != 'true' - arr - end - else - false + response.errors = response.body.inject([]) do |arr, record| + arr << record if record[:status][:@is_success] != 'true' + arr end + + response.body = response.body.inject([]) do |arr, record| + arr << new(record[:record]) unless record[:status][:@is_success] != 'true' + arr + end + + response end end end diff --git a/lib/netsuite/records/custom_segment.rb b/lib/netsuite/records/custom_segment.rb index 23fbf620c..4ea828008 100644 --- a/lib/netsuite/records/custom_segment.rb +++ b/lib/netsuite/records/custom_segment.rb @@ -6,7 +6,7 @@ class CustomSegment include Support::Actions include Namespaces::SetupCustom - actions :get + actions :get, :get_list # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/record/customsegment.html fields :label, From 59887072cdc9cb14d1fb3ee3a98bfd9eef15f2d8 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 12 Apr 2022 15:27:27 -0400 Subject: [PATCH 45/62] additions-to-department why adding missing attributes to department --- lib/netsuite/records/department.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/records/department.rb b/lib/netsuite/records/department.rb index 1c09659a8..c09d1a6d7 100644 --- a/lib/netsuite/records/department.rb +++ b/lib/netsuite/records/department.rb @@ -1,3 +1,5 @@ +#https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/record/department.html + module NetSuite module Records class Department @@ -9,9 +11,10 @@ class Department actions :get, :get_list, :get_select_value, :add, :delete, :upsert, :search, :update - fields :name, :is_inactive + fields :name, :is_inactive, :include_children + field :custom_field_list, CustomFieldList - record_refs :parent + record_refs :parent, :subsidiary_list attr_reader :internal_id attr_accessor :external_id From f330937d35e235c76db60d6993316d90edc0bd6f Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 14 Apr 2022 14:23:24 -0400 Subject: [PATCH 46/62] add-otherCustomField-record Why This recrod type was requested by customer --- lib/netsuite.rb | 1 + lib/netsuite/records/other_custom_field.rb | 67 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 lib/netsuite/records/other_custom_field.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 69aeeb9e2..0ae7b389b 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -236,6 +236,7 @@ module Records autoload :OpportunityItem, 'netsuite/records/opportunity_item' autoload :OpportunityItemList, 'netsuite/records/opportunity_item_list' autoload :OtherChargeSaleItem, 'netsuite/records/other_charge_sale_item' + autoload :OtherCustomField, 'netsuite/records/other_custom_field' autoload :Partner, 'netsuite/records/partner' autoload :PaymentItem, 'netsuite/records/payment_item' autoload :PaymentMethod, 'netsuite/records/payment_method' diff --git a/lib/netsuite/records/other_custom_field.rb b/lib/netsuite/records/other_custom_field.rb new file mode 100644 index 000000000..1ad991c5b --- /dev/null +++ b/lib/netsuite/records/other_custom_field.rb @@ -0,0 +1,67 @@ +module NetSuite + module Records + class OtherCustomField + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::SetupCustom + + actions :add, :delete, :delete_list, :get, :get_list, :get_select_value, :update, :update_list, :upsert, :upsert_list + + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/record/othercustomfield.html + + + fields :access_level, + :check_spelling, + :custom_Ssgment, + :default_checked, + :default_selection, + :default_value, + :dept_access_list, + :description, + :display_height, + :display_type, + :display_width, + :dynamic_default, + :filter_list, + :help, + :insert_before, + :is_formula, + :is_mandatory, + :label, + :link_text, + :max_length, + :max_value, + :min_value, + :role_access_list, + :search_level, + :show_in_list, + :store_value, + :sub_access_list, + :translations_list + + + record_refs :owner, + :rec_type, + :search_compare_field, + :search_default, + :select_record_type, + :source_filter_by, + :source_from, + :source_list + + + attr_reader :internal_id + attr_accessor :external_id + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + initialize_from_attributes_hash(attributes) + end + + end + end +end + From fe2671956eaf0b9031b2af98b4156dccb07369a9 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 20 May 2022 12:36:02 -0500 Subject: [PATCH 47/62] add-item-record-type Why To give users access to the item record --- lib/netsuite.rb | 1 + lib/netsuite/records/item.rb | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 lib/netsuite/records/item.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 0ae7b389b..e51e9d48d 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -203,6 +203,7 @@ module Records autoload :ItemFulfillmentItemList, 'netsuite/records/item_fulfillment_item_list' autoload :ItemFulfillmentPackage, 'netsuite/records/item_fulfillment_package' autoload :ItemFulfillmentPackageList, 'netsuite/records/item_fulfillment_package_list' + autoload :Item, 'netsuite/records/item' autoload :ItemGroup, 'netsuite/records/item_group' autoload :ItemMember, 'netsuite/records/item_member' autoload :ItemMemberList, 'netsuite/records/item_member_list' diff --git a/lib/netsuite/records/item.rb b/lib/netsuite/records/item.rb new file mode 100644 index 000000000..1e4e93b5d --- /dev/null +++ b/lib/netsuite/records/item.rb @@ -0,0 +1,45 @@ +module NetSuite + module Records + class Item + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::ListAcct + + actions :search + + fields :created_date, + :last_modified_date, + :purchase_description, + :expense_account, + :item_id, + :display_name, + :include_children, + :is_inactive, + :tax_schedule, + :deferral_account, + :is_fulfillable, + :generate_accruals, + :currency + + field :custom_field_list, CustomFieldList + + attr_reader :internal_id + attr_accessor :external_id + + def initialize(attributes = {}) + @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) + @external_id = attributes.delete(:external_id) || attributes.delete(:@external_id) + @xsi_type = attributes.delete(:"xsi:type") || attributes.delete(:"@xsi:type") + @item_type = determin_item_type(attributes) if @xsi_type + initialize_from_attributes_hash(attributes) + end + + def determin_item_type(attributes) + @xsi_type.split(":").last + end + + end + end +end From 7577b3c5eb5fb0516d0eb679c0899ef74a2a3310 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 20 May 2022 13:56:29 -0500 Subject: [PATCH 48/62] fix-nme-Attributes-method Why Not all classes have or need a `klass` attribute --- lib/netsuite/support/attributes.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/support/attributes.rb b/lib/netsuite/support/attributes.rb index 6d1e29825..52fd31e0d 100644 --- a/lib/netsuite/support/attributes.rb +++ b/lib/netsuite/support/attributes.rb @@ -14,7 +14,8 @@ def initialize_from_attributes_hash(attributes = {}) attributes.select { |k,v| self.class.fields.include?(k) }.each do |k,v| send("#{k}=", v) end - self.klass = attributes[:class] if attributes[:class] + + self.klass = attributes[:class] if attributes[:class] && self.respond_to?(:klass) end end From 379328ba9e4be5421aa054d040f7f05780bc4616 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 18 Jul 2022 18:14:38 -0400 Subject: [PATCH 49/62] update-default-netsuite-api-version Why version 2015 has been yanked. Updating the default to 2016_2 --- lib/netsuite/configuration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 76d7072a8..489248821 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -101,7 +101,7 @@ def api_version(version = nil) if version self.api_version = version else - attributes[:api_version] ||= '2015_1' + attributes[:api_version] ||= '2016_2' end end From d8b823686f544f90d69f50ea0b4befa6489f699e Mon Sep 17 00:00:00 2001 From: Mike Good Date: Tue, 7 Mar 2023 10:20:56 -0600 Subject: [PATCH 50/62] [CD-4491] Adding async add list action --- lib/netsuite.rb | 1 + lib/netsuite/actions/async_add_list.rb | 122 ++++++++++++++++++ lib/netsuite/records/journal_entry.rb | 2 +- lib/netsuite/support/actions.rb | 2 + spec/netsuite/actions/async_add_list_spec.rb | 113 ++++++++++++++++ .../async_add_list_response.xml | 17 +++ 6 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 lib/netsuite/actions/async_add_list.rb create mode 100644 spec/netsuite/actions/async_add_list_spec.rb create mode 100644 spec/support/fixtures/async_add_list/async_add_list_response.xml diff --git a/lib/netsuite.rb b/lib/netsuite.rb index e51e9d48d..d1c981f19 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -49,6 +49,7 @@ module Support module Actions autoload :Add, 'netsuite/actions/add' + autoload :AsyncAddList, 'netsuite/actions/async_add_list' autoload :Attach, 'netsuite/actions/attach' autoload :Delete, 'netsuite/actions/delete' autoload :DeleteList, 'netsuite/actions/delete_list' diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb new file mode 100644 index 000000000..4f89e255e --- /dev/null +++ b/lib/netsuite/actions/async_add_list.rb @@ -0,0 +1,122 @@ +# https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteCloudCustomizationScriptingWebServices/SuiteTalkWebServices/asyncAddList.html +module NetSuite + module Actions + class AsyncAddList + include Support::Requests + + def initialize(*objects) + @objects = objects + end + + private + + def request(credentials={}) + NetSuite::Configuration.connection( + {}, 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?(:internal_id) && o.internal_id + hash['@internalId'] = o.internal_id + end + + if o.respond_to?(:external_id) && o.external_id + hash['@externalId'] = o.external_id + end + + hash + end + + { 'record' => attrs } + end + + def response_hash + binding.pry + @response_hash ||= Array[@response.body[:async_add_list_response][:async_status_result]] + end + + def response_body + @response_body ||= response_hash.map { |h| h[:job_id] } + end + + def response_errors + binding.pry + if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } + @response_errors ||= errors + end + end + + def errors + errors = response_hash.select { |h| h[:status] && h[:status][:status_detail] }.map do |obj| + error_obj = obj[:status][:status_detail] + error_obj = [error_obj] if error_obj.class == Hash + errors = error_obj.map do |error| + NetSuite::Error.new(error) + end + + [obj[:base_ref][:@external_id], errors] + end + Hash[errors] + end + + def success? + #binding.pry + response_hash[0][:job_id] + end + + module Support + + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def async_add_list(records, credentials = {}) + netsuite_records = records.map do |r| + if r.kind_of?(self) + r + else + self.new(r) + end + end + + response = NetSuite::Actions::AsyncAddList.call(netsuite_records, credentials) + + if response.success? + response.body.map do |attr| + record = netsuite_records.find do |r| + r.external_id == attr[:@external_id] + end + + record.instance_variable_set('@internal_id', attr[:@internal_id]) + end + + netsuite_records + + else + false + end + end + end + end + end + end +end diff --git a/lib/netsuite/records/journal_entry.rb b/lib/netsuite/records/journal_entry.rb index 481b92e6f..722662bad 100644 --- a/lib/netsuite/records/journal_entry.rb +++ b/lib/netsuite/records/journal_entry.rb @@ -7,7 +7,7 @@ class JournalEntry include Support::Actions include Namespaces::TranGeneral - actions :get, :get_list, :add, :delete, :search, :upsert, :update + actions :get, :get_list, :add, :async_add_list, :delete, :search, :upsert, :update fields :approved, :created_date, :exchange_rate, :last_modified_date, :memo, :reversal_date, :reversal_defer, :reversal_entry, :tran_date, :tran_id, :is_book_specific diff --git a/lib/netsuite/support/actions.rb b/lib/netsuite/support/actions.rb index 29617272a..47d2488ee 100644 --- a/lib/netsuite/support/actions.rb +++ b/lib/netsuite/support/actions.rb @@ -48,6 +48,8 @@ def action(name) self.send(:include, NetSuite::Actions::Initialize::Support) when :attach self.send(:include, NetSuite::Actions::Attach::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..e99752324 --- /dev/null +++ b/spec/netsuite/actions/async_add_list_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' +require 'lib/netsuite/actions/async_add_list' + +describe NetSuite::Actions::AsyncAddList do + before { savon.mock! } + after { savon.unmock! } + + context 'Customers' do + context 'one customer' do + let(:customers) do + [ + NetSuite::Records::Customer.new(external_id: 'ext2', entity_id: 'Target', company_name: 'Target') + ] + end + + before do + savon.expects(:async_add_list).with(:message => + { + 'record' => [{ + 'listRel:entityId' => 'Target', + 'listRel:companyName' => 'Target', + '@xsi:type' => 'listRel:Customer', + '@externalId' => 'ext2' + }] + }).returns(File.read('spec/support/fixtures/async_add_list/async_add_list_response.xml')) + end + + it 'makes a valid request to the NetSuite API' do + NetSuite::Actions::AsyncAddList.call(customers) + end + + it 'returns a valid Response object' do + response = NetSuite::Actions::AsyncAddList.call(customers) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end + end + + context 'two customers' do + let(:customers) do + [ + NetSuite::Records::Customer.new(external_id: 'ext1', entity_id: 'Shutter Fly', company_name: 'Shutter Fly, Inc.'), + NetSuite::Records::Customer.new(external_id: 'ext2', entity_id: 'Target', company_name: 'Target') + ] + end + + before do + savon.expects(:async_add_list).with(:message => + { + 'record' => [{ + 'listRel:entityId' => 'Shutter Fly', + 'listRel:companyName' => 'Shutter Fly, Inc.', + '@xsi:type' => 'listRel:Customer', + '@externalId' => 'ext1' + }, + { + 'listRel:entityId' => 'Target', + 'listRel:companyName' => 'Target', + '@xsi:type' => 'listRel:Customer', + '@externalId' => 'ext2' + } + ] + }).returns(File.read('spec/support/fixtures/async_add_list/async_add_list_response.xml')) + end + + it 'makes a valid request to the NetSuite API' do + NetSuite::Actions::AsyncAddList.call(customers) + end + + it 'returns a valid Response object' do + response = NetSuite::Actions::AsyncAddList.call(customers) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end + end + end + + context 'with errors' do + let(:customers) do + [ + NetSuite::Records::Customer.new(external_id: 'ext1-bad', entity_id: 'Shutter Fly', company_name: 'Shutter Fly, Inc.'), + NetSuite::Records::Customer.new(external_id: 'ext2-bad', entity_id: 'Target', company_name: 'Target') + ] + end + + # before do + # savon.expects(:async_add_list).with(:message => + # { + # 'record' => [{ + # 'listRel:entityId' => 'Shutter Fly', + # 'listRel:companyName' => 'Shutter Fly, Inc.', + # '@xsi:type' => 'listRel:Customer', + # '@externalId' => 'ext1-bad' + # }, + # { + # 'listRel:entityId' => 'Target', + # 'listRel:companyName' => 'Target', + # '@xsi:type' => 'listRel:Customer', + # '@externalId' => 'ext2-bad' + # } + # ] + # }).returns(File.read('spec/support/fixtures/upsert_list/upsert_list_with_errors.xml')) + # end + + # it 'constructs error objects' do + # response = NetSuite::Actions::AsyncAddList.call(customers) + # expect(response.errors.keys).to match_array(['ext1', 'ext2']) + # expect(response.errors['ext1'].first.code).to eq('USER_ERROR') + # expect(response.errors['ext1'].first.message).to eq('Please enter value(s) for: Item') + # expect(response.errors['ext1'].first.type).to eq('ERROR') + # end + end +end diff --git a/spec/support/fixtures/async_add_list/async_add_list_response.xml b/spec/support/fixtures/async_add_list/async_add_list_response.xml new file mode 100644 index 000000000..9c2cca97e --- /dev/null +++ b/spec/support/fixtures/async_add_list/async_add_list_response.xml @@ -0,0 +1,17 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + ASYNCWEBSERVICES_563214_053120061943428686160042948_4bee0685 + pending + 0.0 + 0.0 + + + From 818663d406dfe0f8111801c2c425fec7d1579549 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Wed, 8 Mar 2023 08:54:19 -0600 Subject: [PATCH 51/62] Wrapping request body in array --- lib/netsuite/actions/async_add_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index 4f89e255e..543862f9c 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -13,7 +13,7 @@ def initialize(*objects) def request(credentials={}) NetSuite::Configuration.connection( {}, credentials - ).call(:async_add_list, message: request_body) + ).call(:async_add_list, message: [request_body]) end # From 18ef9113db220b3d5fe4afcc6c491c35b2d6f852 Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Thu, 9 Mar 2023 12:58:26 -0600 Subject: [PATCH 52/62] small changes on async_add_list method --- lib/netsuite/actions/async_add_list.rb | 46 ++++++-------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index 543862f9c..ca8d4c64f 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -13,7 +13,7 @@ def initialize(*objects) def request(credentials={}) NetSuite::Configuration.connection( {}, credentials - ).call(:async_add_list, message: [request_body]) + ).call(:async_add_list, message: request_body) end # @@ -49,7 +49,6 @@ def request_body end def response_hash - binding.pry @response_hash ||= Array[@response.body[:async_add_list_response][:async_status_result]] end @@ -58,7 +57,6 @@ def response_body end def response_errors - binding.pry if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } @response_errors ||= errors end @@ -78,44 +76,22 @@ def errors end def success? - #binding.pry response_hash[0][:job_id] end module Support - - def self.included(base) - base.extend(ClassMethods) - end - - module ClassMethods - def async_add_list(records, credentials = {}) - netsuite_records = records.map do |r| - if r.kind_of?(self) - r - else - self.new(r) - end - end - - response = NetSuite::Actions::AsyncAddList.call(netsuite_records, credentials) - - if response.success? - response.body.map do |attr| - record = netsuite_records.find do |r| - r.external_id == attr[:@external_id] - end - - record.instance_variable_set('@internal_id', attr[:@internal_id]) - end - - netsuite_records - - else - false - end + def async_add_list(credentials={}) + response = NetSuite::Actions::AsyncAddList.call([self], credentials) + @errors = response.errors + + if response.success? + response.body unless response.body.class == Nori::StringIOFile + true + else + false end end + end end end From f8c66676f3af56f3f81b24405f8fcdde6cfeafb1 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 10:41:17 -0600 Subject: [PATCH 53/62] Commenting out the code in the response_errors method --- lib/netsuite/actions/async_add_list.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index ca8d4c64f..ebccd3df5 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -57,9 +57,9 @@ def response_body end def response_errors - if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } - @response_errors ||= errors - end + # if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } + # @response_errors ||= errors + # end end def errors From 05dc0ccea7e355149f77b28bcac758c734a9b4f9 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 11:08:14 -0600 Subject: [PATCH 54/62] return raw response --- lib/netsuite/actions/async_add_list.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index ca8d4c64f..f72ccbf35 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -82,14 +82,15 @@ def success? module Support def async_add_list(credentials={}) response = NetSuite::Actions::AsyncAddList.call([self], credentials) - @errors = response.errors - - if response.success? - response.body unless response.body.class == Nori::StringIOFile - true - else - false - end + return response + # @errors = response.errors + + # if response.success? + # response.body unless response.body.class == Nori::StringIOFile + # true + # else + # false + # end end end From ce3954688b091cf889d8c425a9fbd99a6ba91bac Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 11:39:18 -0600 Subject: [PATCH 55/62] commenting out parsing of response --- lib/netsuite/actions/async_add_list.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index afb554684..ac8788b95 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -49,17 +49,17 @@ def request_body end def response_hash - @response_hash ||= Array[@response.body[:async_add_list_response][:async_status_result]] + @response_hash ||= response.body #Array[@response.body[:async_add_list_response][:async_status_result]] end def response_body - @response_body ||= response_hash.map { |h| h[:job_id] } + @response_body ||= response_hash #.map { |h| h[:job_id] } end def response_errors - # if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } - # @response_errors ||= errors - # end + if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } + @response_errors ||= errors + end end def errors From 6169b3e9c127d93c5d4adb3319d161edcd049c54 Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 11:55:40 -0600 Subject: [PATCH 56/62] making class variable --- lib/netsuite/actions/async_add_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index ac8788b95..b248d2405 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -49,7 +49,7 @@ def request_body end def response_hash - @response_hash ||= response.body #Array[@response.body[:async_add_list_response][:async_status_result]] + @response_hash ||= @response.body #Array[@response.body[:async_add_list_response][:async_status_result]] end def response_body From 718fd8b32f9e1aacad18276d06acd5f10132a5da Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 12:01:58 -0600 Subject: [PATCH 57/62] Backing up a step --- lib/netsuite/actions/async_add_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index ac8788b95..efe81fb25 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -49,7 +49,7 @@ def request_body end def response_hash - @response_hash ||= response.body #Array[@response.body[:async_add_list_response][:async_status_result]] + @response_hash ||= Array[@response.body[:async_add_list_response][:async_status_result]] end def response_body From b60e4c04341e828ff2c7f42c0fc65702e2d3b72b Mon Sep 17 00:00:00 2001 From: Mike Good Date: Fri, 10 Mar 2023 12:31:24 -0600 Subject: [PATCH 58/62] commenting out response_errors --- lib/netsuite/actions/async_add_list.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index ac8788b95..12d4a1c96 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -49,18 +49,18 @@ def request_body end def response_hash - @response_hash ||= response.body #Array[@response.body[:async_add_list_response][:async_status_result]] + @response_hash ||= Array[@response.body[:async_add_list_response][:async_status_result]] end def response_body @response_body ||= response_hash #.map { |h| h[:job_id] } end - def response_errors - if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } - @response_errors ||= errors - end - end + # def response_errors + # if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } + # @response_errors ||= errors + # end + # end def errors errors = response_hash.select { |h| h[:status] && h[:status][:status_detail] }.map do |obj| From 1248249488fa20823be46857cc96b95567dcce5e Mon Sep 17 00:00:00 2001 From: Daniel Barkley Date: Fri, 10 Mar 2023 13:04:45 -0600 Subject: [PATCH 59/62] simplify responses --- lib/netsuite/actions/async_add_list.rb | 33 +++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/netsuite/actions/async_add_list.rb b/lib/netsuite/actions/async_add_list.rb index 12d4a1c96..132d9c21d 100644 --- a/lib/netsuite/actions/async_add_list.rb +++ b/lib/netsuite/actions/async_add_list.rb @@ -56,27 +56,28 @@ def response_body @response_body ||= response_hash #.map { |h| h[:job_id] } end - # def response_errors - # if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } - # @response_errors ||= errors - # end - # end + def response_errors + @response_errors ||= response_hash unless success? + # if response_hash[0].any? { |h| h[:status] && h[:status][:status_detail] } + # @response_errors ||= errors + # end + end def errors - errors = response_hash.select { |h| h[:status] && h[:status][:status_detail] }.map do |obj| - error_obj = obj[:status][:status_detail] - error_obj = [error_obj] if error_obj.class == Hash - errors = error_obj.map do |error| - NetSuite::Error.new(error) - end - - [obj[:base_ref][:@external_id], errors] - end - Hash[errors] + # errors = response_hash.select { |h| h[:status] && h[:status][:status_detail] }.map do |obj| + # error_obj = obj[:status][:status_detail] + # error_obj = [error_obj] if error_obj.class == Hash + # errors = error_obj.map do |error| + # NetSuite::Error.new(error) + # end + + # [obj[:base_ref][:@external_id], errors] + # end + # Hash[errors] end def success? - response_hash[0][:job_id] + !response_hash[0][:job_id].nil? end module Support From 1d138f03bb2eef1deffc324cb124613a9839dc7f Mon Sep 17 00:00:00 2001 From: Mike Good Date: Tue, 11 Apr 2023 09:12:25 -0500 Subject: [PATCH 60/62] [CD-4737] Upgraded gems to resolve security vulnerabilities --- Gemfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 5f9f9197a..e1cecd98b 100644 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,12 @@ gem 'pry-rescue' gem 'pry' # optional dependency for more accurate timezone conversion -gem 'tzinfo', '1.2.5' +# gem 'tzinfo', '1.2.5' # gem 'tzinfo', '2.0.0' +gem 'tzinfo', '>= 1.2.10' # required for CircleCI to build properly with ruby 1.9.3 -gem 'json', '~> 1.8.3' -gem 'rack', '~> 1.6.4' +# gem 'json', '~> 1.8.3' +# gem 'rack', '~> 1.6.4' +gem 'json', '>= 2.3.0' +gem 'rack', '>= 2.1.4' \ No newline at end of file From 448348761f7df7355f423402874e8b8c85bb043b Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 15 Jan 2024 10:12:41 -0600 Subject: [PATCH 61/62] update-default-version-to-2018 2016 doesn't work --- lib/netsuite/configuration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 489248821..b1e9af1ee 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -101,7 +101,7 @@ def api_version(version = nil) if version self.api_version = version else - attributes[:api_version] ||= '2016_2' + attributes[:api_version] ||= '2018_2' end end From dd23ea9905b3aa50291e5459f25f6ee9d98f4426 Mon Sep 17 00:00:00 2001 From: tlepaylocity <150275748+tlepaylocity@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:49:42 -0700 Subject: [PATCH 62/62] CD-6394 add klass --- lib/netsuite/records/employee.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index 28b97bc9a..8933b230e 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -19,7 +19,7 @@ class Employee :phonetic_name, :purchase_order_approval_limit, :purchase_order_approver, :purchase_order_limit, :release_date, :resident_status, :salutation, :social_security_number, :visa_exp_date, :visa_type, :default_address - record_refs :currency, :department, :location, :subsidiary, :employee_type, :employee_status, :supervisor + record_refs :currency, :department, :location, :subsidiary, :employee_type, :employee_status, :supervisor, :klass field :custom_field_list, CustomFieldList field :addressbook_list, EmployeeAddressbookList