From a2f282df54501d63536cb6214574a81cfced3b19 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Mon, 26 Oct 2020 15:46:59 -0600 Subject: [PATCH 001/114] Adding missing cm fields --- lib/netsuite/records/credit_memo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/credit_memo.rb b/lib/netsuite/records/credit_memo.rb index b9999c869..d8134113f 100644 --- a/lib/netsuite/records/credit_memo.rb +++ b/lib/netsuite/records/credit_memo.rb @@ -17,7 +17,7 @@ class CreditMemo :sales_effective_date, :shipping_cost, :shipping_tax1_rate, :shipping_tax2_rate, :source, :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, - :vsoe_auto_calc + :vsoe_auto_calc, :tax_details_override, :tax_reg_override field :custom_field_list, CustomFieldList field :item_list, CreditMemoItemList From 180586ad6d4901b4ce2a2f0625561337ecd2847f Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 27 Oct 2020 09:18:14 -0600 Subject: [PATCH 002/114] Remove old ci gem requirements --- Gemfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index ba0ce65e2..49412b054 100644 --- a/Gemfile +++ b/Gemfile @@ -9,8 +9,4 @@ gem 'pry-rescue' # optional dependency for more accurate timezone conversion gem 'tzinfo', '1.2.5' -# gem 'tzinfo', '2.0.0' - -# required for CircleCI to build properly with ruby 1.9.3 -gem 'json', '~> 2.3.0' -gem 'rack', '~> 2.1.4' +# gem 'tzinfo', '2.0.0' \ No newline at end of file From aa535abdf77847e2a368122c6db522a3f19b50a7 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 27 Oct 2020 09:18:27 -0600 Subject: [PATCH 003/114] Bump bundler version on ci --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 664e435a9..99e44ca6a 100644 --- a/circle.yml +++ b/circle.yml @@ -3,7 +3,7 @@ version: 2.1 orbs: # orbs are basically bundles of pre-written build scripts that work for common cases # https://github.com/CircleCI-Public/ruby-orb - ruby: circleci/ruby@1.1 + ruby: circleci/ruby@1.1.2 jobs: # skipping build step because Gemfile.lock is not included in the source @@ -17,7 +17,7 @@ jobs: steps: - checkout - ruby/install-deps: - bundler-version: '1.17.2' + bundler-version: '2.1.4' with-cache: false - ruby/rspec-test From 2034db04e43892d3bab0f8057a99c61e27984b5f Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 27 Oct 2020 09:30:16 -0600 Subject: [PATCH 004/114] lets see if a custom bundle path fixes ci --- circle.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/circle.yml b/circle.yml index 99e44ca6a..6648825f6 100644 --- a/circle.yml +++ b/circle.yml @@ -19,6 +19,7 @@ jobs: - ruby/install-deps: bundler-version: '2.1.4' with-cache: false + path: './vendor/custom_bundle' - ruby/rspec-test # strangely, there seems to be very little documentation about exactly how martix builds work. From 9d740251fcd468b3a3f5ad254951ca4be14caad3 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 27 Oct 2020 16:21:10 -0600 Subject: [PATCH 005/114] Note about path workaround in ci --- circle.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/circle.yml b/circle.yml index 6648825f6..042e3561e 100644 --- a/circle.yml +++ b/circle.yml @@ -19,6 +19,8 @@ jobs: - ruby/install-deps: bundler-version: '2.1.4' with-cache: false + # without specifying a non-standard path `--deployment` will be used when running bundler + # which causes the bundler to fail path: './vendor/custom_bundle' - ruby/rspec-test From a3e7ba112a0c762b7c81ee1917447184c7127fdc Mon Sep 17 00:00:00 2001 From: stevenou Date: Wed, 2 Dec 2020 09:54:04 -0800 Subject: [PATCH 006/114] hack to make the search work --- lib/netsuite/records/purchase_order.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/purchase_order.rb b/lib/netsuite/records/purchase_order.rb index fe5c0d12d..71e296b6e 100644 --- a/lib/netsuite/records/purchase_order.rb +++ b/lib/netsuite/records/purchase_order.rb @@ -14,7 +14,7 @@ class PurchaseOrder :linked_tracking_numbers, :memo, :message, :other_ref_num, :ship_date, :ship_is_residential, :ship_to, :source, :status, :sub_total, :supervisor_approval, :tax2_total, :tax_total, :to_be_emailed, :to_be_faxed, :to_be_printed, - :total, :tracking_numbers, :tran_date, :tran_id, :vat_reg_num + :total, :tracking_numbers, :tran_date, :tran_id, :vat_reg_num, :line_unique_key, :item field :billing_address, Address field :shipping_address, Address From 8251ae413b5edb6d7b67bfaefe694933a5181666 Mon Sep 17 00:00:00 2001 From: stevenou Date: Mon, 14 Dec 2020 16:22:58 -0800 Subject: [PATCH 007/114] add CustomerPaymentCreditList --- lib/netsuite.rb | 2 ++ lib/netsuite/records/customer_payment.rb | 1 + .../records/customer_payment_credit.rb | 17 +++++++++++++ .../records/customer_payment_credit_list.rb | 12 +++++++++ .../customer_payment_credit_list_spec.rb | 25 +++++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 lib/netsuite/records/customer_payment_credit.rb create mode 100644 lib/netsuite/records/customer_payment_credit_list.rb create mode 100644 spec/netsuite/records/customer_payment_credit_list_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index b6bcba512..84d1b7b72 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -123,6 +123,8 @@ module Records autoload :CustomerPayment, 'netsuite/records/customer_payment' autoload :CustomerPaymentApply, 'netsuite/records/customer_payment_apply' autoload :CustomerPaymentApplyList, 'netsuite/records/customer_payment_apply_list' + autoload :CustomerPaymentCredit, 'netsuite/records/customer_payment_credit' + autoload :CustomerPaymentCreditList, 'netsuite/records/customer_payment_credit_list' autoload :CustomerPartner, 'netsuite/records/customer_partner' autoload :CustomerRefund, 'netsuite/records/customer_refund' autoload :CustomerRefundApply, 'netsuite/records/customer_refund_apply' diff --git a/lib/netsuite/records/customer_payment.rb b/lib/netsuite/records/customer_payment.rb index e6a4bb141..04383094a 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 :credit_list, CustomerPaymentCreditList read_only_fields :applied, :balance, :pending, :total, :unapplied diff --git a/lib/netsuite/records/customer_payment_credit.rb b/lib/netsuite/records/customer_payment_credit.rb new file mode 100644 index 000000000..0386d40fe --- /dev/null +++ b/lib/netsuite/records/customer_payment_credit.rb @@ -0,0 +1,17 @@ +module NetSuite + module Records + class CustomerPaymentCredit + include Support::Fields + include Support::Records + include Namespaces::TranCust + + fields :amount, :applied_to, :apply, :credit_date, :currency, :doc, :due, :line, + :ref_num, :total, :type + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + + end + end +end diff --git a/lib/netsuite/records/customer_payment_credit_list.rb b/lib/netsuite/records/customer_payment_credit_list.rb new file mode 100644 index 000000000..d8181179c --- /dev/null +++ b/lib/netsuite/records/customer_payment_credit_list.rb @@ -0,0 +1,12 @@ +module NetSuite + module Records + class CustomerPaymentCreditList < Support::Sublist + include Namespaces::TranCust + + sublist :credit, CustomerPaymentCredit + + alias :credits :credit + + end + end +end diff --git a/spec/netsuite/records/customer_payment_credit_list_spec.rb b/spec/netsuite/records/customer_payment_credit_list_spec.rb new file mode 100644 index 000000000..7d3d1c260 --- /dev/null +++ b/spec/netsuite/records/customer_payment_credit_list_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe NetSuite::Records::CustomerPaymentCreditList do + let(:list) { NetSuite::Records::CustomerPaymentCreditList.new } + let(:apply) { NetSuite::Records::CustomerPaymentCredit.new } + + it 'can have credits be added to it' do + list.credits << credit + credit_list = list.credits + expect(credit_list).to be_kind_of(Array) + expect(credit_list.length).to eql(1) + credit_list.each { |i| expect(i).to be_kind_of(NetSuite::Records::CustomerPaymentCredit) } + end + + describe '#to_record' do + it 'can represent itself as a SOAP record' do + record = { + 'tranCust:credit' => [{},{}] + } + list.credits.concat([credit,credit]) + expect(list.to_record).to eql(record) + end + end + +end From 776dc1b90ed30edb4e2f7ade535e69aa80a0a537 Mon Sep 17 00:00:00 2001 From: stevenou Date: Mon, 14 Dec 2020 16:28:16 -0800 Subject: [PATCH 008/114] spacing. revert the PO change --- lib/netsuite/records/customer_payment.rb | 2 +- lib/netsuite/records/purchase_order.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/records/customer_payment.rb b/lib/netsuite/records/customer_payment.rb index 04383094a..7432f3581 100644 --- a/lib/netsuite/records/customer_payment.rb +++ b/lib/netsuite/records/customer_payment.rb @@ -17,7 +17,7 @@ class CustomerPayment field :custom_field_list, CustomFieldList field :apply_list, CustomerPaymentApplyList - field :credit_list, CustomerPaymentCreditList + field :credit_list, CustomerPaymentCreditList read_only_fields :applied, :balance, :pending, :total, :unapplied diff --git a/lib/netsuite/records/purchase_order.rb b/lib/netsuite/records/purchase_order.rb index 71e296b6e..fe5c0d12d 100644 --- a/lib/netsuite/records/purchase_order.rb +++ b/lib/netsuite/records/purchase_order.rb @@ -14,7 +14,7 @@ class PurchaseOrder :linked_tracking_numbers, :memo, :message, :other_ref_num, :ship_date, :ship_is_residential, :ship_to, :source, :status, :sub_total, :supervisor_approval, :tax2_total, :tax_total, :to_be_emailed, :to_be_faxed, :to_be_printed, - :total, :tracking_numbers, :tran_date, :tran_id, :vat_reg_num, :line_unique_key, :item + :total, :tracking_numbers, :tran_date, :tran_id, :vat_reg_num field :billing_address, Address field :shipping_address, Address From 31236bc5a9fed3793a62d94512321aaafe0e7639 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 15 Dec 2020 06:54:10 -0700 Subject: [PATCH 009/114] Fixing customer payment credit specs --- spec/netsuite/records/customer_payment_credit_list_spec.rb | 6 ++++-- spec/netsuite/records/customer_payment_spec.rb | 5 ----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/spec/netsuite/records/customer_payment_credit_list_spec.rb b/spec/netsuite/records/customer_payment_credit_list_spec.rb index 7d3d1c260..4d14d1fff 100644 --- a/spec/netsuite/records/customer_payment_credit_list_spec.rb +++ b/spec/netsuite/records/customer_payment_credit_list_spec.rb @@ -5,8 +5,9 @@ let(:apply) { NetSuite::Records::CustomerPaymentCredit.new } it 'can have credits be added to it' do - list.credits << credit + list.credits << apply credit_list = list.credits + expect(credit_list).to be_kind_of(Array) expect(credit_list.length).to eql(1) credit_list.each { |i| expect(i).to be_kind_of(NetSuite::Records::CustomerPaymentCredit) } @@ -17,7 +18,8 @@ record = { 'tranCust:credit' => [{},{}] } - list.credits.concat([credit,credit]) + + list.credits.concat([apply, apply]) expect(list.to_record).to eql(record) end end diff --git a/spec/netsuite/records/customer_payment_spec.rb b/spec/netsuite/records/customer_payment_spec.rb index 561e7477f..ba18a6c09 100644 --- a/spec/netsuite/records/customer_payment_spec.rb +++ b/spec/netsuite/records/customer_payment_spec.rb @@ -49,11 +49,6 @@ it 'can be set from a CustomerPaymentApplyList object' end - describe '#credit_list' do - it 'can be set from attributes' - it 'can be set from a CustomerPaymentCreditList object' - end - describe '#deposit_list' do it 'can be set from attributes' it 'can be set from a CustomerPaymentDepositList object' From dfab101dfd06fa614c0f1bdf4f77142afc8d959c Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 15 Dec 2020 06:54:30 -0700 Subject: [PATCH 010/114] Adding customer payment to basic specs --- spec/netsuite/records/basic_record_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/netsuite/records/basic_record_spec.rb b/spec/netsuite/records/basic_record_spec.rb index 8a437fbda..3504538a1 100644 --- a/spec/netsuite/records/basic_record_spec.rb +++ b/spec/netsuite/records/basic_record_spec.rb @@ -61,6 +61,7 @@ NetSuite::Records::BinTransfer, NetSuite::Records::SerializedAssemblyItem, NetSuite::Records::CustomerStatus, + NetSuite::Records::CustomerPayment, NetSuite::Records::TransactionBodyCustomField, NetSuite::Records::TransactionColumnCustomField, NetSuite::Records::EntityCustomField From a268423089eb35e13a532c2d3a614588e8761c9e Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 21 Jan 2021 11:42:10 -0500 Subject: [PATCH 011/114] Add upsert_list and get_deleted actions for contact record --- lib/netsuite/records/contact.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/contact.rb b/lib/netsuite/records/contact.rb index 2934453f0..c107311ca 100644 --- a/lib/netsuite/records/contact.rb +++ b/lib/netsuite/records/contact.rb @@ -7,7 +7,7 @@ class Contact include Support::Actions include Namespaces::ListRel - actions :get, :get_list, :add, :delete, :delete_list, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :delete_list, :search, :update, :upsert, :upsert_list fields :salutation, :first_name, :middle_name, :last_name, :title, :phone, :fax, :email, :default_address, :entity_id, :phonetic_name, :alt_email, :office_phone, :home_phone, :mobile_phone, :supervisor_phone, From 438c233fc0ede0acbeb7f9fbe8c9d8004fb4654a Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Wed, 13 Jan 2021 19:46:36 -0500 Subject: [PATCH 012/114] Update fields/record refs on partner record to match 2020.2 schema --- lib/netsuite/records/partner.rb | 12 +++++++----- spec/netsuite/records/partner_spec.rb | 10 ++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/netsuite/records/partner.rb b/lib/netsuite/records/partner.rb index 58232e3a9..b03e1c659 100644 --- a/lib/netsuite/records/partner.rb +++ b/lib/netsuite/records/partner.rb @@ -8,15 +8,17 @@ class Partner include Support::RecordRefs include Namespaces::ListRel - # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/partner.html + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_2/schema/record/partner.html actions :get, :get_list, :add, :update, :upsert, :upsert_list, :delete, :search - fields :phone, :home_phone, :first_name, :last_name, :alt_name, :is_inactive, :email, :give_access, - :partner_code, :is_person, :company_name, :eligible_for_commission, :entity_id, :last_modified_date, - :date_created, :title, :mobile_phone, :comments, :middle_name, :send_email, :password, :password2 + fields :alt_email, :alt_name, :bcn, :comments, :company_name, :date_created, :default_address, + :eligible_for_commission, :email, :entity_id, :fax, :first_name, :give_access, :home_phone, :is_inactive, + :is_person, :last_modified_date, :last_name, :login_as, :middle_name, :mobile_phone, :partner_code, + :password, :password2, :phone, :phonetic_name, :print_on_check_as, :referring_url, :require_pwd_change, + :salutation, :send_email, :sub_partner_login, :tax_id_num, :title, :url, :vat_reg_number - record_refs :klass, :access_role, :department, :subsidiary + record_refs :access_role, :klass, :custom_form, :default_tax_reg, :department, :image, :location, :parent, :subsidiary attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/partner_spec.rb b/spec/netsuite/records/partner_spec.rb index 197a2ef54..e8806c38e 100644 --- a/spec/netsuite/records/partner_spec.rb +++ b/spec/netsuite/records/partner_spec.rb @@ -5,9 +5,11 @@ it 'has all the right fields' do [ - :phone, :home_phone, :first_name, :last_name, :alt_name, :is_inactive, :email, :give_access, - :partner_code, :is_person, :company_name, :eligible_for_commission, :entity_id, :last_modified_date, - :date_created, :title, :mobile_phone, :comments, :middle_name, :send_email, :password, :password2 + :alt_email, :alt_name, :bcn, :comments, :company_name, :date_created, :default_address, + :eligible_for_commission, :email, :entity_id, :fax, :first_name, :give_access, :home_phone, :is_inactive, + :is_person, :last_modified_date, :last_name, :login_as, :middle_name, :mobile_phone, :partner_code, + :password, :password2, :phone, :phonetic_name, :print_on_check_as, :referring_url, :require_pwd_change, + :salutation, :send_email, :sub_partner_login, :tax_id_num, :title, :url, :vat_reg_number ].each do |field| expect(partner).to have_field(field) end @@ -15,7 +17,7 @@ it 'has all the right record refs' do [ - :klass, :access_role, :department, :subsidiary + :access_role, :klass, :custom_form, :default_tax_reg, :department, :image, :location, :parent, :subsidiary ].each do |record_ref| expect(partner).to have_record_ref(record_ref) end From 776eebbf783dd21adf4e78758e9ed16abd5842ba Mon Sep 17 00:00:00 2001 From: David Laprade Date: Tue, 23 Feb 2021 15:06:26 -0500 Subject: [PATCH 013/114] Add payment_option --- lib/netsuite/records/customer_deposit.rb | 10 +++++----- lib/netsuite/records/customer_payment.rb | 6 ++++-- spec/netsuite/records/customer_payment_spec.rb | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/netsuite/records/customer_deposit.rb b/lib/netsuite/records/customer_deposit.rb index 0503300c9..089627b35 100644 --- a/lib/netsuite/records/customer_deposit.rb +++ b/lib/netsuite/records/customer_deposit.rb @@ -21,11 +21,11 @@ class CustomerDeposit field :apply_list, CustomerDepositApplyList # accountingBookDetailList - record_refs :customer, :sales_order, :account, :department, :payment_method, - :custom_form, :currency, :posting_period, :subsidiary, :location, - - # only available in an advanced search result - :deposit_transaction + record_refs :customer, :sales_order, :account, :department, + :payment_method, :payment_option, :custom_form, :currency, + :posting_period, :subsidiary, :location, + # only available in an advanced search result + :deposit_transaction attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/customer_payment.rb b/lib/netsuite/records/customer_payment.rb index 7432f3581..e2fef1996 100644 --- a/lib/netsuite/records/customer_payment.rb +++ b/lib/netsuite/records/customer_payment.rb @@ -21,8 +21,10 @@ class CustomerPayment read_only_fields :applied, :balance, :pending, :total, :unapplied - record_refs :account, :ar_acct, :credit_card, :credit_card_processor, :custom_form, :customer, :department, :klass, - :location, :payment_method, :posting_period, :subsidiary, :currency + record_refs :account, :ar_acct, :credit_card, :credit_card_processor, + :custom_form, :customer, :department, :klass, :location, + :payment_method, :payment_option, :posting_period, :subsidiary, + :currency attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/customer_payment_spec.rb b/spec/netsuite/records/customer_payment_spec.rb index ba18a6c09..3be6c38c1 100644 --- a/spec/netsuite/records/customer_payment_spec.rb +++ b/spec/netsuite/records/customer_payment_spec.rb @@ -18,7 +18,7 @@ it 'has all the right record refs' do [ - :account, :ar_acct, :credit_card, :credit_card_processor, :custom_form, :customer, :department, :klass, :location, :payment_method, :posting_period, :subsidiary + :account, :ar_acct, :credit_card, :credit_card_processor, :custom_form, :customer, :department, :klass, :location, :payment_method, :payment_option, :posting_period, :subsidiary ].each do |record_ref| expect(payment).to have_record_ref(record_ref) end From 05bc88315f2bf7a6a0735c0c5110812c9c754413 Mon Sep 17 00:00:00 2001 From: stevenou Date: Fri, 18 Dec 2020 10:50:57 -0800 Subject: [PATCH 014/114] add required record_refs for revenue recognition module --- lib/netsuite/records/inventory_item.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index af8165e5e..ef91feaff 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -51,7 +51,8 @@ class InventoryItem :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, - :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor + :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor, :create_revenue_plans_on, + :revenue_recognition_rule, :rev_rec_forecast_rule field :pricing_matrix, PricingMatrix field :custom_field_list, CustomFieldList From 75bac9dd487dd7080cfa722eff7673dbcca08d3a Mon Sep 17 00:00:00 2001 From: David Laprade Date: Mon, 1 Mar 2021 15:41:01 -0500 Subject: [PATCH 015/114] Optionally override the Savon wsdl endpoint --- lib/netsuite/configuration.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 89ebb4d66..936cbb247 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -17,6 +17,7 @@ def attributes def connection(params={}, credentials={}) client = Savon.client({ wsdl: cached_wsdl || wsdl, + endpoint: endpoint, read_timeout: read_timeout, open_timeout: open_timeout, namespaces: namespaces, @@ -94,6 +95,18 @@ def api_version=(version) attributes[:api_version] = version end + def endpoint=(endpoint) + attributes[:endpoint] = endpoint + end + + def endpoint(endpoint=nil) + if endpoint + self.endpoint = endpoint + else + attributes[:endpoint] + end + end + def sandbox=(flag) if attributes[:sandbox] != flag attributes[:wsdl] = nil From 41afd805949e08c1a4089ed181e065ed7c335e9c Mon Sep 17 00:00:00 2001 From: David Laprade Date: Mon, 1 Mar 2021 16:17:27 -0500 Subject: [PATCH 016/114] Add tests --- spec/netsuite/configuration_spec.rb | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/netsuite/configuration_spec.rb b/spec/netsuite/configuration_spec.rb index 7b48a0c6f..a6d0920fe 100644 --- a/spec/netsuite/configuration_spec.rb +++ b/spec/netsuite/configuration_spec.rb @@ -29,10 +29,12 @@ end describe '#connection' do + EXAMPLE_ENDPOINT = 'https://1023.suitetalk.api.netsuite.com/services/NetSuitePort_2020_2' before(:each) do # reset clears out the password info config.email 'me@example.com' config.password 'me@example.com' + config.endpoint EXAMPLE_ENDPOINT config.account 1023 config.wsdl "my_wsdl" config.api_version "2012_2" @@ -57,6 +59,19 @@ expect(config).to have_received(:cached_wsdl) end + + it 'sets the endpoint on the Savon client' do + # this is ugly/brittle, but it's hard to see how else to test this + savon_configs = config.connection.globals.instance_eval {@options} + expect(savon_configs.fetch(:endpoint)).to eq(EXAMPLE_ENDPOINT) + end + + it 'handles a nil endpoint' do + config.endpoint = nil + # this is ugly/brittle, but it's hard to see how else to test this + savon_configs = config.connection.globals.instance_eval {@options} + expect(savon_configs.fetch(:endpoint)).to eq(nil) + end end describe '#wsdl' do @@ -166,6 +181,23 @@ end end + describe '#endpoint' do + it 'can be set with endpoint=' do + config.endpoint = 42 + expect(config.endpoint).to eq(42) + end + + it 'can be set with just endpoint(value)' do + config.endpoint(42) + expect(config.endpoint).to eq(42) + end + + it 'supports nil endpoints' do + config.endpoint = nil + expect(config.endpoint).to eq(nil) + end + end + describe '#auth_header' do context 'when doing user authentication' do before do From 4585f421467e0d87212554499250f17732abd6d5 Mon Sep 17 00:00:00 2001 From: Steven Ou Date: Tue, 23 Mar 2021 20:41:10 -0700 Subject: [PATCH 017/114] Accounting period closed (#474) * hack to make the search work * add CustomerPaymentCreditList * spacing. revert the PO change * closed field * add search_joins to accounting_period * hack to make the search work * add CustomerPaymentCreditList * spacing. revert the PO change * closed field * add search_joins to accounting_period Co-authored-by: stevenou --- lib/netsuite/records/accounting_period.rb | 4 ++-- spec/netsuite/records/customer_payment_credit_list_spec.rb | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/netsuite/records/accounting_period.rb b/lib/netsuite/records/accounting_period.rb index 5dd04b346..74a240a15 100644 --- a/lib/netsuite/records/accounting_period.rb +++ b/lib/netsuite/records/accounting_period.rb @@ -8,12 +8,12 @@ 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, :closed record_refs :parent attr_reader :internal_id - attr_accessor :external_id + attr_accessor :external_id, :search_joins def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) diff --git a/spec/netsuite/records/customer_payment_credit_list_spec.rb b/spec/netsuite/records/customer_payment_credit_list_spec.rb index 4d14d1fff..bdc3c5aa6 100644 --- a/spec/netsuite/records/customer_payment_credit_list_spec.rb +++ b/spec/netsuite/records/customer_payment_credit_list_spec.rb @@ -7,7 +7,6 @@ it 'can have credits be added to it' do list.credits << apply credit_list = list.credits - expect(credit_list).to be_kind_of(Array) expect(credit_list.length).to eql(1) credit_list.each { |i| expect(i).to be_kind_of(NetSuite::Records::CustomerPaymentCredit) } From 82bf41e1e911e2752ca1a4caaa2e7da28aa7f1da Mon Sep 17 00:00:00 2001 From: eugentravod <67692013+eugentravod@users.noreply.github.com> Date: Tue, 27 Apr 2021 19:26:06 +0300 Subject: [PATCH 018/114] Added vendor currecy list to vendor (#475) Co-authored-by: Eugen Torica --- lib/netsuite.rb | 2 ++ lib/netsuite/records/vendor.rb | 3 ++- lib/netsuite/records/vendor_currency.rb | 26 ++++++++++++++++++++ lib/netsuite/records/vendor_currency_list.rb | 9 +++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 lib/netsuite/records/vendor_currency.rb create mode 100644 lib/netsuite/records/vendor_currency_list.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 84d1b7b72..09aca5c8b 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -299,6 +299,8 @@ module Records autoload :VendorCreditItemList, 'netsuite/records/vendor_credit_item_list' autoload :VendorCreditExpense, 'netsuite/records/vendor_credit_expense' autoload :VendorCreditExpenseList, 'netsuite/records/vendor_credit_expense_list' + autoload :VendorCurrencyList, 'netsuite/records/vendor_currency_list' + autoload :VendorCurrency, 'netsuite/records/vendor_currency' autoload :VendorReturnAuthorization, 'netsuite/records/vendor_return_authorization' autoload :VendorReturnAuthorizationItem, 'netsuite/records/vendor_return_authorization_item' autoload :VendorReturnAuthorizationItemList, 'netsuite/records/vendor_return_authorization_item_list' diff --git a/lib/netsuite/records/vendor.rb b/lib/netsuite/records/vendor.rb index e1491c6b1..9c264ab76 100644 --- a/lib/netsuite/records/vendor.rb +++ b/lib/netsuite/records/vendor.rb @@ -11,7 +11,7 @@ class Vendor fields :account_number, :alt_email, :alt_name, :alt_phone, :balance, :balance_primary, :bcn, :bill_pay, :comments, :company_name, :credit_limit, - :currency_list, :date_created, :default_address, :eligible_for_commission, + :date_created, :default_address, :eligible_for_commission, :email, :email_preference, :email_transactions, :entity_id, :fax, :fax_transactions, :first_name, :give_access, :global_subscription_status, :home_phone, :is1099_eligible, :is_accountant, :is_inactive, :is_job_resource_vend, :is_person, :labor_cost, @@ -22,6 +22,7 @@ class Vendor :url, :vat_reg_number field :custom_field_list, CustomFieldList + field :currency_list, VendorCurrencyList # TODO should change name to VendorAddressBookList field :addressbook_list, CustomerAddressbookList diff --git a/lib/netsuite/records/vendor_currency.rb b/lib/netsuite/records/vendor_currency.rb new file mode 100644 index 000000000..9790d1a51 --- /dev/null +++ b/lib/netsuite/records/vendor_currency.rb @@ -0,0 +1,26 @@ +module NetSuite + module Records + class VendorCurrency + include Support::Fields + include Support::RecordRefs + include Support::Records + include Namespaces::ListRel + + fields :balance, :consol_balance, :consol_deposit_balance, :consol_overdue_balance, + :consol_unbilled_orders, :deposit_balance, :display_symbol, :overdue_balance, + :override_currency_format, :symbol_placement, :unbilled_orders + + record_refs :currency + + 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 + + end + end +end diff --git a/lib/netsuite/records/vendor_currency_list.rb b/lib/netsuite/records/vendor_currency_list.rb new file mode 100644 index 000000000..cc9dde1fa --- /dev/null +++ b/lib/netsuite/records/vendor_currency_list.rb @@ -0,0 +1,9 @@ +module NetSuite + module Records + class VendorCurrencyList < Support::Sublist + include Namespaces::ListRel + + sublist :vendor_currency, NetSuite::Records::VendorCurrency + end + end +end From c681ef1d2391666cae199bfaa8e679d52439af0e Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 27 Apr 2021 10:57:19 -0600 Subject: [PATCH 019/114] Fixed vendor test, expanded sublist test on records --- spec/netsuite/records/basic_record_spec.rb | 8 +++++++- spec/netsuite/records/vendor_spec.rb | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/netsuite/records/basic_record_spec.rb b/spec/netsuite/records/basic_record_spec.rb index 3504538a1..887eba201 100644 --- a/spec/netsuite/records/basic_record_spec.rb +++ b/spec/netsuite/records/basic_record_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe 'basic records' do + # all records with internal IDs should be added to this list let(:basic_record_list) { [ NetSuite::Records::Currency, @@ -49,6 +50,7 @@ NetSuite::Records::SerializedInventoryItem, NetSuite::Records::DepositApplication, NetSuite::Records::InventoryAdjustment, + NetSuite::Records::Vendor, NetSuite::Records::VendorReturnAuthorization, NetSuite::Records::AssemblyBuild, NetSuite::Records::AssemblyUnbuild, @@ -109,8 +111,12 @@ if !sublist_fields.empty? sublist_fields.each do |sublist_field| + sublist = record_instance.send(sublist_field) + # TODO make a sublist entry with some fields valid for that sublist item - record_instance.send(sublist_field) << {} + sublist << {} + + expect(sublist.send(sublist.sublist_key).count).to be(1) end end diff --git a/spec/netsuite/records/vendor_spec.rb b/spec/netsuite/records/vendor_spec.rb index 7bc647992..c0e5c75fe 100644 --- a/spec/netsuite/records/vendor_spec.rb +++ b/spec/netsuite/records/vendor_spec.rb @@ -7,7 +7,7 @@ [ :account_number, :alt_email, :alt_name, :alt_phone, :balance, :balance_primary, :bcn, :bill_pay, :comments, :company_name, :credit_limit, - :currency_list, :date_created, :default_address, :eligible_for_commission, + :date_created, :default_address, :eligible_for_commission, :email, :email_preference, :email_transactions, :entity_id, :fax, :fax_transactions, :first_name, :give_access, :global_subscription_status, :home_phone, :is1099_eligible, :is_accountant, :is_inactive, :is_job_resource_vend, :is_person, :labor_cost, From 7b77099f10b3c60baaa26437acf7b3d27c3db2c4 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 12 May 2021 11:19:34 -0600 Subject: [PATCH 020/114] Bumping dev ruby version to 2.7, adding asdf --- .ruby-version | 2 +- .tool-versions | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .tool-versions diff --git a/.ruby-version b/.ruby-version index 338a5b5d8..2c9b4ef42 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.6 +2.7.3 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000..fde9f5b71 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 2.7.3 \ No newline at end of file From 5c5b99c66b00f2efcd3d8c401cff84f80d44eb0d Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 12 May 2021 11:49:14 -0600 Subject: [PATCH 021/114] Big readme update --- README.md | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 672fb4241..b4bbaa356 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [NetSuite SuiteTalk API Ruby Gem](#netsuite-suitetalk-api-ruby-gem) - [Help & Support](#help--support) @@ -13,7 +13,6 @@ - [Custom Records & Fields](#custom-records--fields) - [Searching](#searching) - [Non-standard Operations](#non-standard-operations) -- [About SuiteSync](#about-suitesync) @@ -24,24 +23,23 @@ # NetSuite SuiteTalk API Ruby Gem * This gem will act as a wrapper around the NetSuite SuiteTalk WebServices API. -* The gem does not cover the entire API, only the subset contributors have used so far. -* NetSuite is a complex system. There's a lot to learn and sparse resources available to learn from. Here's a list of [NetSuite Development Resources](https://github.com/NetSweet/netsuite/wiki/NetSuite-Development-Resources) that might make things a bit less painful. +* The gem does not cover the entire API, only the subset contributors have used so far. Please submit a PR for any functionality that's missing! +* NetSuite is a complex system. There's a lot to learn and sparse resources available to learn from. Here's a list of [NetSuite Development Resources](https://github.com/NetSweet/netsuite/wiki/NetSuite-Development-Resources). # Help & Support Join the [slack channel](http://opensuite-slackin.herokuapp.com) for help with any NetSuite issues. Please do not post usage questions as issues in GitHub. -Messages in the Slack ground are [archived here](https://suitechat.slackarchive.io). Search the archives to see if your question has been answered before. - There is some additional helpful resources for NetSuite development [listed here](https://dashboard.suitesync.io/docs/resources#netsuite). # Testing Before contributing a patch make sure all existing tests pass. -``` +```shell git clone git://github.com/NetSweet/netsuite.git cd netsuite + bundle bundle exec rspec ``` @@ -56,28 +54,44 @@ gem 'netsuite' If you'd like more accurate time conversion support, include the `tzinfo` gem. -This gem is built for ruby 1.9.x+, checkout the [1-8-stable](https://github.com/NetSweet/netsuite/tree/1-8-stable) branch for ruby 1.8.x support. +This gem is built for ruby 2.6.x+, but should work on older versions down to 1.9. There's a [1-8-stable](https://github.com/NetSweet/netsuite/tree/1-8-stable) branch for ruby 1.8.x support. ## Configuration The most important thing you'll need is your NetSuite account ID. Not sure how to find your account id? [Here's a guide.](http://mikebian.co/find-netsuite-web-services-account-number/) -For most use-cases, the following configuration will be sufficient: +How you connect to NetSuite has changed a lot over the years and differs between API versions. For instance: + +* Older API versions (~2015) allowed authentication via username and password +* Newever API versions (> 2016) still allowed for username and password authentication, but required an application ID +* "OAuth", which requires four separate keys to be manually generated, was supported sometime after 2015 +* API versions greater than 2018_2 require `endpoint` to be set directly ([more info](https://github.com/NetSweet/netsuite/pull/473)) + +Here's an example connection configuration. You don't want to actually use username + password config; token based authentication is detailed below in a separate section: ```ruby NetSuite.configure do reset! + # production & sandbox account numbers will differ account 'TSTDRV1576318' api_version '2018_2' + # password-based login information + # in most cases you should use token based authentication instead email 'email@example.com' password 'password' role 10 - # use `NetSuite::Utilities.data_center_url('TSTDRV1576318')` to retrieve the URL + # recent API versions require a account-specific endpoint o be set + # use `NetSuite::Utilities.data_center_url('TSTDRV1576318')` to retrieve wsdl URL # you'll want to do this in a background process and strip the protocol out of the return string wsdl_domain 'tstdrv1576318.suitetalk.api.netsuite.com' + + # the endpoint indicated in the > 2018_2 wsdl is invalid + # you must set the endpoint directly + # https://github.com/NetSweet/netsuite/pull/473 + endpoint "#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` @@ -115,6 +129,7 @@ NetSuite.configure do # log_level :debug # password-based login information + # in most cases you should use token based authentication instead email 'email@domain.com' password 'password' account '12345' @@ -127,9 +142,9 @@ NetSuite.configure do end ``` -If you'd like to use a API endpoints greater than 2015_1 you'll need to specify an application ID: +If are using username + password authentication (which you shouldn't be!) *and* you'd like to use a API endpoints greater than 2015_1 you'll need to specify an application ID: -``` +```ruby NetSuite::Configuration.soap_header = { 'platformMsgs:ApplicationInfo' => { 'platformMsgs:applicationId' => 'your-netsuite-app-id' @@ -139,7 +154,7 @@ NetSuite::Configuration.soap_header = { ### Token based Authentication -OAuth credentials are also supported. [Learn more about how to set up token based authentication here](http://mikebian.co/using-netsuites-token-based-authentication-with-suitetalk/). +OAuth credentials are supported and the recommended authentication approach. [Learn more about how to set up token based authentication here](http://mikebian.co/using-netsuites-token-based-authentication-with-suitetalk/). ```ruby NetSuite.configure do @@ -154,6 +169,11 @@ NetSuite.configure do # oauth does not work with API versions less than 2015_2 api_version '2016_2' + + # the endpoint indicated in the > 2018_2 wsdl is invalid + # you must set the endpoint directly + # https://github.com/NetSweet/netsuite/pull/473 + endpoint "#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` @@ -593,7 +613,3 @@ states = NetSuite::Configuration.connection.call(:get_all, message: { }) states.to_array.first[:get_all_response][:get_all_result][:record_list][:record].map { |r| { country: r[:country], abbr: r[:shortname], name: r[:full_name] } } ``` - -# About SuiteSync - -[SuiteSync, the Stripe-NetSuite integration](http://suitesync.io) uses this gem and funds the majority of it's development and maintenance. From e087d2923bb4de7db146434e099d141ffb815978 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 12 May 2021 11:49:22 -0600 Subject: [PATCH 022/114] Version bump --- lib/netsuite/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index 438623e3c..3f0ac2a4b 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.6' + VERSION = '0.8.7' end From 33594f42f0e4f5155f2b426e516c16deda4c50fd Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 25 May 2021 16:20:58 -0400 Subject: [PATCH 023/114] Include protocol in readme examples setting endpoint from wsdl_domain (#477) The `wsdl_domain` is just a domain/hostname, no protocol, however `endpoint` expects to include a protocol, so when you're buliding the `endpoint` from the `wsdl_domain`, you need to prefix it with a protocol. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b4bbaa356..2aac83ee7 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ NetSuite.configure do # the endpoint indicated in the > 2018_2 wsdl is invalid # you must set the endpoint directly # https://github.com/NetSweet/netsuite/pull/473 - endpoint "#{wsdl_domain}/services/NetSuitePort_#{api_version}" + endpoint "https://#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` @@ -173,7 +173,7 @@ NetSuite.configure do # the endpoint indicated in the > 2018_2 wsdl is invalid # you must set the endpoint directly # https://github.com/NetSweet/netsuite/pull/473 - endpoint "#{wsdl_domain}/services/NetSuitePort_#{api_version}" + endpoint "https://#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` From ece6f61fbf0392f0b449e235def57ef78b98d03f Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sun, 30 May 2021 20:45:07 -0400 Subject: [PATCH 024/114] Properly extract external_id from advanced search results (#478) If you performed an advanced search specifying which columns to return and included externalId, you wouldn't be able to get the external_id from the resulting record via the usual external_id method. This now matches how internal_id is extracted. Prior to this, calls to external_id returned: ``` > record.external_id => {:@external_id=>"customer_1"} ``` Now, it returns: ``` > record.external_id => "customer_1" ``` --- lib/netsuite/support/search_result.rb | 4 ++++ spec/netsuite/actions/search_spec.rb | 2 ++ .../search/saved_search_joined_custom_customer.xml | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index 901c46edf..bd7071a18 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -89,6 +89,10 @@ def initialize(response, result_class, credentials) record[:basic][:internal_id] = record[:basic][:internal_id][:@internal_id] end + if record[:basic][:external_id] + record[:basic][:external_id] = record[:basic][:external_id][:@external_id] + end + result_wrapper = result_class.new(record.delete(:basic)) result_wrapper.search_joins = record results << result_wrapper diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index a3cbfea04..2f0abbec4 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -168,6 +168,8 @@ expect(search.results.size).to eq(2) expect(search.current_page).to eq(1) + expect(search.results.first.internal_id).to eq('123') + expect(search.results.first.external_id).to eq('456') expect(search.results.first.alt_name).to eq('A Awesome Name') expect(search.results.last.email).to eq('alessawesome@gmail.com') end diff --git a/spec/support/fixtures/search/saved_search_joined_custom_customer.xml b/spec/support/fixtures/search/saved_search_joined_custom_customer.xml index 490270e97..68b3fa4d5 100644 --- a/spec/support/fixtures/search/saved_search_joined_custom_customer.xml +++ b/spec/support/fixtures/search/saved_search_joined_custom_customer.xml @@ -16,6 +16,12 @@ + + + + + + A Awesome Name @@ -84,4 +90,4 @@ - \ No newline at end of file + From 7ac030ee8afe49a472080077db2bfc39b26abbef Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sun, 30 May 2021 20:45:24 -0400 Subject: [PATCH 025/114] Update readme for including custom fields in search result columns for API 2013.2 and newer (#479) These newer API versions expect the field to be identified by it's scriptId, not internalId. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2aac83ee7..2549b8d4c 100644 --- a/README.md +++ b/README.md @@ -435,7 +435,9 @@ NetSuite::Records::SalesOrder.search({ 'tranSales:itemJoin' => [ 'platformCommon:customFieldList' => [ 'platformCore:customField/' => { - '@internalId' => 'custitem_apcategoryforsales', + '@scriptId' => 'custitem_apcategoryforsales', + # Or, for API versions 2013.1 and older: + # '@internalId' => 'custitem_apcategoryforsales', '@xsi:type' => "platformCore:SearchColumnSelectCustomField" } ] From 1c7fe7fd48cb2f1b6ae174a7c77764c1ff1a1314 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 2 Jun 2021 14:44:49 -0600 Subject: [PATCH 026/114] Adding serialized assembly item to get_item --- lib/netsuite/utilities.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index c0b0f2d91..c8a1ca9de 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -173,6 +173,7 @@ def get_item(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) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedInventoryItem, ns_item_internal_id, opts) + ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedAssemblyItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedAssemblyItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedInventoryItem, ns_item_internal_id, opts) From 0d1f5ab0ced599abdc0767eaa74ee6e04fc2122b Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 2 Jun 2021 14:45:05 -0600 Subject: [PATCH 027/114] Fixing some field definitions on serialized assembly item --- lib/netsuite/records/serialized_assembly_item.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/records/serialized_assembly_item.rb b/lib/netsuite/records/serialized_assembly_item.rb index 3448dbddc..2802eb317 100644 --- a/lib/netsuite/records/serialized_assembly_item.rb +++ b/lib/netsuite/records/serialized_assembly_item.rb @@ -61,7 +61,6 @@ class SerializedAssemblyItem :hazmat_packing_group, :hazmat_shipping_name, :include_children, - :income_account, :interco_cogs_account, :interco_income_account, :invt_classification, @@ -209,6 +208,8 @@ class SerializedAssemblyItem :wip_acct, :wip_variance_acct + record_refs :income_account + # accountingBookDetailList ItemAccountingBookDetailList # binNumberList InventoryItemBinNumberList # itemOptionsList ItemOptionsList @@ -220,6 +221,7 @@ class SerializedAssemblyItem # siteCategoryList SiteCategoryList # translationsList TranslationList + field :subsidiary_list, RecordRefList field :custom_field_list, CustomFieldList attr_reader :internal_id From f367c567cf780200bb48e2e59a47b0632e53e95e Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 15 Jul 2021 10:40:02 -0400 Subject: [PATCH 028/114] Add CostCategory record (#482) --- lib/netsuite.rb | 1 + lib/netsuite/records/cost_category.rb | 28 ++++++ spec/netsuite/records/cost_category_spec.rb | 105 ++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 lib/netsuite/records/cost_category.rb create mode 100644 spec/netsuite/records/cost_category_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 09aca5c8b..4afe36b39 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -95,6 +95,7 @@ module Records autoload :CashRefundItemList, 'netsuite/records/cash_refund_item_list' autoload :Campaign, 'netsuite/records/campaign' autoload :Classification, 'netsuite/records/classification' + autoload :CostCategory, 'netsuite/records/cost_category' autoload :CreditMemo, 'netsuite/records/credit_memo' autoload :CreditMemoApply, 'netsuite/records/credit_memo_apply' autoload :CreditMemoApplyList, 'netsuite/records/credit_memo_apply_list' diff --git a/lib/netsuite/records/cost_category.rb b/lib/netsuite/records/cost_category.rb new file mode 100644 index 000000000..2c6c1a9b5 --- /dev/null +++ b/lib/netsuite/records/cost_category.rb @@ -0,0 +1,28 @@ +module NetSuite + module Records + class CostCategory + include Support::Fields + include Support::RecordRefs + include Support::Records + include Support::Actions + include Namespaces::ListAcct + + actions :add, :delete, :delete_list, :get, :get_all, :get_list, :get_select_value, :search, :update, :update_list, :upsert, :upsert_list + # TODO: Add add_list when supported by gem + + fields :is_inactive, :item_cost_type, :name + + record_refs :account + + 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/cost_category_spec.rb b/spec/netsuite/records/cost_category_spec.rb new file mode 100644 index 000000000..84748a16d --- /dev/null +++ b/spec/netsuite/records/cost_category_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' + +describe NetSuite::Records::CostCategory do + let(:cost_category) { described_class.new } + + it 'has all the right fields' do + [ + :is_inactive, + :item_cost_type, + :name, + ].each do |field| + expect(cost_category).to have_field(field) + end + end + + it 'has all the right record refs' do + [ + :account, + ].each do |record_ref| + expect(cost_category).to have_record_ref(record_ref) + end + end + + describe '.get' do + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :name => 'CostCategory 1' }) } + + it 'returns a CostCategory instance populated with the data from the response object' do + expect(NetSuite::Actions::Get).to receive(:call).with([described_class, {:external_id => 1}], {}).and_return(response) + cost_category = described_class.get(:external_id => 1) + expect(cost_category).to be_kind_of(described_class) + expect(cost_category.name).to eql('CostCategory 1') + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'raises a RecordNotFound exception' do + expect(NetSuite::Actions::Get).to receive(:call).with([described_class, {:external_id => 1}], {}).and_return(response) + expect { + described_class.get(:external_id => 1) + }.to raise_error(NetSuite::RecordNotFound, + /NetSuite::Records::CostCategory with OPTIONS=(.*) could not be found/) + end + end + end + + describe '#add' do + let(:test_data) { { :name => 'Test CostCategory' } } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + cost_category = described_class.new(test_data) + expect(NetSuite::Actions::Add).to receive(:call). + with([cost_category], {}). + and_return(response) + expect(cost_category.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 + cost_category = described_class.new(test_data) + expect(NetSuite::Actions::Add).to receive(:call). + with([cost_category], {}). + and_return(response) + expect(cost_category.add).to be_falsey + end + end + end + + describe '#delete' do + let(:test_data) { { :internal_id => '1' } } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + cost_category = described_class.new(test_data) + expect(NetSuite::Actions::Delete).to receive(:call). + with([cost_category], {}). + and_return(response) + expect(cost_category.delete).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + cost_category = described_class.new(test_data) + expect(NetSuite::Actions::Delete).to receive(:call). + with([cost_category], {}). + and_return(response) + expect(cost_category.delete).to be_falsey + end + end + end + +end From 9836ca7daeacb3d55c6d572ce03e984e468eceb2 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:21:19 -0600 Subject: [PATCH 029/114] Remove rspec formatters, no idea what that was being used for --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 49412b054..baaedc3c2 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,6 @@ source 'https://rubygems.org' gemspec gem 'simplecov', :require => false -gem 'rspec_junit_formatter' gem 'pry-nav' gem 'pry-rescue' From 04105caff7ae00d672a266d7eb655f01031a604a Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:21:59 -0600 Subject: [PATCH 030/114] Expanding tests for custom field list --- .../records/custom_field_list_spec.rb | 42 ++++++++++++++++- .../fixtures/custom_fields/multi_select.xml | 47 +++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 spec/support/fixtures/custom_fields/multi_select.xml diff --git a/spec/netsuite/records/custom_field_list_spec.rb b/spec/netsuite/records/custom_field_list_spec.rb index f483e30f8..2266f51da 100644 --- a/spec/netsuite/records/custom_field_list_spec.rb +++ b/spec/netsuite/records/custom_field_list_spec.rb @@ -3,17 +3,53 @@ describe NetSuite::Records::CustomFieldList do let(:list) { NetSuite::Records::CustomFieldList.new } + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + it 'has a custom_fields attribute' do expect(list.custom_fields).to be_kind_of(Array) end it 'accepts a collection of CustomField records' do - field = NetSuite::Records::CustomField.new({:value=>{:internal_id=>"5", :type_id=>"103"}, - :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"}) + field = NetSuite::Records::CustomField.new({ + :value=>{:internal_id=>"5", :type_id=>"103"}, + :script_id=>"custitem_item_category", + :"@xsi:type"=>"platformCore:SelectCustomFieldRef" + }) + list = described_class.new(custom_field: [field]) + expect(list.custom_fields).to eq([field]) end + it 'properly decodes various custom field types' do + savon. + expects(:get). + with(message: {"platformMsgs:baseRef"=>{"@xsi:type"=>"platformCore:RecordRef", "@internalId"=>123, "@type"=>"creditMemo"}}). + returns(File.read('spec/support/fixtures/custom_fields/multi_select.xml')) + + credit_memo_with_custom_fields = NetSuite::Records::CreditMemo.get(123) + + expect(credit_memo_with_custom_fields.custom_field_list.custbody_standard_select.value.internal_id).to eq("2") + expect(credit_memo_with_custom_fields.custom_field_list.custbody_standard_select.value.attributes[:name]).to eq("Manual") + + expect(credit_memo_with_custom_fields.custom_field_list.custbody_date_field.value).to be_a(DateTime) + expect(credit_memo_with_custom_fields.custom_field_list.custbody_date_field.value.to_s).to eq("2021-07-13T22:00:00-07:00") + + expect(credit_memo_with_custom_fields.custom_field_list.custbody_string_field.value).to eq("a very nice string") + expect(credit_memo_with_custom_fields.custom_field_list.custbody_boolean_field.value).to eq(false) + + # even if there's a single value, it should return an array + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value).to be_a(Array) + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value.size).to eq(1) + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value.first.attributes[:name]).to eq("selection value") + + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value).to be_a(Array) + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.size).to eq(2) + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.first.attributes[:name]).to eq("selection value 1") + expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.last.attributes[:name]).to eq("selection value 2") + end + context 'initializing with custom field attributes without a type' do it 'does not mutate the attributes' do field = {:value=>{:internal_id=>"5", :type_id=>"103"}, @@ -28,7 +64,9 @@ it 'does not mutate the attributes' do field = {:value=>{:internal_id=>"5", :type_id=>"103"}, :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"} + described_class.new(custom_field: [field]) + expect(field).to eq({:value=>{:internal_id=>"5", :type_id=>"103"}, :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"}) end diff --git a/spec/support/fixtures/custom_fields/multi_select.xml b/spec/support/fixtures/custom_fields/multi_select.xml new file mode 100644 index 000000000..bbd4320ac --- /dev/null +++ b/spec/support/fixtures/custom_fields/multi_select.xml @@ -0,0 +1,47 @@ + + + + WEBSERVICES_4384362_0714202114843454571284681300_c8529d78de5 + + + + + + + + 2021-07-14T12:45:42.000-07:00 + 2021-07-14T14:56:35.000-07:00 + + + + Manual + + + + 2021-07-13T22:00:00.000-07:00 + + + a very nice string + + + false + + + + selection value + + + + + selection value 1 + + + selection value 2 + + + + + + + + \ No newline at end of file From 3377c971d0cb727d81f4b4bc6e30edfbdfaccfd1 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:22:31 -0600 Subject: [PATCH 031/114] Fixing bug where single-selection custom multi select fields would incorrectly be parsed --- lib/netsuite/records/custom_field_list.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/records/custom_field_list.rb b/lib/netsuite/records/custom_field_list.rb index 81a7cc555..b60e5f8ad 100644 --- a/lib/netsuite/records/custom_field_list.rb +++ b/lib/netsuite/records/custom_field_list.rb @@ -113,7 +113,12 @@ 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| + # if there is only a single selection, `:value` will be hash not an array + attrs[:value] = if custom_field_data[:value].is_a?(Array) + custom_field_data[:value] + else + [custom_field_data[:value]] + end.map do |entry| CustomRecordRef.new(entry) end end From 22fdc58089f608a4725e4ead99e6bd89af715139 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:24:26 -0600 Subject: [PATCH 032/114] Adding github workflow --- .github/workflows/main.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..cdbf53f56 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,20 @@ +name: Ruby + +on: [push,pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.0', 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + - name: Install dependencies + run: bundle install + - name: Run tests + run: bundle exec rake \ No newline at end of file From df922906ca30728c62051b111e618c79ff654657 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:27:51 -0600 Subject: [PATCH 033/114] default rake to rspec --- Rakefile | 2 +- netsuite.gemspec | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 7572a953c..34b45eb32 100644 --- a/Rakefile +++ b/Rakefile @@ -7,7 +7,7 @@ task :default => :spec desc 'Run specs' RSpec::Core::RakeTask.new do |t| - t.pattern = './spec/**/*_spec.rb' + # t.pattern = './spec/**/*_spec.rb' end desc 'Generate code coverage' diff --git a/netsuite.gemspec b/netsuite.gemspec index fb4ca5452..ec1b6a727 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -18,5 +18,6 @@ Gem::Specification.new do |gem| gem.add_dependency 'savon', '>= 2.3.0', '<= 2.11.1' - gem.add_development_dependency 'rspec', '~> 3.8.0' + gem.add_development_dependency 'rspec', '~> 3.10.0' + gem.add_development_dependency 'rake' end From f95999e26483f842ec450b3d19d901f752f6d248 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:30:01 -0600 Subject: [PATCH 034/114] Remove ruby 3.0 tests Failing for now, will fix later --- .github/workflows/main.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cdbf53f56..f0d4f223a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.0', 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] + ruby-version: [2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] steps: - uses: actions/checkout@v2 - name: Set up Ruby ${{ matrix.ruby-version }} diff --git a/README.md b/README.md index 2549b8d4c..c43664ab5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ -[![Circle CI](https://circleci.com/gh/NetSweet/netsuite/tree/master.svg?style=svg)](https://circleci.com/gh/NetSweet/netsuite/tree/master) +[![Ruby](https://github.com/NetSweet/netsuite/actions/workflows/main.yml/badge.svg)](https://github.com/NetSweet/netsuite/actions/workflows/main.yml) [![Slack Status](https://opensuite-slackin.herokuapp.com/badge.svg)](http://opensuite-slackin.herokuapp.com) [![Gem Version](https://badge.fury.io/rb/netsuite.svg)](http://badge.fury.io/rb/netsuite) From 036f4fa9e1824243da70018740e6d4fc2cb106b6 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 11:33:42 -0600 Subject: [PATCH 035/114] Fixing tests to be compatible with ruby 2.1 and 2.2 --- spec/netsuite/configuration_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/netsuite/configuration_spec.rb b/spec/netsuite/configuration_spec.rb index a6d0920fe..67ecffaf8 100644 --- a/spec/netsuite/configuration_spec.rb +++ b/spec/netsuite/configuration_spec.rb @@ -401,7 +401,7 @@ describe "#log" do it 'allows a file path to be set as the log destination' do - file_path = Tempfile.new.path + file_path = Tempfile.new('tmplog').path config.log = file_path config.logger.info "foo" From 4456ce2c8ecec8fe5e2b7d22a043a9884e50f0e4 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 15 Jul 2021 15:25:07 -0600 Subject: [PATCH 036/114] Removing circleci in favor of github actions --- circle.yml | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 circle.yml diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 042e3561e..000000000 --- a/circle.yml +++ /dev/null @@ -1,39 +0,0 @@ -version: 2.1 - -orbs: - # orbs are basically bundles of pre-written build scripts that work for common cases - # https://github.com/CircleCI-Public/ruby-orb - ruby: circleci/ruby@1.1.2 - -jobs: - # skipping build step because Gemfile.lock is not included in the source - # this makes the bundler caching step a noop - test: - parameters: - ruby-version: - type: string - docker: - - image: cimg/ruby:<< parameters.ruby-version >> - steps: - - checkout - - ruby/install-deps: - bundler-version: '2.1.4' - with-cache: false - # without specifying a non-standard path `--deployment` will be used when running bundler - # which causes the bundler to fail - path: './vendor/custom_bundle' - - ruby/rspec-test - -# strangely, there seems to be very little documentation about exactly how martix builds work. -# By defining a param inside your job definition, Circle CI will automatically spawn a job for -# unique param value passed via `matrix`. Neat! -# https://circleci.com/blog/circleci-matrix-jobs/ -workflows: - build_and_test: - jobs: - - test: - matrix: - parameters: - # https://github.com/CircleCI-Public/cimg-ruby - # only supports the last three ruby versions - ruby-version: ["2.5", "2.6", "2.7"] \ No newline at end of file From 1af5545658153d32c16615b84d269eea65b26f28 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Fri, 16 Jul 2021 17:39:51 -0400 Subject: [PATCH 037/114] Fix accessing custom field values returned in advanced search results (#480) NetSuite seems to wrap values in a `searchValue` element rather than just `value`, breaking the ability to access those values the same in an advanced search as compared to either a basic search or simple `get`. Previously, you'd access the value via `my_record.custom_field_list.my_custom_field.attributes.fetch(:search_value)`, and if it was a `CustomRecordRef`, you'd get a raw hash back, not an instance of `CustomRecordRef`. Now, you'd access the value via `my_record.custom_field_list.my_custom_field.value`, so it's consistent across `get`, basic, and advanced searches, plus you'd get an instance of `CustomRecordRef`, where appropriate. Co-authored-by: Michael Bianco --- lib/netsuite/records/custom_field_list.rb | 5 ++-- lib/netsuite/support/search_result.rb | 23 +++++++++++++++---- spec/netsuite/actions/search_spec.rb | 2 ++ .../saved_search_joined_custom_customer.xml | 8 +++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/netsuite/records/custom_field_list.rb b/lib/netsuite/records/custom_field_list.rb index b60e5f8ad..193bb4b84 100644 --- a/lib/netsuite/records/custom_field_list.rb +++ b/lib/netsuite/records/custom_field_list.rb @@ -110,9 +110,10 @@ def extract_custom_field(custom_field_data) attrs = custom_field_data.clone type = (custom_field_data[:"@xsi:type"] || custom_field_data[:type]) - if type == "platformCore:SelectCustomFieldRef" + case type + when "platformCore:SelectCustomFieldRef", "platformCore:SearchColumnSelectCustomField" attrs[:value] = CustomRecordRef.new(custom_field_data[:value]) - elsif type == 'platformCore:MultiSelectCustomFieldRef' + when 'platformCore:MultiSelectCustomFieldRef', 'platformCore:SearchColumnMultiSelectCustomField' # if there is only a single selection, `:value` will be hash not an array attrs[:value] = if custom_field_data[:value].is_a?(Array) custom_field_data[:value] diff --git a/lib/netsuite/support/search_result.rb b/lib/netsuite/support/search_result.rb index bd7071a18..2cd936c5f 100644 --- a/lib/netsuite/support/search_result.rb +++ b/lib/netsuite/support/search_result.rb @@ -52,9 +52,6 @@ def initialize(response, result_class, credentials) record_list = [record_list] unless record_list.is_a?(Array) record_list.each do |record| - # TODO because of customFieldList we need to either make this recursive - # or handle the customFieldList as a special case - record.each_pair do |search_group, search_data| # skip all attributes: look for :basic and all :xxx_join next if search_group.to_s.start_with?('@') @@ -63,7 +60,25 @@ def initialize(response, result_class, credentials) # all return values are wrapped in a # extract the value from to make results easier to work with - if v.is_a?(Hash) && v.has_key?(:search_value) + if k == :custom_field_list + # Here's an example of a response + + # + # + # sample string value + # + # + # + # + # + + custom_field_list = v.fetch(:custom_field) + custom_field_list = [custom_field_list] unless custom_field_list.is_a?(Array) + record[search_group][k][:custom_field] = custom_field_list.map do |custom_field| + custom_field[:value] = custom_field.fetch(:search_value) + custom_field + end + elsif v.is_a?(Hash) && v.has_key?(:search_value) # Here's an example of a record ref and string response # diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index 2f0abbec4..b6eff64bc 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -171,6 +171,8 @@ expect(search.results.first.internal_id).to eq('123') expect(search.results.first.external_id).to eq('456') expect(search.results.first.alt_name).to eq('A Awesome Name') + expect(search.results.first.custom_field_list.custitem_stringfield.value).to eq('sample string value') + expect(search.results.first.custom_field_list.custitem_apcategoryforsales.value.internal_id).to eq('4') expect(search.results.last.email).to eq('alessawesome@gmail.com') end end diff --git a/spec/support/fixtures/search/saved_search_joined_custom_customer.xml b/spec/support/fixtures/search/saved_search_joined_custom_customer.xml index 68b3fa4d5..22d47550d 100644 --- a/spec/support/fixtures/search/saved_search_joined_custom_customer.xml +++ b/spec/support/fixtures/search/saved_search_joined_custom_customer.xml @@ -43,6 +43,14 @@ 444-444-4444 + + + sample string value + + + + + From 676a618266a6bff8c89772c3b016e0404f837a25 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 10 Aug 2021 09:06:54 -0400 Subject: [PATCH 038/114] Introduce search only fields (#483) When performing a search, there's additional columns that can be requested that aren't normally on the record. Previously such columns were not accessible via this gem's search results. Now these columns can be accessed just as you'd access a regular field or read only field. Starting with InventoryItem and Invoice. Ultimately, these are fields of the ___SearchRowBasic, ItemSearchRowBasic and TransactionSearchRowBasic, so eventually it may be wise to extract a module encapulating those SearchRowBasic's and include that in the relevant records to avoid duplication of search only fields across multiple records (ie. Estimate, SalesOrder, Invoice, CreditMemo, etc.) that all utilize the same SearchRowBasic. --- lib/netsuite/records/inventory_item.rb | 60 ++++++++++++ lib/netsuite/records/invoice.rb | 93 ++++++++++++++++++ lib/netsuite/support/fields.rb | 16 ++++ lib/netsuite/support/records.rb | 2 +- spec/netsuite/actions/search_spec.rb | 18 ++++ spec/netsuite/records/inventory_item_spec.rb | 65 +++++++++++++ spec/netsuite/records/invoice_spec.rb | 94 +++++++++++++++++++ .../fixtures/search/saved_search_item.xml | 55 +++++++++++ spec/support/search_only_field_matcher.rb | 7 ++ 9 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 spec/support/fixtures/search/saved_search_item.xml create mode 100644 spec/support/search_only_field_matcher.rb diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index ef91feaff..2b0969887 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -45,6 +45,66 @@ class InventoryItem :total_value, :track_landed_cost, :transfer_price, :upc_code, :url_component, :use_bins, :use_marginal_rates, :vendor_name, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_2/schema/search/itemsearchrowbasic.html?mode=package + search_only_fields :acc_book_rev_rec_forecast_rule, :accounting_book, + :accounting_book_amortization, :accounting_book_create_plans_on, + :accounting_book_rev_rec_rule, :accounting_book_rev_rec_schedule, + :allowed_shipping_method, :atp_lead_time, :atp_method, :base_price, + :bin_number, :bin_on_hand_avail, :bin_on_hand_count, :bom_quantity, + :build_entire_assembly, :build_time, :buy_it_now_price, :category, + :category_preferred, :component_yield, :correlated_item, + :correlated_item_correlation, :correlated_item_count, + :correlated_item_lift, :correlated_item_purchase_rate, + :cost_accounting_status, :created, :create_job, + :cust_return_variance_account, :date_viewed, :days_before_expiration, + :default_shipping_method, :deferred_expense_account, + :departmentnohierarchy, :display_ine_bay_store, :e_bay_item_description, + :e_bay_item_subtitle, :e_bay_item_title, :ebay_relisting_option, + :effective_bom_control, :effective_date, :effective_revision, + :end_auctions_when_out_of_stock, :feed_description, :feed_name, + :froogle_product_feed, :fx_cost, :generate_accruals, + :gift_cert_auth_code, :gift_cert_email, :gift_cert_expiration_date, + :gift_cert_from, :gift_cert_message, :gift_cert_original_amount, + :gift_cert_recipient, :hierarchy_node, :hierarchy_version, :hits, + :image_url, :interco_expense_account, :inventory_location, + :is_available, :is_fulfillable, :is_lot_item, :is_serial_item, + :is_special_work_order_item, :is_vsoe_bundle, :is_wip, :item_url, + :last_quantity_available_change, :liability_account, :listing_duration, + :location_allow_store_pickup, :location_atp_lead_time, + :location_average_cost, :location_bin_quantity_available, + :location_build_time, :location_cost, :location_cost_accounting_status, + :location_default_return_cost, :location_demand_source, + :location_demand_time_fence, :location_fixed_lot_size, + :location_inventory_cost_template, :location_invt_classification, + :location_invt_count_interval, :location_last_invt_count_date, + :location_lead_time, :location_next_invt_count_date, + :location_periodic_lot_size_days, :location_periodic_lot_size_type, + :location_preferred_stock_level, :location_qty_avail_for_store_pickup, + :location_quantity_available, :location_quantity_back_ordered, + :location_quantity_committed, :location_quantity_in_transit, + :location_quantity_on_hand, :location_quantity_on_order, + :location_re_order_point, :location_reschedule_in_days, + :location_reschedule_out_days, :location_safety_stock_level, + :location_store_pickup_buffer_stock, :location_supply_lot_sizing_method, + :location_supply_time_fence, :location_supply_type, + :location_total_value, :loc_backward_consumption_days, + :loc_forward_consumption_days, :manufacturing_charge_item, :member_item, + :member_quantity, :modified, :moss_applies, :nextag_product_feed, + :num_active_listings, :number_allowed_downloads, :num_currently_listed, + :obsolete_date, :obsolete_revision, :online_customer_price, + :online_price, :other_prices, :other_vendor, :overhead_type, + :preferred_bin, :primary_category, :prod_price_variance_acct, + :prod_qty_variance_acct, :purchase_unit, :reserve_price, + :revenue_recognition_rule, :same_as_primary_book_amortization, + :same_as_primary_book_rev_rec, :scrap_acct, :sell_on_ebay, + :serial_number, :serial_number_location, :shipping_carrier, + :shipping_rate, :shopping_product_feed, :shopzilla_product_feed, + :soft_descriptor, :starting_price, :subsidiary, :sub_type, + :thumb_nail_url, :type, :unbuild_variance_account, :use_component_yield, + :vendor_code, :vendor_cost, :vendor_cost_entered, + :vendor_price_currency, :vendor_schedule, :vend_return_variance_account, + :web_site, :wip_acct, :wip_variance_acct, :yahoo_product_feed + 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, diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 60f25aba5..7ef656e32 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -42,6 +42,99 @@ class Invoice read_only_fields :sub_total, :discount_total, :total, :recognized_revenue, :amount_remaining, :amount_paid, :amount, :alt_shipping_cost, :gift_cert_applied, :handling_cost, :alt_handling_cost + # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_2/schema/search/transactionsearchrowbasic.html?mode=package + search_only_fields :abbrev, :account_type, :acct_corp_card_exp, + :actual_production_end_date, :actual_production_start_date, + :actual_ship_date, :alt_sales_amount, :alt_sales_net_amount, :amount, + :amount_unbilled, :applied_to_foreign_amount, + :applied_to_is_fx_variance, :applied_to_link_amount, + :applied_to_link_type, :applied_to_transaction, + :applying_foreign_amount, :applying_is_fx_variance, + :applying_link_amount, :applying_link_type, :applying_transaction, + :auth_code, :auto_calculate_lag, :avs_street_match, :avs_zip_match, + :billable, :bill_address, :bill_address1, :bill_address2, + :bill_address3, :bill_addressee, :bill_attention, :bill_city, + :bill_country, :bill_country_code, :billed_date, :billing_amount, + :billing_transaction, :bill_phone, :bill_state, :bill_variance_status, + :bill_zip, :bin_number, :bin_number_quantity, :bom_quantity, + :build_entire_assembly, :build_variance, :built, + :can_have_stackable_promotions, :catch_up_period, :cc_customer_code, + :cc_exp_date, :cc_holder_name, :cc_number, :cc_street, :cc_zip_code, + :cleared, :closed, :close_date, :cogs_amount, + :commission_effective_date, :commit, :component_yield, + :confirmation_number, :contribution, :contribution_primary, + :cost_component_amount, :cost_component_category, :cost_component_item, + :cost_component_quantity, :cost_component_standard_cost, :cost_estimate, + :cost_estimate_rate, :cost_estimate_type, :created_by, :credit_amount, + :csc_match, :custom_gl, :cust_type, :date_created, :days_open, + :days_overdue, :debit_amount, :defer_rev_rec, :deposit_date, + :deposit_transaction, :doc_unit, :dr_account, :effective_rate, + :entity_status, :est_gross_profit_pct, :exclude_from_rate_request, + :expected_close_date, :expected_receipt_date, :expense_category, + :expense_date, :firmed, :forecast_type, :fulfilling_transaction, + :fx_account, :fx_amount, :fx_cost_estimate, :fx_cost_estimate_rate, + :fx_est_gross_profit, :fx_tran_cost_estimate, :fx_vsoe_allocation, + :fx_vsoe_amount, :fx_vsoe_price, :gco_availabel_to_charge, + :gco_available_to_refund, :gco_avs_street_match, :gco_avs_zip_match, + :gco_buyer_account_age, :gco_buyer_ip, :gco_charge_amount, + :gco_chargeback_amount, :gco_confirmed_charged_total, + :gco_confirmed_refunded_total, :gco_creditcard_number, :gco_csc_match, + :gco_financial_state, :gco_fulfillment_state, :gco_order_id, + :gco_order_total, :gco_promotion_amount, :gco_promotion_name, + :gco_refund_amount, :gco_shipping_total, :gco_state_changed_detail, + :gift_cert, :gross_amount, :include_in_forecast, :incoterm, + :interco_status, :interco_transaction, :inventory_location, + :inventory_subsidiary, :in_vsoe_bundle, :is_allocation, :is_backflush, + :is_gco_chargeback, :is_gco_charge_confirmed, + :is_gco_payment_guaranteed, :is_gco_refund_confirmed, + :is_inside_delivery, :is_inside_pickup, :is_intercompany_adjustment, + :is_in_transit_payment, :is_multi_ship_to, :is_reversal, + :is_rev_rec_transaction, :is_scrap, :is_ship_address, + :is_transfer_price_costing, :is_wip, :item, :item_fulfillment_choice, + :item_revision, :landed_cost_per_line, :line, :line_sequence_number, + :line_unique_key, :location_auto_assigned, :main_line, :main_name, + :manufacturing_routing, :match_bill_to_receipt, :memo_main, :memorized, + :merchant_account, :multi_subsidiary, :net_amount, :net_amount_no_tax, + :next_bill_date, :no_auto_assign_location, :non_reimbursable, + :one_time_total, :options, :order_allocation_strategy, :order_priority, + :originator, :other_ref_num, :overhead_parent_item, + :override_installments, :package_count, :paid_amount, :paid_transaction, + :partner_contribution, :partner_role, :partner_team_member, + :paying_amount, :paying_transaction, :payment_approved, + :payment_event_date, :payment_event_hold_reason, + :payment_event_purchase_card_used, :payment_event_purchase_data_sent, + :payment_event_result, :payment_event_type, :payment_hold, + :payment_method, :payment_option, :pay_pal_pending, :pay_pal_status, + :pay_pal_tran_id, :payroll_batch, :pn_ref_num, :po_rate, :posting, + :price_level, :print, :probability, :projected_amount, :project_task, + :purchase_order, :quantity, :quantity_billed, :quantity_committed, + :quantity_packed, :quantity_picked, :quantity_rev_committed, + :quantity_ship_recv, :quantity_uom, :rate, + :realized_gain_posting_transaction, :recur_annually_total, + :recur_monthly_total, :recur_quarterly_total, :recur_weekly_total, + :ref_number, :requested_date, :rev_commit_status, + :rev_committing_transaction, :reversal_date, :reversal_number, + :rg_account, :rg_amount, :sales_order, :sales_team_member, + :sales_team_role, :scheduling_method, :serial_number, + :serial_number_cost, :serial_number_cost_adjustment, + :serial_number_quantity, :serial_numbers, :ship_address, :ship_address1, + :ship_address2, :ship_address3, :ship_addressee, :ship_attention, + :ship_carrier, :ship_city, :ship_complete, :ship_country, + :ship_country_code, :ship_group, :ship_phone, :shipping_amount, + :ship_recv_status_line, :ship_state, :ship_to, :ship_zip, + :signed_amount, :subscription, :subscription_line, :tax_amount, + :tax_code, :tax_line, :tax_period, :term_in_months, :terms_of_sale, + :title, :to_subsidiary, :tran_est_gross_profit, + :tran_fx_est_gross_profit, :transaction_discount, + :transaction_line_type, :transaction_number, :transfer_location, + :transfer_order_item_line, :transfer_order_quantity_committed, + :transfer_order_quantity_packed, :transfer_order_quantity_picked, + :transfer_order_quantity_received, :transfer_order_quantity_shipped, + :type, :unit, :unit_cost_override, :vend_type, :visible_to_customer, + :vsoe_allocation, :vsoe_amount, :vsoe_deferral, :vsoe_delivered, + :vsoe_permit_discount, :vsoe_price, :web_site + # TODO: Add record_type, conflicts with Support::Records#record_type, returns "invoice" versus "tranSales:Invoice" + record_refs :account, :bill_address_list, :custom_form, :department, :entity, :klass, :partner, :posting_period, :ship_address_list, :terms, :location, :sales_rep, :tax_item, :created_from, :ship_method, :lead_source, :promo_code, :subsidiary, :currency, :approval_status, :job, :discount_item diff --git a/lib/netsuite/support/fields.rb b/lib/netsuite/support/fields.rb index 14e3d7fc1..94d529e1d 100644 --- a/lib/netsuite/support/fields.rb +++ b/lib/netsuite/support/fields.rb @@ -60,6 +60,22 @@ def read_only_field(name) read_only_fields << name_sym field name end + + def search_only_fields(*args) + if args.empty? + @search_only_fields ||= Set.new + else + args.each do |arg| + search_only_field arg + end + end + end + + def search_only_field(name) + name_sym = name.to_sym + search_only_fields << name_sym + field name + end end end diff --git a/lib/netsuite/support/records.rb b/lib/netsuite/support/records.rb index 74f3aa9d2..447755f55 100644 --- a/lib/netsuite/support/records.rb +++ b/lib/netsuite/support/records.rb @@ -5,7 +5,7 @@ module Records include Namespaces::PlatformCore def to_record - attributes.reject { |k,v| self.class.read_only_fields.include?(k) }.inject({}) do |hash, (k,v)| + attributes.reject { |k,v| self.class.read_only_fields.include?(k) || self.class.search_only_fields.include?(k) }.inject({}) do |hash, (k,v)| kname = "#{record_namespace}:" kname += k == :klass ? 'class' : k.to_s.lower_camelcase diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index b6eff64bc..b8babbfbd 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -175,6 +175,24 @@ expect(search.results.first.custom_field_list.custitem_apcategoryforsales.value.internal_id).to eq('4') expect(search.results.last.email).to eq('alessawesome@gmail.com') end + + it "should handle an ID search with basic search only field result columns" do + response = File.read('spec/support/fixtures/search/saved_search_item.xml') + savon.expects(:search) + .with(message: { + "searchRecord"=>{ + "@xsi:type" =>"listAcct:ItemSearchAdvanced", + "@savedSearchId" =>42, + :content! =>{"listAcct:criteria"=>{}}, + } + }).returns(response) + + search = NetSuite::Records::InventoryItem.search(saved: 42) + + expect(search.results.first.location_quantity_available).to eq('3307.0') + expect(search.results.first.location_re_order_point).to eq('2565.0') + expect(search.results.first.location_quantity_on_order).to eq('40000.0') + end end context "advanced search" do diff --git a/spec/netsuite/records/inventory_item_spec.rb b/spec/netsuite/records/inventory_item_spec.rb index 32c643f67..f44e3a256 100644 --- a/spec/netsuite/records/inventory_item_spec.rb +++ b/spec/netsuite/records/inventory_item_spec.rb @@ -31,6 +31,70 @@ end end + it 'has all the right search_only_fields' do + [ + :acc_book_rev_rec_forecast_rule, :accounting_book, + :accounting_book_amortization, :accounting_book_create_plans_on, + :accounting_book_rev_rec_rule, :accounting_book_rev_rec_schedule, + :allowed_shipping_method, :atp_lead_time, :atp_method, :base_price, + :bin_number, :bin_on_hand_avail, :bin_on_hand_count, :bom_quantity, + :build_entire_assembly, :build_time, :buy_it_now_price, :category, + :category_preferred, :component_yield, :correlated_item, + :correlated_item_correlation, :correlated_item_count, + :correlated_item_lift, :correlated_item_purchase_rate, + :cost_accounting_status, :created, :create_job, + :cust_return_variance_account, :date_viewed, :days_before_expiration, + :default_shipping_method, :deferred_expense_account, + :departmentnohierarchy, :display_ine_bay_store, :e_bay_item_description, + :e_bay_item_subtitle, :e_bay_item_title, :ebay_relisting_option, + :effective_bom_control, :effective_date, :effective_revision, + :end_auctions_when_out_of_stock, :feed_description, :feed_name, + :froogle_product_feed, :fx_cost, :generate_accruals, :gift_cert_auth_code, + :gift_cert_email, :gift_cert_expiration_date, :gift_cert_from, + :gift_cert_message, :gift_cert_original_amount, :gift_cert_recipient, + :hierarchy_node, :hierarchy_version, :hits, :image_url, + :interco_expense_account, :inventory_location, :is_available, + :is_fulfillable, :is_lot_item, :is_serial_item, + :is_special_work_order_item, :is_vsoe_bundle, :is_wip, :item_url, + :last_quantity_available_change, :liability_account, :listing_duration, + :location_allow_store_pickup, :location_atp_lead_time, + :location_average_cost, :location_bin_quantity_available, + :location_build_time, :location_cost, :location_cost_accounting_status, + :location_default_return_cost, :location_demand_source, + :location_demand_time_fence, :location_fixed_lot_size, + :location_inventory_cost_template, :location_invt_classification, + :location_invt_count_interval, :location_last_invt_count_date, + :location_lead_time, :location_next_invt_count_date, + :location_periodic_lot_size_days, :location_periodic_lot_size_type, + :location_preferred_stock_level, :location_qty_avail_for_store_pickup, + :location_quantity_available, :location_quantity_back_ordered, + :location_quantity_committed, :location_quantity_in_transit, + :location_quantity_on_hand, :location_quantity_on_order, + :location_re_order_point, :location_reschedule_in_days, + :location_reschedule_out_days, :location_safety_stock_level, + :location_store_pickup_buffer_stock, :location_supply_lot_sizing_method, + :location_supply_time_fence, :location_supply_type, :location_total_value, + :loc_backward_consumption_days, :loc_forward_consumption_days, + :manufacturing_charge_item, :member_item, :member_quantity, :modified, + :moss_applies, :nextag_product_feed, :num_active_listings, + :number_allowed_downloads, :num_currently_listed, :obsolete_date, + :obsolete_revision, :online_customer_price, :online_price, :other_prices, + :other_vendor, :overhead_type, :preferred_bin, :primary_category, + :prod_price_variance_acct, :prod_qty_variance_acct, :purchase_unit, + :reserve_price, :revenue_recognition_rule, + :same_as_primary_book_amortization, :same_as_primary_book_rev_rec, + :scrap_acct, :sell_on_ebay, :serial_number, :serial_number_location, + :shipping_carrier, :shipping_rate, :shopping_product_feed, + :shopzilla_product_feed, :soft_descriptor, :starting_price, :subsidiary, + :sub_type, :thumb_nail_url, :type, :unbuild_variance_account, + :use_component_yield, :vendor_code, :vendor_cost, :vendor_cost_entered, + :vendor_price_currency, :vendor_schedule, :vend_return_variance_account, + :web_site, :wip_acct, :wip_variance_acct, :yahoo_product_feed, + ].each do |field| + expect(NetSuite::Records::InventoryItem).to have_search_only_field(field) + end + end + it 'has all the right record refs' do [ :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, :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, :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor @@ -215,6 +279,7 @@ before do item.cost = 100 item.is_inactive = false + item.location_quantity_available = '1.0' # Search only, excluded end it 'can represent itself as a SOAP record' do record = { diff --git a/spec/netsuite/records/invoice_spec.rb b/spec/netsuite/records/invoice_spec.rb index cae6262e9..4b654ec38 100644 --- a/spec/netsuite/records/invoice_spec.rb +++ b/spec/netsuite/records/invoice_spec.rb @@ -41,6 +41,99 @@ end end + it 'has all the right search_only_fields' do + [ + :abbrev, :account_type, :acct_corp_card_exp, :actual_production_end_date, + :actual_production_start_date, :actual_ship_date, :alt_sales_amount, + :alt_sales_net_amount, :amount, :amount_unbilled, + :applied_to_foreign_amount, :applied_to_is_fx_variance, + :applied_to_link_amount, :applied_to_link_type, :applied_to_transaction, + :applying_foreign_amount, :applying_is_fx_variance, :applying_link_amount, + :applying_link_type, :applying_transaction, :auth_code, + :auto_calculate_lag, :avs_street_match, :avs_zip_match, :billable, + :bill_address, :bill_address1, :bill_address2, :bill_address3, + :bill_addressee, :bill_attention, :bill_city, :bill_country, + :bill_country_code, :billed_date, :billing_amount, :billing_transaction, + :bill_phone, :bill_state, :bill_variance_status, :bill_zip, :bin_number, + :bin_number_quantity, :bom_quantity, :build_entire_assembly, + :build_variance, :built, :can_have_stackable_promotions, :catch_up_period, + :cc_customer_code, :cc_exp_date, :cc_holder_name, :cc_number, :cc_street, + :cc_zip_code, :cleared, :closed, :close_date, :cogs_amount, + :commission_effective_date, :commit, :component_yield, + :confirmation_number, :contribution, :contribution_primary, + :cost_component_amount, :cost_component_category, :cost_component_item, + :cost_component_quantity, :cost_component_standard_cost, :cost_estimate, + :cost_estimate_rate, :cost_estimate_type, :created_by, :credit_amount, + :csc_match, :custom_gl, :cust_type, :date_created, :days_open, + :days_overdue, :debit_amount, :defer_rev_rec, :deposit_date, + :deposit_transaction, :doc_unit, :dr_account, :effective_rate, + :entity_status, :est_gross_profit_pct, :exclude_from_rate_request, + :expected_close_date, :expected_receipt_date, :expense_category, + :expense_date, :firmed, :forecast_type, :fulfilling_transaction, + :fx_account, :fx_amount, :fx_cost_estimate, :fx_cost_estimate_rate, + :fx_est_gross_profit, :fx_tran_cost_estimate, :fx_vsoe_allocation, + :fx_vsoe_amount, :fx_vsoe_price, :gco_availabel_to_charge, + :gco_available_to_refund, :gco_avs_street_match, :gco_avs_zip_match, + :gco_buyer_account_age, :gco_buyer_ip, :gco_charge_amount, + :gco_chargeback_amount, :gco_confirmed_charged_total, + :gco_confirmed_refunded_total, :gco_creditcard_number, :gco_csc_match, + :gco_financial_state, :gco_fulfillment_state, :gco_order_id, + :gco_order_total, :gco_promotion_amount, :gco_promotion_name, + :gco_refund_amount, :gco_shipping_total, :gco_state_changed_detail, + :gift_cert, :gross_amount, :include_in_forecast, :incoterm, + :interco_status, :interco_transaction, :inventory_location, + :inventory_subsidiary, :in_vsoe_bundle, :is_allocation, :is_backflush, + :is_gco_chargeback, :is_gco_charge_confirmed, :is_gco_payment_guaranteed, + :is_gco_refund_confirmed, :is_inside_delivery, :is_inside_pickup, + :is_intercompany_adjustment, :is_in_transit_payment, :is_multi_ship_to, + :is_reversal, :is_rev_rec_transaction, :is_scrap, :is_ship_address, + :is_transfer_price_costing, :is_wip, :item, :item_fulfillment_choice, + :item_revision, :landed_cost_per_line, :line, :line_sequence_number, + :line_unique_key, :location_auto_assigned, :main_line, :main_name, + :manufacturing_routing, :match_bill_to_receipt, :memo_main, :memorized, + :merchant_account, :multi_subsidiary, :net_amount, :net_amount_no_tax, + :next_bill_date, :no_auto_assign_location, :non_reimbursable, + :one_time_total, :options, :order_allocation_strategy, :order_priority, + :originator, :other_ref_num, :overhead_parent_item, + :override_installments, :package_count, :paid_amount, :paid_transaction, + :partner_contribution, :partner_role, :partner_team_member, + :paying_amount, :paying_transaction, :payment_approved, + :payment_event_date, :payment_event_hold_reason, + :payment_event_purchase_card_used, :payment_event_purchase_data_sent, + :payment_event_result, :payment_event_type, :payment_hold, + :payment_method, :payment_option, :pay_pal_pending, :pay_pal_status, + :pay_pal_tran_id, :payroll_batch, :pn_ref_num, :po_rate, :posting, + :price_level, :print, :probability, :projected_amount, :project_task, + :purchase_order, :quantity, :quantity_billed, :quantity_committed, + :quantity_packed, :quantity_picked, :quantity_rev_committed, + :quantity_ship_recv, :quantity_uom, :rate, + :realized_gain_posting_transaction, :recur_annually_total, + :recur_monthly_total, :recur_quarterly_total, :recur_weekly_total, + :ref_number, :requested_date, :rev_commit_status, + :rev_committing_transaction, :reversal_date, :reversal_number, + :rg_account, :rg_amount, :sales_order, :sales_team_member, + :sales_team_role, :scheduling_method, :serial_number, :serial_number_cost, + :serial_number_cost_adjustment, :serial_number_quantity, :serial_numbers, + :ship_address, :ship_address1, :ship_address2, :ship_address3, + :ship_addressee, :ship_attention, :ship_carrier, :ship_city, + :ship_complete, :ship_country, :ship_country_code, :ship_group, + :ship_phone, :shipping_amount, :ship_recv_status_line, :ship_state, + :ship_to, :ship_zip, :signed_amount, :subscription, :subscription_line, + :tax_amount, :tax_code, :tax_line, :tax_period, :term_in_months, + :terms_of_sale, :title, :to_subsidiary, :tran_est_gross_profit, + :tran_fx_est_gross_profit, :transaction_discount, :transaction_line_type, + :transaction_number, :transfer_location, :transfer_order_item_line, + :transfer_order_quantity_committed, :transfer_order_quantity_packed, + :transfer_order_quantity_picked, :transfer_order_quantity_received, + :transfer_order_quantity_shipped, :type, :unit, :unit_cost_override, + :vend_type, :visible_to_customer, :vsoe_allocation, :vsoe_amount, + :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, + :web_site, + ].each do |field| + expect(NetSuite::Records::Invoice).to have_search_only_field(field) + end + end + it 'has the right record_refs' do [ :account, :bill_address_list, :job, :custom_form, :department, :entity, :klass, :posting_period, :ship_address_list, :terms, @@ -329,6 +422,7 @@ before do invoice.email = 'something@example.com' invoice.tran_id = '4' + invoice.close_date = '2021-08-04' # Search only, excluded end it 'can represent itself as a SOAP record' do record = { diff --git a/spec/support/fixtures/search/saved_search_item.xml b/spec/support/fixtures/search/saved_search_item.xml new file mode 100644 index 000000000..78a14968d --- /dev/null +++ b/spec/support/fixtures/search/saved_search_item.xml @@ -0,0 +1,55 @@ + + + + WEBSERVICES_3603333_SB1_0320201916835580962038419462_2ce0aa2 + + + + + + + 49 + 1000 + 1 + 1 + WEBSERVICES_3603333_SB1_0320201916835580962038419462_2ce0aa2 + + + + + + Business Unit + + + 9781945179747 + SKU + + + 3307.0 + Qty - Available + + + 40000.0 + Qty - On Order + + + 2565.0 + Qty - Reorder Point + + + + + Product Line + + + + Reorder Status + + + + + + + + + diff --git a/spec/support/search_only_field_matcher.rb b/spec/support/search_only_field_matcher.rb new file mode 100644 index 000000000..4d6b8fb10 --- /dev/null +++ b/spec/support/search_only_field_matcher.rb @@ -0,0 +1,7 @@ +RSpec::Matchers.define :have_search_only_field do |attribute| + + match do |model| + expect(model.search_only_fields.include?(attribute)).to be_truthy + end + +end From a9ea53352c985eda93d8679c5120ff41d7bfb7df Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 10 Aug 2021 07:29:28 -0600 Subject: [PATCH 039/114] initial changelog doc --- HISTORY.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 HISTORY.md diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 000000000..243270ac6 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,11 @@ +## Unreleased + +### Added + +* +* + +### Fixed + +* +* From 5ecc4e6067a9a1fe1b7b2bf5a6b1f6a6f7aa5685 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 10 Aug 2021 07:31:53 -0600 Subject: [PATCH 040/114] Adding 0.8.8 changelog --- HISTORY.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 243270ac6..20d62bde7 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,3 +9,18 @@ * * + +## 0.8.8 + +### Added + +* Adding serialized assembly item to get_item +* Add CostCategory record (#482) +* Introduce search only fields (#483) + +### Fixed + +* Fix accessing custom field values returned in advanced search results (#480) +* Fixing bug where single-selection custom multi select fields would incorrectly be parsed 3377c971d0cb727d81f4b4bc6e30edfbdfaccfd1 +* Fixed some field definitions on serialized assembly item +* Properly extract external_id from advanced search results (#478) \ No newline at end of file From a8395e3f72643ed10e2340c156d5dbe834c49961 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 10 Aug 2021 07:32:09 -0600 Subject: [PATCH 041/114] Version bump --- lib/netsuite/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index 3f0ac2a4b..fd1dcde82 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.7' + VERSION = '0.8.8' end From 1758fc5249c67216c055242117f05969bb104308 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 10 Aug 2021 21:46:53 -0400 Subject: [PATCH 042/114] Explain search only fields in Readme (#484) Attempt to document #483. I wasn't sure how best to convey this given it affects consuming the search results, not performing the search itself. It should also be unsurprising that you'd access these search-only fields the same way you'd access regular or read-only fields. Had we buried these search-only fields in custom fields, like #426 first attempted, then I'd find that more surprising and warranting clearer documentation. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c43664ab5..1eb2bd567 100644 --- a/README.md +++ b/README.md @@ -421,7 +421,10 @@ NetSuite::Records::SalesOrder.search({ 'tranSales:basic' => [ 'platformCommon:internalId/' => {}, 'platformCommon:email/' => {}, - 'platformCommon:tranDate/' => {} + 'platformCommon:tranDate/' => {}, + # If you include columns that are only part of the *SearchRowBasic (ie. TransactionSearchRowBasic), + # they'll be readable on the resulting record just like regular fields (my_record.close_date). + 'platformCommon:closeDate/' => {} ], 'tranSales:accountJoin' => [ 'platformCommon:internalId/' => {} From 2c35927b88d5a594d26b0c102988ff13c8c2e9ac Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Mon, 16 Aug 2021 21:05:43 -0400 Subject: [PATCH 043/114] Fix standard fields mistakenly included as search only fields (#487) This prevents the fields from being included when pushing data to NetSuite. Discussing a longer term fix in #486. --- lib/netsuite/records/inventory_item.rb | 6 +++--- lib/netsuite/records/invoice.rb | 2 +- spec/netsuite/records/inventory_item_spec.rb | 6 +++--- spec/netsuite/records/invoice_spec.rb | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index 2b0969887..1850d04d0 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -94,12 +94,12 @@ class InventoryItem :obsolete_date, :obsolete_revision, :online_customer_price, :online_price, :other_prices, :other_vendor, :overhead_type, :preferred_bin, :primary_category, :prod_price_variance_acct, - :prod_qty_variance_acct, :purchase_unit, :reserve_price, - :revenue_recognition_rule, :same_as_primary_book_amortization, + :prod_qty_variance_acct, :reserve_price, + :same_as_primary_book_amortization, :same_as_primary_book_rev_rec, :scrap_acct, :sell_on_ebay, :serial_number, :serial_number_location, :shipping_carrier, :shipping_rate, :shopping_product_feed, :shopzilla_product_feed, - :soft_descriptor, :starting_price, :subsidiary, :sub_type, + :starting_price, :subsidiary, :sub_type, :thumb_nail_url, :type, :unbuild_variance_account, :use_component_yield, :vendor_code, :vendor_cost, :vendor_cost_entered, :vendor_price_currency, :vendor_schedule, :vend_return_variance_account, diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 7ef656e32..12e32b49b 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -97,7 +97,7 @@ class Invoice :merchant_account, :multi_subsidiary, :net_amount, :net_amount_no_tax, :next_bill_date, :no_auto_assign_location, :non_reimbursable, :one_time_total, :options, :order_allocation_strategy, :order_priority, - :originator, :other_ref_num, :overhead_parent_item, + :originator, :overhead_parent_item, :override_installments, :package_count, :paid_amount, :paid_transaction, :partner_contribution, :partner_role, :partner_team_member, :paying_amount, :paying_transaction, :payment_approved, diff --git a/spec/netsuite/records/inventory_item_spec.rb b/spec/netsuite/records/inventory_item_spec.rb index f44e3a256..6251151cd 100644 --- a/spec/netsuite/records/inventory_item_spec.rb +++ b/spec/netsuite/records/inventory_item_spec.rb @@ -80,12 +80,12 @@ :number_allowed_downloads, :num_currently_listed, :obsolete_date, :obsolete_revision, :online_customer_price, :online_price, :other_prices, :other_vendor, :overhead_type, :preferred_bin, :primary_category, - :prod_price_variance_acct, :prod_qty_variance_acct, :purchase_unit, - :reserve_price, :revenue_recognition_rule, + :prod_price_variance_acct, :prod_qty_variance_acct, + :reserve_price, :same_as_primary_book_amortization, :same_as_primary_book_rev_rec, :scrap_acct, :sell_on_ebay, :serial_number, :serial_number_location, :shipping_carrier, :shipping_rate, :shopping_product_feed, - :shopzilla_product_feed, :soft_descriptor, :starting_price, :subsidiary, + :shopzilla_product_feed, :starting_price, :subsidiary, :sub_type, :thumb_nail_url, :type, :unbuild_variance_account, :use_component_yield, :vendor_code, :vendor_cost, :vendor_cost_entered, :vendor_price_currency, :vendor_schedule, :vend_return_variance_account, diff --git a/spec/netsuite/records/invoice_spec.rb b/spec/netsuite/records/invoice_spec.rb index 4b654ec38..10753ce74 100644 --- a/spec/netsuite/records/invoice_spec.rb +++ b/spec/netsuite/records/invoice_spec.rb @@ -94,7 +94,7 @@ :merchant_account, :multi_subsidiary, :net_amount, :net_amount_no_tax, :next_bill_date, :no_auto_assign_location, :non_reimbursable, :one_time_total, :options, :order_allocation_strategy, :order_priority, - :originator, :other_ref_num, :overhead_parent_item, + :originator, :overhead_parent_item, :override_installments, :package_count, :paid_amount, :paid_transaction, :partner_contribution, :partner_role, :partner_team_member, :paying_amount, :paying_transaction, :payment_approved, From 232340cd42cb2dcb32a936633c7870f363ad0a1b Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Mon, 16 Aug 2021 20:39:07 -0400 Subject: [PATCH 044/114] Add simple specs around search_only_field(s) methods, matching read_only_field(s) --- spec/netsuite/support/fields_spec.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/netsuite/support/fields_spec.rb b/spec/netsuite/support/fields_spec.rb index ddcc1379f..f8d4e34a2 100644 --- a/spec/netsuite/support/fields_spec.rb +++ b/spec/netsuite/support/fields_spec.rb @@ -57,4 +57,30 @@ end end + describe '.search_only_fields' do + context 'with arguments' do + it 'calls .search_only_field with each argument passed to it' do + [:one, :two, :three].each do |field| + expect(klass).to receive(:search_only_field).with(field) + end + klass.search_only_fields(:one, :two, :three) + end + end + + context 'without arguments' do + it 'returns a Set of the search_only_field arguments' do + arguments = [:one, :two, :three] + klass.search_only_fields(*arguments) + expect(klass.search_only_fields).to eql(Set.new(arguments)) + end + end + end + + describe '.search_only_field' do + it 'defines instance accessor methods for the given field' do + expect(klass).to receive(:field).with(:one) + klass.search_only_field(:one) + end + end + end From 025f22bc90ebf743dffd4bfb1c98d97d80554d16 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Mon, 16 Aug 2021 21:42:54 -0400 Subject: [PATCH 045/114] Remove duplicate definition of replace_all field on MemberList Support::Sublist already defines the replace_all field. --- lib/netsuite/records/member_list.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/netsuite/records/member_list.rb b/lib/netsuite/records/member_list.rb index 8c03fea18..a03f1a066 100644 --- a/lib/netsuite/records/member_list.rb +++ b/lib/netsuite/records/member_list.rb @@ -3,8 +3,6 @@ module Records class MemberList < Support::Sublist include Namespaces::ListAcct - fields :replace_all - sublist :item_member, ItemMember end From b15f5cb1b15599f9fbb74c10df762bcc6bada14b Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Mon, 16 Aug 2021 22:12:38 -0400 Subject: [PATCH 046/114] Raise error if field is defined twice in record definition In adding the start of search_only_fields, a couple standard fields were mistakenly re-defined as search_only_fields, which ended up excluding them when pushing data to NetSuite, under the guise they were search-only. Now it's impossible to define the same field twice. As a result, had to fix a number of occurrences of fields repeated between `fields` and another definition (ie `record_refs`, `read_only_fields`, `field`). The only notable fix is on `Invoice`, where `bill_address` and `ship_address` were previously defined as `fields`, then got repeated as `search_only_fields`. In old APIs (<= 2014.1), these seemed to actually be fields, however in newer APIs (>= 2014.2), they no longer are. I'm erring on the side of newer APIs here, removing them as `fields` and leaving them as `search_only_fields`. Fixed #486 --- lib/netsuite/records/assembly_unbuild.rb | 4 +--- lib/netsuite/records/currency_rate.rb | 2 +- lib/netsuite/records/estimate.rb | 12 ++++++------ lib/netsuite/records/invoice.rb | 10 +++++----- lib/netsuite/records/invoice_item.rb | 2 +- lib/netsuite/records/item_fulfillment_item.rb | 2 +- lib/netsuite/records/item_receipt_item.rb | 2 +- lib/netsuite/records/non_inventory_purchase_item.rb | 2 +- lib/netsuite/records/non_inventory_resale_item.rb | 2 +- lib/netsuite/records/non_inventory_sale_item.rb | 2 +- lib/netsuite/records/opportunity.rb | 4 ++-- lib/netsuite/records/phone_call.rb | 2 +- lib/netsuite/records/serialized_assembly_item.rb | 1 - lib/netsuite/records/service_resale_item.rb | 2 +- lib/netsuite/records/service_sale_item.rb | 2 +- lib/netsuite/records/transfer_order_item.rb | 2 +- lib/netsuite/records/vendor.rb | 8 ++++---- lib/netsuite/support/fields.rb | 1 + spec/netsuite/support/fields_spec.rb | 11 ++++++++++- 19 files changed, 40 insertions(+), 33 deletions(-) diff --git a/lib/netsuite/records/assembly_unbuild.rb b/lib/netsuite/records/assembly_unbuild.rb index 1b0aa045a..763cb0d73 100644 --- a/lib/netsuite/records/assembly_unbuild.rb +++ b/lib/netsuite/records/assembly_unbuild.rb @@ -12,7 +12,7 @@ class AssemblyUnbuild :search fields :bin_numbers, :built, :created_date, :expiration_date, - :last_modified_date, :memo, :quantity, :serial_numbers, :total, + :last_modified_date, :memo, :quantity, :serial_numbers, :tran_date, :tran_id read_only_fields :total @@ -36,5 +36,3 @@ def initialize(attributes = {}) end end end - - diff --git a/lib/netsuite/records/currency_rate.rb b/lib/netsuite/records/currency_rate.rb index 39f940ff0..6ed7c962d 100644 --- a/lib/netsuite/records/currency_rate.rb +++ b/lib/netsuite/records/currency_rate.rb @@ -12,7 +12,7 @@ class CurrencyRate actions :get, :get_list, :search - fields :base_currency, :effective_date, :exchange_rate, :transaction_currency + fields :effective_date, :exchange_rate record_refs :base_currency, :transaction_currency diff --git a/lib/netsuite/records/estimate.rb b/lib/netsuite/records/estimate.rb index cc1602f59..d131964dd 100644 --- a/lib/netsuite/records/estimate.rb +++ b/lib/netsuite/records/estimate.rb @@ -10,12 +10,12 @@ class Estimate actions :get, :get_list, :add, :initialize, :delete, :update, :upsert, :search fields :alt_handling_cost, :alt_sales_total, :alt_shipping_cost, :balance, - :bill_address, :billing_address, :billing_schedule, :bill_is_residential, + :bill_address, :billing_schedule, :bill_is_residential, :created_date, :currency_name, :discount_rate, :email, :end_date, :est_gross_profit, :exchange_rate, :handling_cost, :handling_tax1_rate, :is_taxable, - :last_modified_date, :memo, :message, :other_ref_num, :ship_date, :shipping_cost, - :shipping_tax1_rate, :source, :start_date, :status, :sync_partner_teams, :sync_sales_teams, - :to_be_emailed, :to_be_faxed, :to_be_printed, :total_cost_estimate, :tran_date, :tran_id, + :last_modified_date, :memo, :message, :other_ref_num, :ship_date, :shipping_cost, + :shipping_tax1_rate, :source, :start_date, :status, :sync_partner_teams, :sync_sales_teams, + :to_be_emailed, :to_be_faxed, :to_be_printed, :total_cost_estimate, :tran_date, :tran_id, :linked_tracking_numbers, :is_multi_ship_to field :shipping_address, Address @@ -24,8 +24,8 @@ class Estimate field :item_list, EstimateItemList field :custom_field_list, CustomFieldList - record_refs :bill_address_list, :created_from, :currency, :custom_form, :department, :discount_item, :entity, - :handling_tax_code, :job, :klass, :lead_source, :location, :message_sel, :opportunity, :partner, + record_refs :bill_address_list, :created_from, :currency, :custom_form, :department, :discount_item, :entity, + :handling_tax_code, :job, :klass, :lead_source, :location, :message_sel, :opportunity, :partner, :promo_code, :sales_group, :sales_rep, :ship_method, :shipping_tax_code, :subsidiary, :terms attr_reader :internal_id diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 12e32b49b..997ed302f 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -11,8 +11,8 @@ class Invoice actions :get, :get_deleted, :get_list, :initialize, :add, :update, :delete, :upsert, :upsert_list, :search - fields :balance, :bill_address, - :billing_schedule, :contrib_pct, :created_date, :currency_name, :custom_field_list, + fields :balance, + :billing_schedule, :contrib_pct, :created_date, :currency_name, :deferred_revenue, :discount_amount, :discount_date, :discount_rate, :due_date, :email, :end_date, :est_gross_profit, :est_gross_profit_percent, :exchange_rate, :exclude_commission, :exp_cost_disc_amount, :exp_cost_disc_print, :exp_cost_disc_rate, :exp_cost_disc_tax_1_amt, @@ -24,13 +24,13 @@ class Invoice :linked_tracking_numbers, :memo, :message, :message_sel, :on_credit_hold, :opportunity, :other_ref_num, :partners_list, :rev_rec_end_date, :rev_rec_on_rev_commitment, :rev_rec_schedule, :rev_rec_start_date, :revenue_status, :sales_effective_date, - :sales_group, :sales_team_list, :ship_address, :ship_date, :ship_group_list, + :sales_group, :sales_team_list, :ship_date, :ship_group_list, :shipping_cost, :shipping_tax_1_rate, :shipping_tax_2_rate, :shipping_tax_code, :source, :start_date, :status, :sync_partner_teams, :sync_sales_teams, :tax_2_total, :tax_total, :time_disc_amount, :time_disc_print, :time_disc_rate, :time_disc_tax_1_amt, :time_disc_taxable, :time_discount, :time_list, :time_tax_code, :time_tax_rate_1, :time_tax_rate_2, :to_be_emailed, :to_be_faxed, :to_be_printed, :total_cost_estimate, :tracking_numbers, :tran_date, :tran_id, :tran_is_vsoe_bundle, - :transaction_bill_address, :transaction_ship_address, :vat_reg_num, :vsoe_auto_calc, :tax_rate + :vat_reg_num, :vsoe_auto_calc, :tax_rate field :transaction_bill_address, BillAddress field :transaction_ship_address, ShipAddress @@ -39,7 +39,7 @@ class Invoice field :shipping_address, Address field :billing_address, Address - read_only_fields :sub_total, :discount_total, :total, :recognized_revenue, :amount_remaining, :amount_paid, :amount, + 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 # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_2/schema/search/transactionsearchrowbasic.html?mode=package diff --git a/lib/netsuite/records/invoice_item.rb b/lib/netsuite/records/invoice_item.rb index c760b2bee..bf53483c2 100644 --- a/lib/netsuite/records/invoice_item.rb +++ b/lib/netsuite/records/invoice_item.rb @@ -9,7 +9,7 @@ class InvoiceItem fields :amount, :amount_ordered, :bin_numbers, :cost_estimate, :cost_estimate_type, :current_percent, :defer_rev_rec, :description, :gift_cert_from, :gift_cert_message, :gift_cert_number, :gift_cert_recipient_email, :gift_cert_recipient_name, :gross_amt, :inventory_detail, :is_taxable, :item_is_fulfilled, :license_code, :line, - :klass, :options, :order_line, :percent_complete, :quantity, :quantity_available, :quantity_fulfilled, + :options, :order_line, :percent_complete, :quantity, :quantity_available, :quantity_fulfilled, :quantity_on_hand, :quantity_ordered, :rate, :rev_rec_end_date, :rev_rec_start_date, :serial_numbers, :ship_group, :tax1_amt, :tax_rate1, :tax_rate2, :vsoe_allocation, :vsoe_amount, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price diff --git a/lib/netsuite/records/item_fulfillment_item.rb b/lib/netsuite/records/item_fulfillment_item.rb index 4dcc3549c..27fab331a 100644 --- a/lib/netsuite/records/item_fulfillment_item.rb +++ b/lib/netsuite/records/item_fulfillment_item.rb @@ -9,7 +9,7 @@ class ItemFulfillmentItem fields :amount, :amount_ordered, :bin_numbers, :cost_estimate, :cost_estimate_type, :current_percent, :defer_rev_rec, :description, :gift_cert_from, :gift_cert_message, :gift_cert_number, :gift_cert_recipient_email, :gift_cert_recipient_name, :gross_amt, :inventory_detail, :is_taxable, :item_is_fulfilled, :license_code, :line, - :klass, :options, :order_line, :percent_complete, :quantity, :quantity_available, :quantity_fulfilled, + :options, :order_line, :percent_complete, :quantity, :quantity_available, :quantity_fulfilled, :quantity_on_hand, :quantity_ordered, :rate, :rev_rec_end_date, :rev_rec_start_date, :serial_numbers, :ship_group, :tax1_amt, :tax_rate1, :tax_rate2, :vsoe_allocation, :vsoe_amount, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :item_receive diff --git a/lib/netsuite/records/item_receipt_item.rb b/lib/netsuite/records/item_receipt_item.rb index c9b927a16..0d921e7e4 100644 --- a/lib/netsuite/records/item_receipt_item.rb +++ b/lib/netsuite/records/item_receipt_item.rb @@ -7,7 +7,7 @@ class ItemReceiptItem include Namespaces::TranPurch fields :bin_numbers, :currency, :description, :expiration_date, :is_drop_shipment, - :item_name, :item_receive, :job_name, :line, :on_hand, :options, :order_line, + :item_name, :item_receive, :job_name, :line, :on_hand, :order_line, :quantity, :quantity_remaining, :rate, :restock, :serial_numbers, :unit_cost_override, :units_display diff --git a/lib/netsuite/records/non_inventory_purchase_item.rb b/lib/netsuite/records/non_inventory_purchase_item.rb index f321910aa..12d831eb0 100644 --- a/lib/netsuite/records/non_inventory_purchase_item.rb +++ b/lib/netsuite/records/non_inventory_purchase_item.rb @@ -17,7 +17,7 @@ class NonInventoryPurchaseItem :manufacturer_zip, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, - :preference_criterion, :presentation_item_list, :prices_include_tax, :pricing_matrix, :producer, :product_feed_list, + :preference_criterion, :presentation_item_list, :prices_include_tax, :producer, :product_feed_list, :rate, :related_items_description, :sales_description, :schedule_b_code, :schedule_b_number, :schedule_b_quantity, :search_keywords, :ship_individually, :shipping_cost, :shipping_cost_units, :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index 832dda4f0..25c084aa6 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -17,7 +17,7 @@ class NonInventoryResaleItem :manufacturer_zip, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, - :preference_criterion, :presentation_item_list, :prices_include_tax, :pricing_matrix, :producer, :product_feed_list, + :preference_criterion, :presentation_item_list, :prices_include_tax, :producer, :product_feed_list, :rate, :related_items_description, :sales_description, :schedule_b_code, :schedule_b_number, :schedule_b_quantity, :search_keywords, :ship_individually, :shipping_cost, :shipping_cost_units, :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index 7699b4637..832e267bf 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -17,7 +17,7 @@ class NonInventorySaleItem :manufacturer_zip, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, - :preference_criterion, :presentation_item_list, :prices_include_tax, :pricing_matrix, :producer, :product_feed_list, + :preference_criterion, :presentation_item_list, :prices_include_tax, :producer, :product_feed_list, :rate, :related_items_description, :sales_description, :schedule_b_code, :schedule_b_number, :schedule_b_quantity, :search_keywords, :ship_individually, :shipping_cost, :shipping_cost_units, :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, diff --git a/lib/netsuite/records/opportunity.rb b/lib/netsuite/records/opportunity.rb index d1cced560..7da4f0aef 100644 --- a/lib/netsuite/records/opportunity.rb +++ b/lib/netsuite/records/opportunity.rb @@ -17,7 +17,7 @@ class Opportunity :memo, :probability, :proj_alt_sales_amt, :projected_total, :range_high, :range_low, :ship_is_residential, :source, :status, :sync_partner_teams, :sync_sales_teams, - :tax2_total, :tax_total, :title, :total_cost_estimate, :tran_date, :tran_id, + :tax2_total, :title, :total_cost_estimate, :tran_date, :tran_id, :vat_reg_num, :weighted_total field :ship_address, ShipAddress @@ -43,4 +43,4 @@ def initialize(attributes = {}) end end -end \ No newline at end of file +end diff --git a/lib/netsuite/records/phone_call.rb b/lib/netsuite/records/phone_call.rb index e7c42d7eb..c6d68531a 100644 --- a/lib/netsuite/records/phone_call.rb +++ b/lib/netsuite/records/phone_call.rb @@ -10,7 +10,7 @@ class PhoneCall actions :get, :get_list, :add, :delete, :update, :upsert fields :title, :message, :phone, :status, :priority, :start_date, :end_date, - :start_time, :end_time, :completed_date, :timed_event, :access_level, :timed_event + :start_time, :end_time, :completed_date, :timed_event, :access_level field :contact_list, ContactList diff --git a/lib/netsuite/records/serialized_assembly_item.rb b/lib/netsuite/records/serialized_assembly_item.rb index 2802eb317..60c0c5866 100644 --- a/lib/netsuite/records/serialized_assembly_item.rb +++ b/lib/netsuite/records/serialized_assembly_item.rb @@ -180,7 +180,6 @@ class SerializedAssemblyItem :store_display_name, :store_display_thumbnail, :store_item_template, - :subsidiary_list, :supply_lot_sizing_method, :supply_replenishment_method, :supply_time_fence, diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index d5ee833b5..0eef3bc4b 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -15,7 +15,7 @@ class ServiceResaleItem :item_id, :last_modified_date, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :presentation_item_list, :prices_include_tax, - :pricing_matrix, :rate, :related_items_description, :sales_description, :search_keywords, + :rate, :related_items_description, :sales_description, :search_keywords, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, :store_description, :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :vsoe_sop_group diff --git a/lib/netsuite/records/service_sale_item.rb b/lib/netsuite/records/service_sale_item.rb index 85bcb30fb..5a1b361f4 100644 --- a/lib/netsuite/records/service_sale_item.rb +++ b/lib/netsuite/records/service_sale_item.rb @@ -15,7 +15,7 @@ class ServiceSaleItem :item_id, :last_modified_date, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :presentation_item_list, :prices_include_tax, - :pricing_matrix, :rate, :related_items_description, :sales_description, :search_keywords, + :rate, :related_items_description, :sales_description, :search_keywords, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, :store_description, :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :vsoe_sop_group diff --git a/lib/netsuite/records/transfer_order_item.rb b/lib/netsuite/records/transfer_order_item.rb index 84e163089..72d9337dc 100644 --- a/lib/netsuite/records/transfer_order_item.rb +++ b/lib/netsuite/records/transfer_order_item.rb @@ -8,7 +8,7 @@ class TransferOrderItem fields :amount, :average_cost, :klass, :commit_inventory, :description, :expected_receipt_date, :expected_ship_date, :inventory_detail, :is_closed, :last_purchase_price, - :line, :options, :order_priority, :quantity, :quantity_available, + :line, :order_priority, :quantity, :quantity_available, :quantity_back_ordered, :quantity_committed, :quantity_fulfilled, :quantity_on_hand, :quantity_packed, :quantity_picked, :quantity_received, :rate, :serial_numbers diff --git a/lib/netsuite/records/vendor.rb b/lib/netsuite/records/vendor.rb index 9c264ab76..caff2fbf7 100644 --- a/lib/netsuite/records/vendor.rb +++ b/lib/netsuite/records/vendor.rb @@ -9,16 +9,16 @@ class Vendor actions :get, :get_list, :add, :update, :upsert, :delete, :search - fields :account_number, :alt_email, :alt_name, :alt_phone, :balance, - :balance_primary, :bcn, :bill_pay, :comments, :company_name, :credit_limit, + fields :account_number, :alt_email, :alt_name, :alt_phone, + :bcn, :bill_pay, :comments, :company_name, :credit_limit, :date_created, :default_address, :eligible_for_commission, :email, :email_preference, :email_transactions, :entity_id, :fax, :fax_transactions, :first_name, :give_access, :global_subscription_status, :home_phone, :is1099_eligible, :is_accountant, :is_inactive, :is_job_resource_vend, :is_person, :labor_cost, - :last_modified_date, :last_name, :legal_name, :middle_name, :mobile_phone, :opening_balance, + :last_name, :legal_name, :middle_name, :mobile_phone, :opening_balance, :opening_balance_date, :password, :password2, :phone, :phonetic_name, :pricing_schedule_list, :print_on_check_as, :print_transactions, :require_pwd_change, :roles_list, :salutation, - :send_email, :subscriptions_list, :tax_id_num, :title, :unbilled_orders, :unbilled_orders_primary, + :send_email, :subscriptions_list, :tax_id_num, :title, :url, :vat_reg_number field :custom_field_list, CustomFieldList diff --git a/lib/netsuite/support/fields.rb b/lib/netsuite/support/fields.rb index 94d529e1d..56adb55dc 100644 --- a/lib/netsuite/support/fields.rb +++ b/lib/netsuite/support/fields.rb @@ -21,6 +21,7 @@ def fields(*args) def field(name, klass = nil) name_sym = name.to_sym + raise "#{name} already defined on #{self.name}" if fields.include?(name_sym) fields << name_sym if klass define_method(name_sym) do diff --git a/spec/netsuite/support/fields_spec.rb b/spec/netsuite/support/fields_spec.rb index f8d4e34a2..bffe8ba5e 100644 --- a/spec/netsuite/support/fields_spec.rb +++ b/spec/netsuite/support/fields_spec.rb @@ -1,9 +1,12 @@ require 'spec_helper' describe NetSuite::Support::Fields do - let(:klass) { Class.new.send(:include, NetSuite::Support::Fields) } + DummyRecord = Class.new.send(:include, NetSuite::Support::Fields) + let(:klass) { DummyRecord } let(:instance) { klass.new } + before { klass.fields.clear } + describe '.fields' do context 'with arguments' do it 'calls .field with each argument passed to it' do @@ -29,6 +32,12 @@ instance.one = 1 expect(instance.one).to eql(1) end + + it 'errors when already a field' do + klass.field :one + + expect { klass.field :one }.to raise_error('one already defined on DummyRecord') + end end describe '.read_only_fields' do From 7a5d0c01293a3cdae4435f2f473a26c10c1d314a Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Mon, 6 Sep 2021 12:23:38 -0600 Subject: [PATCH 047/114] Version bump --- HISTORY.md | 6 ++++++ lib/netsuite/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 20d62bde7..c01f6d46b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -10,6 +10,12 @@ * * +## 0.8.9 + +### Fixed + +* Fixed issue where search only fields could be specified when an existing field exists. https://github.com/NetSweet/netsuite/pull/488 + ## 0.8.8 ### Added diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index fd1dcde82..5a638ee88 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.8' + VERSION = '0.8.9' end From 9da0ef249feb0dc5382523f26650db07ca5d7bb0 Mon Sep 17 00:00:00 2001 From: Tim JK Date: Sun, 3 Oct 2021 10:36:08 -0300 Subject: [PATCH 048/114] Update README.md Method is called refresh, not reload --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1eb2bd567..7dddf95dc 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ task.update(message: 'New Message') task.delete # refresh/reload a record (helpful after adding the record for the first time) -task.reload +task.refresh # using get_select_value with a standard record NetSuite::Records::BaseRefList.get_select_value( From 3353bdd1628e5633d372ccea8c3bd3ac5c2a4a20 Mon Sep 17 00:00:00 2001 From: Hugues Bernet-Rollande Date: Mon, 11 Oct 2021 16:04:21 +0200 Subject: [PATCH 049/114] add inventory number update action --- lib/netsuite/records/inventory_number.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/inventory_number.rb b/lib/netsuite/records/inventory_number.rb index 67cef2e1a..83bf2e824 100644 --- a/lib/netsuite/records/inventory_number.rb +++ b/lib/netsuite/records/inventory_number.rb @@ -7,7 +7,7 @@ class InventoryNumber include Support::Actions include Namespaces::ListAcct - actions :get, :search + actions :get, :search, :update fields :expiration_date, :inventory_number, :isonhand, :memo, :status, :units, :location, :quantityavailable, :quantityintransit, :quantityonhand, :quantityonorder From 74d8db827c374494470ed94986face569efa1b6a Mon Sep 17 00:00:00 2001 From: Hugues Bernet-Rollande Date: Mon, 11 Oct 2021 16:02:42 +0200 Subject: [PATCH 050/114] adding `custom_field_list` to inventory transfer --- lib/netsuite/records/inventory_transfer.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/records/inventory_transfer.rb b/lib/netsuite/records/inventory_transfer.rb index 4e36be04f..0a4815092 100644 --- a/lib/netsuite/records/inventory_transfer.rb +++ b/lib/netsuite/records/inventory_transfer.rb @@ -12,6 +12,7 @@ class InventoryTransfer fields :klass, :created_date, :last_modified_date, :tran_date, :tran_id, :memo field :inventory_list, InventoryTransferInventoryList + field :custom_field_list, CustomFieldList record_refs :posting_period, :location, :transfer_location, :department, :subsidiary From f0e46a076d0e7cb2abd5e9001ccbfd4bbb3d35c3 Mon Sep 17 00:00:00 2001 From: Hugues Bernet-Rollande Date: Mon, 11 Oct 2021 15:59:46 +0200 Subject: [PATCH 051/114] fix incorrectly reference `:inventory_detail` to field instead of record_refs --- lib/netsuite/records/item_receipt_item.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/netsuite/records/item_receipt_item.rb b/lib/netsuite/records/item_receipt_item.rb index 0d921e7e4..0bc4b60a3 100644 --- a/lib/netsuite/records/item_receipt_item.rb +++ b/lib/netsuite/records/item_receipt_item.rb @@ -11,11 +11,12 @@ class ItemReceiptItem :quantity, :quantity_remaining, :rate, :restock, :serial_numbers, :unit_cost_override, :units_display - record_refs :bill_variance_status, :inventory_detail, :item, :landed_cost, + record_refs :bill_variance_status, :item, :landed_cost, :location field :options, CustomFieldList field :custom_field_list, CustomFieldList + field :inventory_detail, InventoryDetail def initialize(attributes_or_record = {}) case attributes_or_record From 7264a51cd5610aafbad08801d3e566fbaf16f31f Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Wed, 20 Oct 2021 21:08:07 -0400 Subject: [PATCH 052/114] Update Estimate fields/record_refs for 2021.2 (#496) A couple were missing for my use case, so I updated them based on 2021.2 This effectively removes the `balance` and `bill_is_residential` fields. Best I can tell going back to 2014.1, they were never fields. Perhaps this was a bad copy-paste when first introducing `Estimate` using another record as a starting point? `is_multi_ship_to` was also removed as it's technically a field of `TransactionSearchRowBasic`, not `Estimate`. It never could have been set, and at best it only could have been read after a search. Ideally it'd be reintroduced in the future as an expansion on the work in #483, extracting a common module to represent the fields from `TransactionSearchRowBasic`. `bill_address` was also removed as it last appeared in 2014.1. Now it's a field of `TransactionSearchRowBasic`, so it could be re-introduced later, like above. `billing_schedule` was corrected to be a `record_ref`. `accountingBookDetailList`, `partnersList`, `salesTeamList`, `shipGroupList`, and `taxDetailsList` are still missing as `record_refs` as their corresponding classes haven't been implemented yet. I improved the `have_field` matcher to optionally take a class argument for testing the fields that are represented by special classes. I deviated from the standard style of multiple-fields-per-line-wrapped for a single-field-per-line style. I found the old style hard to read, particularly when the fields fell out of alphabetical order, when scanning to see either what fields were available, or what fields were already supported. I'd imagine this'll make for cleaner git diffs in the future too. --- HISTORY.md | 4 +- lib/netsuite/records/estimate.rb | 109 ++++++++++++++++++++--- spec/netsuite/records/estimate_spec.rb | 116 ++++++++++++++++++++++--- spec/support/field_matcher.rb | 14 +-- 4 files changed, 208 insertions(+), 35 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index c01f6d46b..ac317b1b2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,7 +2,7 @@ ### Added -* +* Update Estimate record fields/record refs for 2021.2. `balance`, `bill_address`, `bill_is_residential`, and `is_multi_ship_to` were all removed as fields as either being incorrect, outdated, or a search-only field. (#496) * ### Fixed @@ -29,4 +29,4 @@ * Fix accessing custom field values returned in advanced search results (#480) * Fixing bug where single-selection custom multi select fields would incorrectly be parsed 3377c971d0cb727d81f4b4bc6e30edfbdfaccfd1 * Fixed some field definitions on serialized assembly item -* Properly extract external_id from advanced search results (#478) \ No newline at end of file +* Properly extract external_id from advanced search results (#478) diff --git a/lib/netsuite/records/estimate.rb b/lib/netsuite/records/estimate.rb index d131964dd..41e11631b 100644 --- a/lib/netsuite/records/estimate.rb +++ b/lib/netsuite/records/estimate.rb @@ -9,24 +9,105 @@ class Estimate actions :get, :get_list, :add, :initialize, :delete, :update, :upsert, :search - fields :alt_handling_cost, :alt_sales_total, :alt_shipping_cost, :balance, - :bill_address, :billing_schedule, :bill_is_residential, - :created_date, :currency_name, :discount_rate, :email, :end_date, - :est_gross_profit, :exchange_rate, :handling_cost, :handling_tax1_rate, :is_taxable, - :last_modified_date, :memo, :message, :other_ref_num, :ship_date, :shipping_cost, - :shipping_tax1_rate, :source, :start_date, :status, :sync_partner_teams, :sync_sales_teams, - :to_be_emailed, :to_be_faxed, :to_be_printed, :total_cost_estimate, :tran_date, :tran_id, - :linked_tracking_numbers, :is_multi_ship_to + fields :alt_handling_cost, + :alt_sales_total, + :alt_shipping_cost, + :can_have_stackable, + :contrib_pct, + :created_date, + :currency_name, + :discount_rate, + :discount_total, + :due_date, + :email, + :end_date, + :est_gross_profit, + :est_gross_profit_percent, + :exchange_rate, + :expected_close_date, + :fax, + :fob, + :handling_cost, + :handling_tax1_rate, + :handling_tax2_rate, + :include_in_forecast, + :is_taxable, + :last_modified_date, + :linked_tracking_numbers, + :memo, + :message, + :one_time, + :other_ref_num, + :probability, + :recur_annually, + :recur_monthly, + :recur_quarterly, + :recur_weekly, + :ship_date, + :ship_is_residential, + :shipping_cost, + :shipping_tax1_rate, + :shipping_tax2_rate, + :source, + :start_date, + :status, + :sub_total, + :sync_partner_teams, + :sync_sales_teams, + :tax2_total, + :tax_details_override, + :tax_point_date, + :tax_rate, + :tax_reg_override, + :tax_total, + :title, + :to_be_emailed, + :to_be_faxed, + :to_be_printed, + :total, + :total_cost_estimate, + :tracking_numbers, + :tran_date, + :tran_id, + :vat_reg_num, + :visible_to_customer - field :shipping_address, Address field :billing_address, Address - - field :item_list, EstimateItemList field :custom_field_list, CustomFieldList + field :item_list, EstimateItemList + field :promotions_list, PromotionsList + field :shipping_address, Address - record_refs :bill_address_list, :created_from, :currency, :custom_form, :department, :discount_item, :entity, - :handling_tax_code, :job, :klass, :lead_source, :location, :message_sel, :opportunity, :partner, - :promo_code, :sales_group, :sales_rep, :ship_method, :shipping_tax_code, :subsidiary, :terms + record_refs :bill_address_list, + :billing_schedule, + :klass, + :created_from, + :currency, + :custom_form, + :department, + :discount_item, + :entity, + :entity_status, + :entity_tax_reg_num, + :forecast_type, + :handling_tax_code, + :job, + :lead_source, + :location, + :message_sel, + :nexus, + :opportunity, + :partner, + :promo_code, + :sales_group, + :sales_rep, + :ship_address_list, + :ship_method, + :shipping_tax_code, + :subsidiary, + :subsidiary_tax_reg_num, + :tax_item, + :terms attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/estimate_spec.rb b/spec/netsuite/records/estimate_spec.rb index 9c6546696..7731e827a 100644 --- a/spec/netsuite/records/estimate_spec.rb +++ b/spec/netsuite/records/estimate_spec.rb @@ -7,27 +7,117 @@ it 'has all the right fields' do [ - :alt_handling_cost, :alt_shipping_cost, - :balance, :bill_address, :created_date, :currency_name, - :discount_rate, :email, :end_date, :est_gross_profit, + :alt_handling_cost, + :alt_sales_total, + :alt_shipping_cost, + :can_have_stackable, + :contrib_pct, + :created_date, + :currency_name, + :discount_rate, + :discount_total, + :due_date, + :email, + :end_date, + :est_gross_profit, + :est_gross_profit_percent, :exchange_rate, - :handling_cost, :handling_tax1_rate, :is_taxable, - :last_modified_date, :memo, :message, :other_ref_num, - :shipping_cost, :shipping_tax1_rate, - :source, :start_date, :status, :sync_partner_teams, - :sync_sales_teams, :to_be_emailed, :to_be_faxed, :to_be_printed, - :total_cost_estimate, :tran_date, :tran_id + :expected_close_date, + :fax, + :fob, + :handling_cost, + :handling_tax1_rate, + :handling_tax2_rate, + :include_in_forecast, + :is_taxable, + :last_modified_date, + :linked_tracking_numbers, + :memo, + :message, + :one_time, + :other_ref_num, + :probability, + :recur_annually, + :recur_monthly, + :recur_quarterly, + :recur_weekly, + :ship_date, + :ship_is_residential, + :shipping_cost, + :shipping_tax1_rate, + :shipping_tax2_rate, + :source, + :start_date, + :status, + :sub_total, + :sync_partner_teams, + :sync_sales_teams, + :tax2_total, + :tax_details_override, + :tax_point_date, + :tax_rate, + :tax_reg_override, + :tax_total, + :title, + :to_be_emailed, + :to_be_faxed, + :to_be_printed, + :total, + :total_cost_estimate, + :tracking_numbers, + :tran_date, + :tran_id, + :vat_reg_num, + :visible_to_customer, ].each do |field| expect(estimate).to have_field(field) end end + it 'has all the right fields with specific classes' do + { + billing_address: NetSuite::Records::Address, + custom_field_list: NetSuite::Records::CustomFieldList, + item_list: NetSuite::Records::EstimateItemList, + promotions_list: NetSuite::Records::PromotionsList, + shipping_address: NetSuite::Records::Address, + }.each do |field, klass| + expect(estimate).to have_field(field, klass) + end + end + it 'has all the right record refs' do [ - :bill_address_list, :created_from, :currency, :custom_form, :department, :discount_item, - :entity, :handling_tax_code, :job, :klass, :lead_source, :location, :message_sel, - :opportunity, :partner, :promo_code, :sales_group, :sales_rep, - :ship_method, :shipping_tax_code, :subsidiary + :bill_address_list, + :billing_schedule, + :klass, + :created_from, + :currency, + :custom_form, + :department, + :discount_item, + :entity, + :entity_status, + :entity_tax_reg_num, + :forecast_type, + :handling_tax_code, + :job, + :lead_source, + :location, + :message_sel, + :nexus, + :opportunity, + :partner, + :promo_code, + :sales_group, + :sales_rep, + :ship_address_list, + :ship_method, + :shipping_tax_code, + :subsidiary, + :subsidiary_tax_reg_num, + :tax_item, + :terms, ].each do |record_ref| expect(estimate).to have_record_ref(record_ref) end diff --git a/spec/support/field_matcher.rb b/spec/support/field_matcher.rb index 0233b84a3..a748a0e34 100644 --- a/spec/support/field_matcher.rb +++ b/spec/support/field_matcher.rb @@ -1,17 +1,19 @@ -RSpec::Matchers.define :have_field do |attribute| +RSpec::Matchers.define :have_field do |attribute, klass| match do |model| - field_can_be_set_and_retrieved?(model, attribute) && field_can_be_set_on_instantiation?(model, attribute) + klass = klass || Object + + field_can_be_set_and_retrieved?(model, attribute, klass) && field_can_be_set_on_instantiation?(model, attribute, klass) end - def field_can_be_set_and_retrieved?(model, attribute) - obj = Object.new + def field_can_be_set_and_retrieved?(model, attribute, klass) + obj = klass.new model.send("#{attribute}=".to_sym, obj) model.send(attribute) == obj end - def field_can_be_set_on_instantiation?(model, attribute) - obj = Object.new + def field_can_be_set_on_instantiation?(model, attribute, klass) + obj = klass.new new_model = model.class.new(attribute => obj) new_model.send(attribute) == obj end From e0b9f4501e428cc8ffd94b2da0f4c87d00806ff3 Mon Sep 17 00:00:00 2001 From: andrewdicken-stripe <89274571+andrewdicken-stripe@users.noreply.github.com> Date: Tue, 16 Nov 2021 11:40:49 -0800 Subject: [PATCH 053/114] Updating necessary savon version (#497) --- netsuite.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netsuite.gemspec b/netsuite.gemspec index ec1b6a727..d69be399a 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.version = NetSuite::VERSION - gem.add_dependency 'savon', '>= 2.3.0', '<= 2.11.1' + gem.add_dependency 'savon', '>= 2.3.0' gem.add_development_dependency 'rspec', '~> 3.10.0' gem.add_development_dependency 'rake' From b4a078e9c5a0a14b2baea3a5e07da696ef982c3c Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 16 Nov 2021 12:43:31 -0700 Subject: [PATCH 054/114] Version bump --- HISTORY.md | 12 +++++++++--- lib/netsuite/version.rb | 2 +- netsuite.gemspec | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index ac317b1b2..66f1a361b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,14 +1,20 @@ ## Unreleased ### Added +* -* Update Estimate record fields/record refs for 2021.2. `balance`, `bill_address`, `bill_is_residential`, and `is_multi_ship_to` were all removed as fields as either being incorrect, outdated, or a search-only field. (#496) +### Fixed * +## 0.8.10 + +### Added + +* Update Estimate record fields/record refs for 2021.2. `balance`, `bill_address`, `bill_is_residential`, and `is_multi_ship_to` were all removed as fields as either being incorrect, outdated, or a search-only field. (#496) + ### Fixed -* -* +* Savon 2.12 supported ## 0.8.9 diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index 5a638ee88..98c3aebd2 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.9' + VERSION = '0.8.10' end diff --git a/netsuite.gemspec b/netsuite.gemspec index d69be399a..8504bceaf 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -15,6 +15,7 @@ Gem::Specification.new do |gem| gem.name = 'netsuite' gem.require_paths = ['lib'] gem.version = NetSuite::VERSION + gem.metadata['changelog_uri'] = 'https://github.com/netsweet/netsuite/blob/master/HISTORY.md' gem.add_dependency 'savon', '>= 2.3.0' From 75e5ae286b12bc70c98290afe9cf96451753d6fa Mon Sep 17 00:00:00 2001 From: Sim Greenbaum <44986920+gbs4ever@users.noreply.github.com> Date: Thu, 2 Dec 2021 08:49:53 -0500 Subject: [PATCH 055/114] added gem 'tzinfo-data' to pass all test for ruby 3.0.0 (#498) * add gem 'tzinfo-data' for ruby 3.0.0 * Update main.yml added back ruby 3.0..0 --- .github/workflows/main.yml | 4 ++-- Gemfile | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f0d4f223a..5524217a2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: [2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] + ruby-version: [3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] steps: - uses: actions/checkout@v2 - name: Set up Ruby ${{ matrix.ruby-version }} @@ -17,4 +17,4 @@ jobs: - name: Install dependencies run: bundle install - name: Run tests - run: bundle exec rake \ No newline at end of file + run: bundle exec rake diff --git a/Gemfile b/Gemfile index baaedc3c2..4b6f7977a 100644 --- a/Gemfile +++ b/Gemfile @@ -8,4 +8,5 @@ gem 'pry-rescue' # optional dependency for more accurate timezone conversion gem 'tzinfo', '1.2.5' -# gem 'tzinfo', '2.0.0' \ No newline at end of file +# gem 'tzinfo', '2.0.0' +gem 'tzinfo-data' From 5c1d56e9fb221068f89ed26b7ff70b2725dcca1a Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 14 Dec 2021 07:06:19 -0500 Subject: [PATCH 056/114] Update ServiceResaleItem fields/record_refs for 2021.2 (#500) A couple were missing for my use case, so I updated them based on 2021.2 The following "fields" were removed as "fields" since they require specialized record classes that haven't been implemented yet: - cost_estimate_type - item_options_list - matrix_type - out_of_stock_behavior - overall_quantity_pricing_type - presentation_item_list - site_category_list - sitemap_priority - translations_list - vsoe_deferral - vsoe_permit_discount - vsoe_sop_group I arbitrarily went back 5 years (to version 2016.1) and these were all using specialized types back then, so this doesn't appear to have been a recent change on the NetSuite side of things that might affect users of this gem. --- HISTORY.md | 2 +- lib/netsuite/records/service_resale_item.rb | 142 +++++++++++++++--- .../records/service_resale_item_spec.rb | 131 +++++++++++++--- 3 files changed, 238 insertions(+), 37 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 66f1a361b..1270599f9 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,7 +1,7 @@ ## Unreleased ### Added -* +* Update ServiceResaleItem record fields/record refs for 2021.2. `cost_estimate_type`, `item_options_list`, `matrix_type`, `out_of_stock_behavior`, `overall_quantity_pricing_type`, `presentation_item_list`, `site_category_list`, `sitemap_priority`, `translations_list`, `vsoe_deferral`, `vsoe_permit_discount`, `vsoe_sop_group` were all removed as fields as the are not simple fields, they require special classes. (#500) ### Fixed * diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index 0eef3bc4b..47431baae 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -9,28 +9,132 @@ class ServiceResaleItem actions :get, :get_list, :add, :update, :delete, :upsert, :search - fields :available_to_partners, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :create_job, :created_date, - :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, - :include_children, :is_donation_item, :is_fulfillable, :is_gco_compliant, :is_inactive, :is_online, :is_taxable, - :item_id, :last_modified_date, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, - :minimum_quantity, :minimum_quantity_units, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, - :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :presentation_item_list, :prices_include_tax, - :rate, :related_items_description, :sales_description, :search_keywords, - :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, - :store_description, :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, - :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :vsoe_sop_group - - # item_task_templates_list - # billing_rates_matrix -- RecordRef, via listAcct::ItemOptionsList - - record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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, :store_display_image, - :store_display_thumbnail, :store_item_template, :tax_schedule, :units_type + fields :amortization_period, + :available_to_partners, + :contingent_revenue_handling, + :cost, + :cost_estimate, + :cost_estimate_units, + :cost_units, + :created_date, + :create_job, + :currency, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :generate_accruals, + :include_children, + :is_donation_item, + :is_fulfillable, + :is_gco_compliant, + :is_inactive, + :is_online, + :is_taxable, + :item_id, + :last_modified_date, + :manufacturing_charge_item, + :matrix_item_name_template, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_message, + :page_title, + :prices_include_tax, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :residual, + :sales_description, + :search_keywords, + :show_default_donation_amount, + :soft_descriptor, + :specials_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vendor_name, + :vsoe_delivered, + :vsoe_price + + record_refs :amortization_template, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :deferral_account, + :deferred_revenue_account, + :department, + :expense_account, + :income_account, + :interco_def_rev_account, + :interco_expense_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type, + :vendor - field :pricing_matrix, PricingMatrix field :custom_field_list, CustomFieldList + field :item_vendor_list, ItemVendorList + field :matrix_option_list, MatrixOptionList + field :pricing_matrix, PricingMatrix field :subsidiary_list, RecordRefList + # TODO: field :accounting_book_detail_list, ItemAccountingBookDetailList + # TODO: field :billing_rates_matrix, BillingRatesMatrix + # TODO: field :cost_estimate_type, ItemCostEstimateType + # TODO: field :item_options_list, ItemOptionsList + # TODO: field :item_task_templates_list, ServiceItemTaskTemplatesList + # TODO: field :hierarchy_versions_list, ServiceResaleItemHierarchyVersionsList + # TODO: field :matrix_type, ItemMatrixType + # TODO: field :out_of_stock_behavior, ItemOutOfStockBehavior + # TODO: field :overall_quantity_pricing_type, ItemOverallQuantityPricingType + # TODO: field :presentation_item_list, PresentationItemList + # TODO: field :site_category_list, SiteCategoryList + # TODO: field :sitemap_priority, SitemapPriority + # TODO: field :translations_list, TranslationList + # TODO: field :vsoe_deferral, VsoeDeferral + # TODO: field :vsoe_permit_discount, VsoePermitDiscount + # TODO: field :vsoe_sop_group, VsoeSopGroup attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/service_resale_item_spec.rb b/spec/netsuite/records/service_resale_item_spec.rb index b59f99176..76de57471 100644 --- a/spec/netsuite/records/service_resale_item_spec.rb +++ b/spec/netsuite/records/service_resale_item_spec.rb @@ -5,31 +5,128 @@ it 'has the right fields' do [ - :available_to_partners, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :create_job, :created_date, - :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, - :include_children, :is_donation_item, :is_fulfillable, :is_gco_compliant, :is_inactive, :is_online, :is_taxable, - :item_id, :last_modified_date, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, - :minimum_quantity, :minimum_quantity_units, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, - :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :presentation_item_list, :prices_include_tax, - :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, - :store_description, :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, - :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :vsoe_sop_group + :amortization_period, + :available_to_partners, + :contingent_revenue_handling, + :cost, + :cost_estimate, + :cost_estimate_units, + :cost_units, + :created_date, + :create_job, + :currency, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :generate_accruals, + :include_children, + :is_donation_item, + :is_fulfillable, + :is_gco_compliant, + :is_inactive, + :is_online, + :is_taxable, + :item_id, + :last_modified_date, + :manufacturing_charge_item, + :matrix_item_name_template, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_message, + :page_title, + :prices_include_tax, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :residual, + :sales_description, + :search_keywords, + :show_default_donation_amount, + :soft_descriptor, + :specials_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vendor_name, + :vsoe_delivered, + :vsoe_price, ].each do |field| expect(item).to have_field(field) end + end - # TODO there is a probably a more robust way to test this - expect(item.custom_field_list.class).to eq(NetSuite::Records::CustomFieldList) - expect(item.pricing_matrix.class).to eq(NetSuite::Records::PricingMatrix) - expect(item.subsidiary_list.class).to eq(NetSuite::Records::RecordRefList) + it 'has all the right fields with specific classes' do + { + custom_field_list: NetSuite::Records::CustomFieldList, + item_vendor_list: NetSuite::Records::ItemVendorList, + matrix_option_list: NetSuite::Records::MatrixOptionList, + pricing_matrix: NetSuite::Records::PricingMatrix, + subsidiary_list: NetSuite::Records::RecordRefList, + }.each do |field, klass| + expect(item).to have_field(field, klass) + end end it 'has the right record_refs' do [ - :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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, :store_display_image, - :store_display_thumbnail, :store_item_template, :tax_schedule, :units_type + :amortization_template, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :deferral_account, + :deferred_revenue_account, + :department, + :expense_account, + :income_account, + :interco_def_rev_account, + :interco_expense_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type, + :vendor, ].each do |record_ref| expect(item).to have_record_ref(record_ref) end From f502ac33b7f1ec32d795571986739cc85a3c8e6e Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 14 Dec 2021 07:13:47 -0500 Subject: [PATCH 057/114] Fix "undefined method `[]' for #" when adding File (#495) When calling `File#add`, the response XML sets a `type="file"` attribute on the `baseRef` element, where "file" corresponds to the NetSuite record. This then causes Nori (the XML parser used by Savon, the SOAP client) to interpret that element as representing a base64 encoded file, so it tries to get fancy about how it parses that element into a hash by returning an instance of it's `StringIOFile` class: https://github.com/savonrb/nori/blob/f59f8e18b0e53285c87d75a635058745e66b0bfb/lib/nori/xml_utility_node.rb#L131-L136 Either NetSuite's doing something non-standard with it's use of the `type` attribute that Nori is trying to enforce, or Nori is over-aggressive in trying to typecast to aid the developer. The end result was that when we tried to extract the `internal_id` from the response, the `body` was actually an instance of `StringIOFile`, not a hash: https://github.com/NetSweet/netsuite/blob/f0e46a076d0e7cb2abd5e9001ccbfd4bbb3d35c3/lib/netsuite/actions/add.rb#L80 To work around this, as I don't see a way to disable such behavior in Savon/Nori, if we detect the `baseRef` element was parsed to `StringIOFile`, we'll then take the raw XML and parse out the `baseRef` ourselves, returning a hash with the `internal_id` as we'd exect from non-`File` responses. I'm not thrilled with this solution. If we ever needed something else from the `baseRef` element, this effectively drops all other attributes for file records. It also introduces explicit references to `Nori` and `Nokogiri`, both of which are dependencies of Savon, but I'm not sure if that means this gem should list them as explicit dependencies to guard against Savon replacing them in a future update. Listing them as dependencies would then require keeping their version constraints in sync with Savon most likely. I believe this answers a question from #481: https://github.com/NetSweet/netsuite/pull/481#discussion_r674351298 However the fix in #481 solves it by not trying to extract the `internal_id`, which would create a problem if someone wanted to add a file then save the ID in their own database for future use. --- HISTORY.md | 1 + lib/netsuite/actions/add.rb | 6 ++++- spec/netsuite/actions/add_spec.rb | 36 ++++++++++++++++++++++++++ spec/support/fixtures/add/add_file.xml | 20 ++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 spec/support/fixtures/add/add_file.xml diff --git a/HISTORY.md b/HISTORY.md index 1270599f9..f5610d7c2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,7 @@ * Update ServiceResaleItem record fields/record refs for 2021.2. `cost_estimate_type`, `item_options_list`, `matrix_type`, `out_of_stock_behavior`, `overall_quantity_pricing_type`, `presentation_item_list`, `site_category_list`, `sitemap_priority`, `translations_list`, `vsoe_deferral`, `vsoe_permit_discount`, `vsoe_sop_group` were all removed as fields as the are not simple fields, they require special classes. (#500) ### Fixed +* Fix "undefined method `[]` for #" when adding File (#495) * ## 0.8.10 diff --git a/lib/netsuite/actions/add.rb b/lib/netsuite/actions/add.rb index 4cc352661..8acc99e86 100644 --- a/lib/netsuite/actions/add.rb +++ b/lib/netsuite/actions/add.rb @@ -49,7 +49,11 @@ def success? end def response_body - @response_body ||= response_hash[:base_ref] + @response_body ||= if response_hash[:base_ref].is_a?(Nori::StringIOFile) + { :@internal_id => Nokogiri::XML(@response.to_s).remove_namespaces!.at_xpath('//baseRef')[:internalId] } + else + response_hash[:base_ref] + end end def response_errors diff --git a/spec/netsuite/actions/add_spec.rb b/spec/netsuite/actions/add_spec.rb index c55403c28..2be80d272 100644 --- a/spec/netsuite/actions/add_spec.rb +++ b/spec/netsuite/actions/add_spec.rb @@ -114,4 +114,40 @@ end end + context 'File' do + let(:file) do + NetSuite::Records::File.new(name: 'foo.pdf', content: 'abc123') + end + + context 'when successful' do + before do + savon.expects(:add).with(:message => { + 'platformMsgs:record' => { + :content! => { + 'fileCabinet:name' => 'foo.pdf', + 'fileCabinet:content' => 'abc123', + }, + '@xsi:type' => 'fileCabinet:File' + }, + }).returns(File.read('spec/support/fixtures/add/add_file.xml')) + end + + it 'makes a valid request to the NetSuite API' do + NetSuite::Actions::Add.call([file]) + end + + it 'returns a valid Response object' do + response = NetSuite::Actions::Add.call([file]) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end + + it 'properly extracts internal ID from response' do + file.add + + expect(file.internal_id).to eq('23556') + end + end + end + end diff --git a/spec/support/fixtures/add/add_file.xml b/spec/support/fixtures/add/add_file.xml new file mode 100644 index 000000000..99c9962b5 --- /dev/null +++ b/spec/support/fixtures/add/add_file.xml @@ -0,0 +1,20 @@ + + + + + REDACTED + + + + + + + + false + + + + + + + From cd107f98efecae6bfb201bcd81ecb6f19e8ed120 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 14 Dec 2021 05:16:25 -0700 Subject: [PATCH 058/114] Dependabot setup --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..8545fc442 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + # Maintain dependencies for rubygems + - package-ecosystem: "bundler" + directory: "/" + schedule: + interval: "daily" From d5956afef8080a6528b579215b538874cca47932 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 14 Dec 2021 05:27:28 -0700 Subject: [PATCH 059/114] Updating changelog --- HISTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index f5610d7c2..f7c75212c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,9 @@ ### Added * Update ServiceResaleItem record fields/record refs for 2021.2. `cost_estimate_type`, `item_options_list`, `matrix_type`, `out_of_stock_behavior`, `overall_quantity_pricing_type`, `presentation_item_list`, `site_category_list`, `sitemap_priority`, `translations_list`, `vsoe_deferral`, `vsoe_permit_discount`, `vsoe_sop_group` were all removed as fields as the are not simple fields, they require special classes. (#500) +* Dependabot to CI +* CI run for Ruby 3 +* Add CI run for an environment with and without `tzinfo` installed ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) From 1deab7927f4be4be2489f8291c02135906f11d99 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 14 Dec 2021 05:23:50 -0700 Subject: [PATCH 060/114] Fix spec to work without tzinfo --- spec/netsuite/utilities_spec.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/netsuite/utilities_spec.rb b/spec/netsuite/utilities_spec.rb index 5e11a961b..035d64d0e 100644 --- a/spec/netsuite/utilities_spec.rb +++ b/spec/netsuite/utilities_spec.rb @@ -13,11 +13,19 @@ no_dst_stamp = DateTime.parse('Sun, November 6 2017 00:00:00 -0000') formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp.to_time.to_i) - expect(formatted_date).to eq('2017-11-06T00:00:00-08:00') + if Gem.loaded_specs.has_key?('tzinfo') + expect(formatted_date).to eq('2017-11-06T00:00:00-08:00') + else + expect(formatted_date).to eq('2017-11-06T00:00:00-07:00') + end no_dst_stamp_with_time = DateTime.parse('Sun, November 6 2017 12:11:10 -0000') formatted_date = NetSuite::Utilities.normalize_time_to_netsuite_date(no_dst_stamp_with_time.to_time.to_i) - expect(formatted_date).to eq('2017-11-06T00:00:00-08:00') + if Gem.loaded_specs.has_key?('tzinfo') + expect(formatted_date).to eq('2017-11-06T00:00:00-08:00') + else + expect(formatted_date).to eq('2017-11-06T00:00:00-07:00') + end end end end From b75d70cd6a0f0af5bb58197167c9d39fcf0e3ec5 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 14 Dec 2021 05:19:51 -0700 Subject: [PATCH 061/114] Test tzinfo support across matrix --- .github/workflows/main.yml | 5 ++++- Gemfile | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5524217a2..024b919b4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,6 @@ name: Ruby -on: [push,pull_request] +on: [push, pull_request] jobs: build: @@ -8,6 +8,9 @@ jobs: strategy: matrix: ruby-version: [3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] + bundle-tzinfo: [true, false] + env: + BUNDLE_TZINFO: "${{ matrix.bundle-tzinfo }}" steps: - uses: actions/checkout@v2 - name: Set up Ruby ${{ matrix.ruby-version }} diff --git a/Gemfile b/Gemfile index 4b6f7977a..5ef6f16b1 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,8 @@ gem 'simplecov', :require => false gem 'pry-nav' gem 'pry-rescue' -# optional dependency for more accurate timezone conversion -gem 'tzinfo', '1.2.5' -# gem 'tzinfo', '2.0.0' -gem 'tzinfo-data' + +if ENV.fetch('BUNDLE_TZINFO', 'false') == 'true' + # optional dependency for more accurate timezone conversion + gem 'tzinfo', '>= 1.2.5' +end From 8be86c9c3d5e137a69299df9e019c7c9cef2f888 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 16 Dec 2021 18:28:44 -0500 Subject: [PATCH 062/114] Implement MatrixOptionList#to_record (#504) When creating a matrix child item, you pass the matrix options, but without #to_record, the right XML wasn't generated. --- HISTORY.md | 1 + lib/netsuite/records/matrix_option_list.rb | 16 ++++++++++++ .../records/matrix_option_list_spec.rb | 26 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index f7c75212c..062e75e25 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,7 @@ * Dependabot to CI * CI run for Ruby 3 * Add CI run for an environment with and without `tzinfo` installed +* Implement MatrixOptionList#to_record (#504) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) diff --git a/lib/netsuite/records/matrix_option_list.rb b/lib/netsuite/records/matrix_option_list.rb index af0790205..55a29b745 100644 --- a/lib/netsuite/records/matrix_option_list.rb +++ b/lib/netsuite/records/matrix_option_list.rb @@ -1,6 +1,8 @@ module NetSuite module Records class MatrixOptionList + include Namespaces::ListAcct + # Deals with both hash and arrays of attributes[:matrix_option_list] # # Hash: @@ -50,6 +52,20 @@ def initialize(attributes = {}) def options @options ||= [] end + + def to_record + { + "#{record_namespace}:matrixOption" => options.map do |option| + { + 'platformCore:value' => { + '@internalId' => option.value_id, + '@typeId' => option.type_id, + }, + '@scriptId' => option.script_id + } + end + } + end end end end diff --git a/spec/netsuite/records/matrix_option_list_spec.rb b/spec/netsuite/records/matrix_option_list_spec.rb index f0ccc1cc3..034018c02 100644 --- a/spec/netsuite/records/matrix_option_list_spec.rb +++ b/spec/netsuite/records/matrix_option_list_spec.rb @@ -4,6 +4,8 @@ module NetSuite module Records describe MatrixOptionList do + let(:list) { described_class.new } + it "deals with hash properly" do hash = {:value=>{:@internal_id=>"1", :@type_id=>"36", :name=>"some value"}, :@script_id=>'cust_field_1'} @@ -30,6 +32,30 @@ module Records expect(option.name).to eq "some value 28" expect(option.script_id).to eq "cust_field_28" end + + describe '#to_record' do + before do + list.options << OpenStruct.new( + type_id: 'TYPE', + value_id: 'VALUE', + script_id: 'SCRIPT', + name: 'NAME', + ) + end + + it 'can represent itself as a SOAP record' do + record = { + 'listAcct:matrixOption' => [{ + '@scriptId' => 'SCRIPT', + 'platformCore:value' => { + '@internalId' => 'VALUE', + '@typeId' => 'TYPE', + }, + }], + } + expect(list.to_record).to eql(record) + end + end end end end From 3bc60d6c777846c2cb3e359e37775322ff04fa2d Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 16 Dec 2021 18:29:32 -0500 Subject: [PATCH 063/114] Update NonInventorySaleItem fields/record_refs for 2021.2 (#503) A couple were missing for my use case, so I updated them based on 2021.2 The following "fields"/"record refs" were removed as "fields"/"record refs" since they require specialized record classes that haven't been implemented yet: * item_options_list * presentation_item_list * product_feed_list * site_category_list * translations_list I arbitrarily went back 5 years (to version 2016.1) and these were all using specialized types back then, so this doesn't appear to have been a recent change on the NetSuite side of things that might affect users of this gem. Co-authored-by: Michael Bianco --- HISTORY.md | 1 + .../records/non_inventory_sale_item.rb | 153 ++++++++++++++--- .../records/non_inventory_sale_item_spec.rb | 157 +++++++++++++++--- 3 files changed, 269 insertions(+), 42 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 062e75e25..29322db10 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,7 @@ * Dependabot to CI * CI run for Ruby 3 * Add CI run for an environment with and without `tzinfo` installed +* Update NonInventorySaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#503) * Implement MatrixOptionList#to_record (#504) ### Fixed diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index 832e267bf..2d786a7d8 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -9,31 +9,144 @@ class NonInventorySaleItem actions :get, :get_list, :add, :delete, :search, :update, :upsert - fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, - :created_date, :direct_revenue_posting, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, - :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable, - :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer, - :manufacturer_addr1, :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, - :manufacturer_zip, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, - :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, - :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, - :preference_criterion, :presentation_item_list, :prices_include_tax, :producer, :product_feed_list, - :rate, :related_items_description, :sales_description, :schedule_b_code, :schedule_b_number, :schedule_b_quantity, - :search_keywords, :ship_individually, :shipping_cost, :shipping_cost_units, :shopping_dot_com_category, - :shopzilla_category_id, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, - :specials_description, :stock_description, :store_description, :store_detailed_description, :store_display_name, - :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, - :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + fields :available_to_partners, + :contingent_revenue_handling, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :country_of_manufacture, + :created_date, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :is_donation_item, + :is_fulfillable, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_taxable, + :item_carrier, + :item_id, + :last_modified_date, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :preference_criterion, + :prices_include_tax, + :producer, + :rate, + :related_items_description, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :soft_descriptor, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units - record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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 + record_refs :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :department, + :income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :ship_package, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type field :custom_field_list, CustomFieldList + field :item_ship_method_list, RecordRefList + field :matrix_option_list, MatrixOptionList field :pricing_matrix, PricingMatrix field :subsidiary_list, RecordRefList - + # TODO: field :accounting_book_detail_list, ItemAccountingBookDetailList + # TODO: field :hierarchy_versions_list, NonInventorySaleItemHierarchyVersionsList + # TODO: field :item_options_list, ItemOptionsList + # TODO: field :presentation_item_list, PresentationItemList + # TODO: field :product_feed_list, ProductFeedList + # TODO: field :site_category_list, SiteCategoryList + # TODO: field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/non_inventory_sale_item_spec.rb b/spec/netsuite/records/non_inventory_sale_item_spec.rb index 723324f39..43e26dbc0 100644 --- a/spec/netsuite/records/non_inventory_sale_item_spec.rb +++ b/spec/netsuite/records/non_inventory_sale_item_spec.rb @@ -5,36 +5,149 @@ it 'has the right fields' do [ - :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, :created_date, - :direct_revenue_posting, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, - :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable, - :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer, :manufacturer_addr1, - :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :matrix_option_list, - :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, - :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, - :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :preference_criterion, :presentation_item_list, - :prices_include_tax, :producer, :product_feed_list, :rate, :related_items_description, :sales_description, - :schedule_b_code, :schedule_b_number, :schedule_b_quantity, :search_keywords, :ship_individually, :shipping_cost, - :shipping_cost_units, :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, - :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, :stock_description, :store_description, - :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, :use_marginal_rates, - :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + :available_to_partners, + :contingent_revenue_handling, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :country_of_manufacture, + :created_date, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :is_donation_item, + :is_fulfillable, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_taxable, + :item_carrier, + :item_id, + :last_modified_date, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :preference_criterion, + :prices_include_tax, + :producer, + :rate, + :related_items_description, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :soft_descriptor, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units, ].each do |field| expect(item).to have_field(field) end + end - # TODO there is a probably a more robust way to test this - expect(item.custom_field_list.class).to eq(NetSuite::Records::CustomFieldList) - expect(item.pricing_matrix.class).to eq(NetSuite::Records::PricingMatrix) - expect(item.subsidiary_list.class).to eq(NetSuite::Records::RecordRefList) + it 'has all the right fields with specific classes' do + { + custom_field_list: NetSuite::Records::CustomFieldList, + item_ship_method_list: NetSuite::Records::RecordRefList, + matrix_option_list: NetSuite::Records::MatrixOptionList, + pricing_matrix: NetSuite::Records::PricingMatrix, + subsidiary_list: NetSuite::Records::RecordRefList, + }.each do |field, klass| + expect(item).to have_field(field, klass) + end end it 'has the right record_refs' do [ - :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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 + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :department, + :income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :ship_package, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type, ].each do |record_ref| expect(item).to have_record_ref(record_ref) end From 70db1a1c526b3b4bb0dde5ae8758dc63fb516c3a Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 16 Dec 2021 18:29:51 -0500 Subject: [PATCH 064/114] Fix enum fields removed from ServiceResaleItem mistakenly (#502) I jumped the gun in #500 and removed these fields assuming their custom types had to be implemented in the gem, but a few were just enums, such as `sitemap_priority`, which shouldn't need a custom type class as we get a string value back: ```xml _auto ``` https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/enum/sitemappriority.html?mode=package Perhaps one day these enums should exist in the gem so you can refer to the values by something like a constant rather than a magic string (ie. `SitemapPriority::AUTO` vs "_auto"), but for now, the magic string is probably sufficient. --- HISTORY.md | 2 +- lib/netsuite/records/service_resale_item.rb | 18 +++++++++--------- .../records/service_resale_item_spec.rb | 8 ++++++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 29322db10..7af7a6641 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,7 +1,7 @@ ## Unreleased ### Added -* Update ServiceResaleItem record fields/record refs for 2021.2. `cost_estimate_type`, `item_options_list`, `matrix_type`, `out_of_stock_behavior`, `overall_quantity_pricing_type`, `presentation_item_list`, `site_category_list`, `sitemap_priority`, `translations_list`, `vsoe_deferral`, `vsoe_permit_discount`, `vsoe_sop_group` were all removed as fields as the are not simple fields, they require special classes. (#500) +* Update ServiceResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#500) * Dependabot to CI * CI run for Ruby 3 * Add CI run for an environment with and without `tzinfo` installed diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index 47431baae..3b68e04df 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -14,6 +14,7 @@ class ServiceResaleItem :contingent_revenue_handling, :cost, :cost_estimate, + :cost_estimate_type, :cost_estimate_units, :cost_units, :created_date, @@ -38,6 +39,7 @@ class ServiceResaleItem :last_modified_date, :manufacturing_charge_item, :matrix_item_name_template, + :matrix_type, :max_donation_amount, :maximum_quantity, :meta_tag_html, @@ -46,7 +48,9 @@ class ServiceResaleItem :no_price_message, :offer_support, :on_special, + :out_of_stock_behavior, :out_of_stock_message, + :overall_quantity_pricing_type, :page_title, :prices_include_tax, :purchase_description, @@ -62,6 +66,7 @@ class ServiceResaleItem :sales_description, :search_keywords, :show_default_donation_amount, + :sitemap_priority, :soft_descriptor, :specials_description, :store_description, @@ -71,8 +76,11 @@ class ServiceResaleItem :url_component, :use_marginal_rates, :vendor_name, + :vsoe_deferral, :vsoe_delivered, - :vsoe_price + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group record_refs :amortization_template, :bill_exch_rate_variance_acct, @@ -121,20 +129,12 @@ class ServiceResaleItem field :subsidiary_list, RecordRefList # TODO: field :accounting_book_detail_list, ItemAccountingBookDetailList # TODO: field :billing_rates_matrix, BillingRatesMatrix - # TODO: field :cost_estimate_type, ItemCostEstimateType # TODO: field :item_options_list, ItemOptionsList # TODO: field :item_task_templates_list, ServiceItemTaskTemplatesList # TODO: field :hierarchy_versions_list, ServiceResaleItemHierarchyVersionsList - # TODO: field :matrix_type, ItemMatrixType - # TODO: field :out_of_stock_behavior, ItemOutOfStockBehavior - # TODO: field :overall_quantity_pricing_type, ItemOverallQuantityPricingType # TODO: field :presentation_item_list, PresentationItemList # TODO: field :site_category_list, SiteCategoryList - # TODO: field :sitemap_priority, SitemapPriority # TODO: field :translations_list, TranslationList - # TODO: field :vsoe_deferral, VsoeDeferral - # TODO: field :vsoe_permit_discount, VsoePermitDiscount - # TODO: field :vsoe_sop_group, VsoeSopGroup attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/service_resale_item_spec.rb b/spec/netsuite/records/service_resale_item_spec.rb index 76de57471..0913501b0 100644 --- a/spec/netsuite/records/service_resale_item_spec.rb +++ b/spec/netsuite/records/service_resale_item_spec.rb @@ -10,6 +10,7 @@ :contingent_revenue_handling, :cost, :cost_estimate, + :cost_estimate_type, :cost_estimate_units, :cost_units, :created_date, @@ -34,6 +35,7 @@ :last_modified_date, :manufacturing_charge_item, :matrix_item_name_template, + :matrix_type, :max_donation_amount, :maximum_quantity, :meta_tag_html, @@ -42,7 +44,9 @@ :no_price_message, :offer_support, :on_special, + :out_of_stock_behavior, :out_of_stock_message, + :overall_quantity_pricing_type, :page_title, :prices_include_tax, :purchase_description, @@ -58,6 +62,7 @@ :sales_description, :search_keywords, :show_default_donation_amount, + :sitemap_priority, :soft_descriptor, :specials_description, :store_description, @@ -67,8 +72,11 @@ :url_component, :use_marginal_rates, :vendor_name, + :vsoe_deferral, :vsoe_delivered, + :vsoe_permit_discount, :vsoe_price, + :vsoe_sop_group, ].each do |field| expect(item).to have_field(field) end From 56667d836c7422a9b89add5cc315d00e841b18a7 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sat, 18 Dec 2021 08:51:45 -0500 Subject: [PATCH 065/114] Update InventoryItem fields/record_refs for 2021.2 (#506) A couple were missing for my use case, so I updated them based on 2021.2 `member_list` was removed as a field as it doesn't exist on InventoryItem in the NetSuite schema. It was added back in a108ae4d to appease searching, at a time when KitItem inherited from InventoryItem, which is no longer the case. If I'm understanding the ItemSearchRowBasic schema correctly, it's not returned as a field there: https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2021_2/schema/search/itemsearchrowbasic.html?mode=package --- HISTORY.md | 1 + lib/netsuite/records/inventory_item.rb | 271 ++++++++++++++++--- spec/netsuite/records/inventory_item_spec.rb | 261 ++++++++++++++++-- 3 files changed, 475 insertions(+), 58 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 7af7a6641..3929ce059 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,6 +7,7 @@ * Add CI run for an environment with and without `tzinfo` installed * Update NonInventorySaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#503) * Implement MatrixOptionList#to_record (#504) +* Update InventoryItem record fields/record refs for 2021.2. `member_list` was removed as a field as it doesn't belong to InventoryItem. (#506) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index 1850d04d0..a0c2cda17 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -22,28 +22,169 @@ class InventoryItem # actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list - fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, - :copy_description, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, - :costing_method_display, :country_of_manufacture, :created_date, :currency, :date_converted_to_inv, - :default_return_cost, :demand_modifier, :display_name, :dont_show_price, :enforce_min_qty_internally, - :exclude_from_sitemap, :featured_description, :fixed_lot_size, :handling_cost, :handling_cost_units, :include_children, - :is_donation_item, :is_drop_ship_item, :is_gco_compliant, :is_inactive, :is_online, :is_special_order_item, :is_taxable, - :item_id, :last_modified_date, :last_purchase_price, :lead_time, :manufacturer, :manufacturer_addr1, :manufacturer_city, - :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :match_bill_to_receipt, - :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, - :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_hand_value_mli, :on_special, - :original_item_subtype, :original_item_type, :out_of_stock_behavior, :out_of_stock_message, - :overall_quantity_pricing_type, :page_title, :preference_criterion, :preferred_stock_level, :preferred_stock_level_days, - :preferred_stock_level_units, :prices_include_tax, :producer, :purchase_description, :quantity_available, - :quantity_available_units, :quantity_back_ordered, :quantity_committed, :quantity_committed_units, :quantity_on_hand, - :quantity_on_hand_units, :quantity_on_order, :quantity_on_order_units, :quantity_reorder_units, :rate, - :related_items_description, :reorder_multiple, :reorder_point, :reorder_point_units, :safety_stock_level, - :safety_stock_level_days, :safety_stock_level_units, :sales_description, :schedule_b_code, :schedule_b_number, - :schedule_b_quantity, :search_keywords, :seasonal_demand, :ship_individually, :shipping_cost, :shipping_cost_units, - :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, :sitemap_priority, - :specials_description, :stock_description, :store_description, :store_detailed_description, :store_display_name, - :total_value, :track_landed_cost, :transfer_price, :upc_code, :url_component, :use_bins, :use_marginal_rates, - :vendor_name, :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + fields :auto_lead_time, + :auto_preferred_stock_level, + :auto_reorder_point, + :available_to_partners, + :average_cost, + :backward_consumption_days, + :contingent_revenue_handling, + :conversion_rate, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :costing_method, + :costing_method_display, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :date_converted_to_inv, + :default_return_cost, + :defer_rev_rec, + :demand_modifier, + :demand_time_fence, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enable_catch_weight, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :fixed_lot_size, + :forward_consumption_days, + :fraud_risk, + :future_horizon, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :invt_classification, + :invt_count_interval, + :is_donation_item, + :is_drop_ship_item, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_store_pickup_allowed, + :is_taxable, + :item_carrier, + :item_id, + :last_invt_count_date, + :last_modified_date, + :last_purchase_price, + :lead_time, + :lower_warning_limit, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :match_bill_to_receipt, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :next_invt_count_date, + :no_price_message, + :offer_support, + :on_hand_value_mli, + :on_special, + :original_item_subtype, + :original_item_type, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :periodic_lot_size_days, + :periodic_lot_size_type, + :preference_criterion, + :preferred_stock_level, + :preferred_stock_level_days, + :preferred_stock_level_units, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :quantity_available, + :quantity_available_units, + :quantity_back_ordered, + :quantity_committed, + :quantity_committed_units, + :quantity_on_hand, + :quantity_on_hand_units, + :quantity_on_order, + :quantity_on_order_units, + :quantity_reorder_units, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :reorder_multiple, + :reorder_point, + :reorder_point_units, + :reschedule_in_days, + :reschedule_out_days, + :round_up_as_component, + :safety_stock_level, + :safety_stock_level_days, + :safety_stock_level_units, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :seasonal_demand, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :supply_time_fence, + :total_value, + :track_landed_cost, + :transfer_price, + :upc_code, + :upper_warning_limit, + :url_component, + :use_bins, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_2/schema/search/itemsearchrowbasic.html?mode=package search_only_fields :acc_book_rev_rec_forecast_rule, :accounting_book, @@ -105,25 +246,83 @@ class InventoryItem :vendor_price_currency, :vendor_schedule, :vend_return_variance_account, :web_site, :wip_acct, :wip_variance_acct, :yahoo_product_feed - 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, - :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, - :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor, :create_revenue_plans_on, - :revenue_recognition_rule, :rev_rec_forecast_rule + record_refs :alternate_demand_source_item, + :asset_account, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :cogs_account, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :demand_source, + :department, + :distribution_category, + :distribution_network, + :dropship_expense_account, + :expense_account, + :gain_loss_account, + :income_account, + :interco_cogs_account, + :interco_def_rev_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :planning_item_category, + :preferred_location, + :pricing_group, + :purchase_price_variance_acct, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :secondary_base_unit, + :secondary_consumption_unit, + :secondary_purchase_unit, + :secondary_sale_unit, + :secondary_stock_unit, + :secondary_units_type, + :ship_package, + :soft_descriptor, + :stock_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :supply_lot_sizing_method, + :supply_replenishment_method, + :supply_type, + :tax_schedule, + :units_type, + :vendor - field :pricing_matrix, PricingMatrix - field :custom_field_list, CustomFieldList field :bin_number_list, BinNumberList - field :locations_list, LocationsList + field :custom_field_list, CustomFieldList + field :item_ship_method_list, RecordRefList field :item_vendor_list, ItemVendorList + field :locations_list, LocationsList field :matrix_option_list, MatrixOptionList + field :pricing_matrix, PricingMatrix field :subsidiary_list, RecordRefList - - # for Assembly/Kit - field :member_list, MemberList + # TODO: :accounting_book_detail_list, ItemAccountingBookDetailList + # TODO: :hierarchy_versions_list, InventoryItemHierarchyVersionsList + # TODO: :item_options_list, ItemOptionsList + # TODO: :presentation_item_list, PresentationItemList + # TODO: :product_feed_list, ProductFeedList + # TODO: :site_category_list, SiteCategoryList + # TODO: :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id, :search_joins diff --git a/spec/netsuite/records/inventory_item_spec.rb b/spec/netsuite/records/inventory_item_spec.rb index 6251151cd..b92852d0b 100644 --- a/spec/netsuite/records/inventory_item_spec.rb +++ b/spec/netsuite/records/inventory_item_spec.rb @@ -5,27 +5,169 @@ it 'has all the right fields' do [ - :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, :copy_description, - :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, :costing_method_display, - :country_of_manufacture, :created_date, :currency, :date_converted_to_inv, :default_return_cost, :demand_modifier, - :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, :fixed_lot_size, - :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_drop_ship_item, :is_gco_compliant, - :is_inactive, :is_online, :is_special_order_item, :is_taxable, :item_id, :last_modified_date, :last_purchase_price, - :lead_time, :manufacturer, :manufacturer_addr1, :manufacturer_city, :manufacturer_state, :manufacturer_tariff, - :manufacturer_tax_id, :manufacturer_zip, :match_bill_to_receipt, :matrix_type, :max_donation_amount, :meta_tag_html, - :minimum_quantity, :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, - :offer_support, :on_hand_value_mli, :on_special, :original_item_subtype, :original_item_type, :out_of_stock_behavior, - :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :preference_criterion, :preferred_stock_level, - :preferred_stock_level_days, :preferred_stock_level_units, :prices_include_tax, :producer, :purchase_description, - :quantity_available, :quantity_available_units, :quantity_back_ordered, :quantity_committed, :quantity_committed_units, - :quantity_on_hand, :quantity_on_hand_units, :quantity_on_order, :quantity_on_order_units, :quantity_reorder_units, :rate, - :related_items_description, :reorder_multiple, :reorder_point, :reorder_point_units, :safety_stock_level, - :safety_stock_level_days, :safety_stock_level_units, :sales_description, :schedule_b_code, :schedule_b_number, - :schedule_b_quantity, :search_keywords, :seasonal_demand, :ship_individually, :shipping_cost, :shipping_cost_units, - :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, :sitemap_priority, :specials_description, - :stock_description, :store_description, :store_detailed_description, :store_display_name, :total_value, :track_landed_cost, - :transfer_price, :upc_code, :url_component, :use_bins, :use_marginal_rates, :vendor_name, :vsoe_deferral, :vsoe_delivered, - :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + :auto_lead_time, + :auto_preferred_stock_level, + :auto_reorder_point, + :available_to_partners, + :average_cost, + :backward_consumption_days, + :contingent_revenue_handling, + :conversion_rate, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :costing_method, + :costing_method_display, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :date_converted_to_inv, + :default_return_cost, + :defer_rev_rec, + :demand_modifier, + :demand_time_fence, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enable_catch_weight, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :fixed_lot_size, + :forward_consumption_days, + :fraud_risk, + :future_horizon, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :invt_classification, + :invt_count_interval, + :is_donation_item, + :is_drop_ship_item, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_store_pickup_allowed, + :is_taxable, + :item_carrier, + :item_id, + :last_invt_count_date, + :last_modified_date, + :last_purchase_price, + :lead_time, + :lower_warning_limit, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :match_bill_to_receipt, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :next_invt_count_date, + :no_price_message, + :offer_support, + :on_hand_value_mli, + :on_special, + :original_item_subtype, + :original_item_type, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :periodic_lot_size_days, + :periodic_lot_size_type, + :preference_criterion, + :preferred_stock_level, + :preferred_stock_level_days, + :preferred_stock_level_units, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :quantity_available, + :quantity_available_units, + :quantity_back_ordered, + :quantity_committed, + :quantity_committed_units, + :quantity_on_hand, + :quantity_on_hand_units, + :quantity_on_order, + :quantity_on_order_units, + :quantity_reorder_units, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :reorder_multiple, + :reorder_point, + :reorder_point_units, + :reschedule_in_days, + :reschedule_out_days, + :round_up_as_component, + :safety_stock_level, + :safety_stock_level_days, + :safety_stock_level_units, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :seasonal_demand, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :supply_time_fence, + :total_value, + :track_landed_cost, + :transfer_price, + :upc_code, + :upper_warning_limit, + :url_component, + :use_bins, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units, ].each do |field| expect(item).to have_field(field) end @@ -95,9 +237,84 @@ end end + it 'has all the right fields with specific classes' do + { + bin_number_list: NetSuite::Records::BinNumberList, + custom_field_list: NetSuite::Records::CustomFieldList, + item_ship_method_list: NetSuite::Records::RecordRefList, + item_vendor_list: NetSuite::Records::ItemVendorList, + locations_list: NetSuite::Records::LocationsList, + matrix_option_list: NetSuite::Records::MatrixOptionList, + pricing_matrix: NetSuite::Records::PricingMatrix, + subsidiary_list: NetSuite::Records::RecordRefList, + }.each do |field, klass| + expect(item).to have_field(field, klass) + end + end + it 'has all the right record refs' do [ - :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, :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, :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor + :alternate_demand_source_item, + :asset_account, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :cogs_account, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :demand_source, + :department, + :distribution_category, + :distribution_network, + :dropship_expense_account, + :expense_account, + :gain_loss_account, + :income_account, + :interco_cogs_account, + :interco_def_rev_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :planning_item_category, + :preferred_location, + :pricing_group, + :purchase_price_variance_acct, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_reclass_f_x_account, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :secondary_base_unit, + :secondary_consumption_unit, + :secondary_purchase_unit, + :secondary_sale_unit, + :secondary_stock_unit, + :secondary_units_type, + :ship_package, + :soft_descriptor, + :stock_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :supply_lot_sizing_method, + :supply_replenishment_method, + :supply_type, + :tax_schedule, + :units_type, + :vendor, ].each do |record_ref| expect(item).to have_record_ref(record_ref) end From 3975245b5571fb1baeb8884325b9014adcbfde77 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sat, 18 Dec 2021 08:52:38 -0500 Subject: [PATCH 066/114] Update ItemVendor fields/record_refs for 2021.2 (#505) A couple were missing for my use case, so I updated them based on 2021.2 `vendor` got moved from a `field` to a `record_ref`. I arbitrarily went back 5 years (to version 2016.1) and it was still a `RecordRef` back then, so this doesn't appear to have been a recent change on the NetSuite side of things that might affect users of this gem. Co-authored-by: Michael Bianco --- HISTORY.md | 1 + lib/netsuite/records/item_vendor.rb | 11 ++++++++++- spec/netsuite/records/item_vendor_list_spec.rb | 7 ++----- spec/netsuite/records/item_vendor_spec.rb | 16 ++++++++++++++-- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 3929ce059..f04b98e79 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,6 +7,7 @@ * Add CI run for an environment with and without `tzinfo` installed * Update NonInventorySaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#503) * Implement MatrixOptionList#to_record (#504) +* Update ItemVendor record fields/record refs for 2021.1. `vendor` is now a record_ref instead of a field. (#505) * Update InventoryItem record fields/record refs for 2021.2. `member_list` was removed as a field as it doesn't belong to InventoryItem. (#506) ### Fixed diff --git a/lib/netsuite/records/item_vendor.rb b/lib/netsuite/records/item_vendor.rb index 91c7d788c..d14bc1496 100644 --- a/lib/netsuite/records/item_vendor.rb +++ b/lib/netsuite/records/item_vendor.rb @@ -2,10 +2,19 @@ module NetSuite module Records class ItemVendor include Support::Fields + include Support::RecordRefs include Support::Records include Namespaces::ListAcct - fields :vendor, :purchase_price, :preferred_vendor + fields :purchase_price, + :preferred_vendor, + :vendor_code, + :vendor_currency_name + + record_refs :schedule, + :subsidiary, + :vendor, + :vendor_currency def initialize(attributes = {}) initialize_from_attributes_hash(attributes) diff --git a/spec/netsuite/records/item_vendor_list_spec.rb b/spec/netsuite/records/item_vendor_list_spec.rb index bfae58a37..d018337f5 100644 --- a/spec/netsuite/records/item_vendor_list_spec.rb +++ b/spec/netsuite/records/item_vendor_list_spec.rb @@ -10,17 +10,14 @@ describe '#to_record' do before do list.item_vendors << NetSuite::Records::ItemVendor.new( - :vendor => {:name => 'Spring Water'} + :vendor_code => 'Spring Water', ) end it 'can represent itself as a SOAP record' do record = { "listAcct:itemVendor"=>[ - {"listAcct:vendor"=>{ - :name=>"Spring Water" - } - } + {"listAcct:vendorCode"=>"Spring Water"} ] } diff --git a/spec/netsuite/records/item_vendor_spec.rb b/spec/netsuite/records/item_vendor_spec.rb index 534db5c31..67ea6d452 100644 --- a/spec/netsuite/records/item_vendor_spec.rb +++ b/spec/netsuite/records/item_vendor_spec.rb @@ -5,11 +5,23 @@ it 'has all the right fields' do [ - :vendor, :purchase_price, :preferred_vendor + :purchase_price, + :preferred_vendor, + :vendor_code, + :vendor_currency_name, ].each do |field| expect(vendor).to have_field(field) end end - it 'has all the right record refs' + it 'has all the right record refs' do + [ + :schedule, + :subsidiary, + :vendor, + :vendor_currency, + ].each do |field| + expect(vendor).to have_record_ref(field) + end + end end From d8b130a2ef164b75e29b236397fa96996634270a Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 21 Dec 2021 07:32:59 -0500 Subject: [PATCH 067/114] Update LotNumberedInventoryItem fields/record_refs for 2021.2 (#507) A couple were missing for my use case, so I updated them based on 2021.2 --- HISTORY.md | 1 + .../records/lot_numbered_inventory_item.rb | 304 +++++++++++++----- .../lot_numbered_inventory_item_spec.rb | 246 ++++++++++++++ 3 files changed, 471 insertions(+), 80 deletions(-) create mode 100644 spec/netsuite/records/lot_numbered_inventory_item_spec.rb diff --git a/HISTORY.md b/HISTORY.md index f04b98e79..ae2135405 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,6 +9,7 @@ * Implement MatrixOptionList#to_record (#504) * Update ItemVendor record fields/record refs for 2021.1. `vendor` is now a record_ref instead of a field. (#505) * Update InventoryItem record fields/record refs for 2021.2. `member_list` was removed as a field as it doesn't belong to InventoryItem. (#506) +* Update LotNumberedInventoryItem record fields/record refs for 2021.2. (#507) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) diff --git a/lib/netsuite/records/lot_numbered_inventory_item.rb b/lib/netsuite/records/lot_numbered_inventory_item.rb index 027f27a91..81103f88d 100644 --- a/lib/netsuite/records/lot_numbered_inventory_item.rb +++ b/lib/netsuite/records/lot_numbered_inventory_item.rb @@ -9,94 +9,238 @@ class LotNumberedInventoryItem # http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2018_2/schema/record/lotnumberedinventoryitem.html - # TODO - # countryOfManufacture Country - # hazmatPackingGroup HazmatPackingGroup - # accountingBookDetailList ItemAccountingBookDetailList - # costEstimateType ItemCostEstimateType - # costingMethod ItemCostingMethod - # invtClassification ItemInvtClassification - # matrixType ItemMatrixType - # itemOptionsList ItemOptionsList - # outOfStockBehavior ItemOutOfStockBehavior - # overallQuantityPricingType ItemOverallQuantityPricingType - # preferenceCriterion ItemPreferenceCriterion - # itemVendorList ItemVendorList - # weightUnit ItemWeightUnit - # hierarchyVersionsList LotNumberedInventoryItemHierarchyVersionsList - # numbersList LotNumberedInventoryItemNumbersList - # periodicLotSizeType PeriodicLotSizeType - # presentationItemList PresentationItemList - # productFeedList ProductFeedList - - field :pricing_matrix, PricingMatrix - field :custom_field_list, CustomFieldList field :bin_number_list, BinNumberList - field :locations_list, LocationsList + field :custom_field_list, CustomFieldList + field :item_number_options_list, RecordRefList + field :item_ship_method_list, RecordRefList field :item_vendor_list, ItemVendorList + field :locations_list, LocationsList field :matrix_option_list, MatrixOptionList + field :pricing_matrix, PricingMatrix field :subsidiary_list, RecordRefList + # TODO: field :accounting_book_detail_list, ItemAccountingBookDetailList + # TODO: field :hierarchy_versions_list, LotNumberedInventoryItemHierarchyVersionsList + # TODO: field :item_options_list, ItemOptionsList + # TODO: field :numbers_list, LotNumberedInventoryItemNumbersList + # TODO: field :presentation_item_list, PresentationItemList + # TODO: field :product_feed_list, ProductFeedList + # TODO: field :site_category_list, SiteCategoryList + # TODO: field :translations_list, TranslationList actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list - record_refs :alternate_demand_source_item, :asset_account, :bill_exch_rate_variance_acct, - :billing_schedule, :bill_price_variance_acct, :bill_qty_variance_acct, - :klass, :cogs_account, :cost_category, :create_revenue_plans_on, - :custom_form, :default_item_ship_method, :deferred_revenue_account, - :demand_source, :department, :dropship_expense_account, :gain_loss_account, - :income_account, :interco_cogs_account, :interco_income_account, - :issue_product, :item_revenue_category, :location, :parent, :preferred_location, - :pricing_group, :purchase_price_variance_acct, :purchase_tax_code, :purchase_unit, - :quantity_pricing_schedule, :revenue_allocation_group, :revenue_recognition_rule, - :rev_rec_forecast_rule, :rev_rec_schedule, :sales_tax_code, :sale_unit, - :ship_package, :soft_descriptor, :stock_unit, :store_display_image, - :store_display_thumbnail, :store_item_template, :supply_lot_sizing_method, - :supply_replenishment_method, :supply_type, :tax_schedule, :units_type, :vendor - - # TODO - # itemNumberOptionsList RecordRefList - # itemShipMethodList RecordRefList - # subsidiaryList RecordRefList - # scheduleBCode ScheduleBCode - # itemCarrier ShippingCarrier - # siteCategoryList SiteCategoryList - # sitemapPriority SitemapPriority - # translationsList TranslationList - # vsoeDeferral VsoeDeferral - # vsoePermitDiscount VsoePermitDiscount - # vsoeSopGroup VsoeSopGroup - - fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, - :copy_description, :direct_revenue_posting, :dont_show_price, :enforce_min_qty_internally, - :exclude_from_sitemap, :include_children, :is_donation_item, :is_drop_ship_item, :is_gco_compliant, - :is_hazmat_item, :is_inactive, :is_online, :is_special_order_item, :is_store_pickup_allowed, - :is_taxable, :match_bill_to_receipt, :mult_manufacture_addr, :offer_support, :on_special, - :prices_include_tax, :producer, :round_up_as_component, :seasonal_demand, :ship_individually, - :show_default_donation_amount, :track_landed_cost, :use_bins, :use_marginal_rates, :vsoe_delivered, - :created_date, :expiration_date, :last_invt_count_date, :last_modified_date, :next_invt_count_date, - :average_cost, :cost, :cost_estimate, :default_return_cost, :demand_modifier, :fixed_lot_size, - :handling_cost, :hazmat_item_units_qty, :last_purchase_price, :max_donation_amount, - :on_hand_value_mli, :preferred_stock_level, :preferred_stock_level_days, :purchase_order_amount, - :purchase_order_quantity, :purchase_order_quantity_diff, :quantity_available, - :quantity_back_ordered, :quantity_committed, :quantity_on_hand, :quantity_on_order, - :rate, :receipt_amount, :receipt_quantity, :receipt_quantity_diff, :reorder_point, - :safety_stock_level, :shipping_cost, :total_value, :transfer_price, :vsoe_price, - :weight, :backward_consumption_days, :demand_time_fence, :forward_consumption_days, - :invt_count_interval, :lead_time, :maximum_quantity, :minimum_quantity, :periodic_lot_size_days, - :reorder_multiple, :reschedule_in_days, :reschedule_out_days, :safety_stock_level_days, - :schedule_b_quantity, :shopzilla_category_id, :supply_time_fence, :costing_method_display, - :cost_units, :currency, :display_name, :featured_description, :handling_cost_units, - :hazmat_hazard_class, :hazmat_id, :hazmat_item_units, :hazmat_shipping_name, :item_id, - :manufacturer, :manufacturer_addr1, :manufacturer_city, :manufacturer_state, - :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :matrix_item_name_template, - :meta_tag_html, :minimum_quantity_units, :mpn, :nex_tag_category, :no_price_message, - :out_of_stock_message, :page_title, :preferred_stock_level_units, :purchase_description, - :quantity_on_hand_units, :quantity_reorder_units, :related_items_description, - :reorder_point_units, :safety_stock_level_units, :sales_description, :schedule_b_number, - :search_keywords, :serial_numbers, :shipping_cost_units, :shopping_dot_com_category, - :specials_description, :stock_description, :store_description, :store_detailed_description, - :store_display_name, :upc_code, :url_component, :vendor_name, :weight_units + record_refs :alternate_demand_source_item, + :asset_account, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :cogs_account, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :demand_source, + :department, + :dropship_expense_account, + :gain_loss_account, + :income_account, + :interco_cogs_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :planning_item_category, + :preferred_location, + :pricing_group, + :purchase_price_variance_acct, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :secondary_base_unit, + :secondary_consumption_unit, + :secondary_purchase_unit, + :secondary_sale_unit, + :secondary_stock_unit, + :secondary_units_type, + :ship_package, + :soft_descriptor, + :stock_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :supply_lot_sizing_method, + :supply_replenishment_method, + :supply_type, + :tax_schedule, + :units_type, + :vendor + fields :auto_lead_time, + :auto_preferred_stock_level, + :auto_reorder_point, + :available_to_partners, + :average_cost, + :backward_consumption_days, + :conversion_rate, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :costing_method, + :costing_method_display, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :default_return_cost, + :demand_modifier, + :demand_time_fence, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enable_catch_weight, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :expiration_date, + :featured_description, + :fixed_lot_size, + :forward_consumption_days, + :future_horizon, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :invt_classification, + :invt_count_interval, + :is_donation_item, + :is_drop_ship_item, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_store_pickup_allowed, + :is_taxable, + :item_carrier, + :item_id, + :last_invt_count_date, + :last_modified_date, + :last_purchase_price, + :lead_time, + :lower_warning_limit, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :match_bill_to_receipt, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :next_invt_count_date, + :no_price_message, + :offer_support, + :on_hand_value_mli, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :periodic_lot_size_days, + :periodic_lot_size_type, + :preference_criterion, + :preferred_stock_level, + :preferred_stock_level_days, + :preferred_stock_level_units, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :quantity_available, + :quantity_back_ordered, + :quantity_committed, + :quantity_on_hand, + :quantity_on_hand_units, + :quantity_on_order, + :quantity_reorder_units, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :reorder_multiple, + :reorder_point, + :reorder_point_units, + :reschedule_in_days, + :reschedule_out_days, + :round_up_as_component, + :safety_stock_level, + :safety_stock_level_days, + :safety_stock_level_units, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :seasonal_demand, + :serial_numbers, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :supply_time_fence, + :total_value, + :track_landed_cost, + :transfer_price, + :upc_code, + :upper_warning_limit, + :url_component, + :use_bins, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units attr_reader :internal_id attr_accessor :external_id, :search_joins diff --git a/spec/netsuite/records/lot_numbered_inventory_item_spec.rb b/spec/netsuite/records/lot_numbered_inventory_item_spec.rb new file mode 100644 index 000000000..c10821bf3 --- /dev/null +++ b/spec/netsuite/records/lot_numbered_inventory_item_spec.rb @@ -0,0 +1,246 @@ +require 'spec_helper' + +describe NetSuite::Records::LotNumberedInventoryItem do + let(:item) { described_class.new } + + it 'has all the right fields' do + [ + :auto_lead_time, + :auto_preferred_stock_level, + :auto_reorder_point, + :available_to_partners, + :average_cost, + :backward_consumption_days, + :conversion_rate, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :costing_method, + :costing_method_display, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :default_return_cost, + :demand_modifier, + :demand_time_fence, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enable_catch_weight, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :expiration_date, + :featured_description, + :fixed_lot_size, + :forward_consumption_days, + :future_horizon, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :invt_classification, + :invt_count_interval, + :is_donation_item, + :is_drop_ship_item, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_store_pickup_allowed, + :is_taxable, + :item_carrier, + :item_id, + :last_invt_count_date, + :last_modified_date, + :last_purchase_price, + :lead_time, + :lower_warning_limit, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :match_bill_to_receipt, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :next_invt_count_date, + :no_price_message, + :offer_support, + :on_hand_value_mli, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :periodic_lot_size_days, + :periodic_lot_size_type, + :preference_criterion, + :preferred_stock_level, + :preferred_stock_level_days, + :preferred_stock_level_units, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :quantity_available, + :quantity_back_ordered, + :quantity_committed, + :quantity_on_hand, + :quantity_on_hand_units, + :quantity_on_order, + :quantity_reorder_units, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :reorder_multiple, + :reorder_point, + :reorder_point_units, + :reschedule_in_days, + :reschedule_out_days, + :round_up_as_component, + :safety_stock_level, + :safety_stock_level_days, + :safety_stock_level_units, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :seasonal_demand, + :serial_numbers, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :supply_time_fence, + :total_value, + :track_landed_cost, + :transfer_price, + :upc_code, + :upper_warning_limit, + :url_component, + :use_bins, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units, + ].each do |field| + expect(item).to have_field(field) + end + end + + it 'has all the right fields with specific classes' do + { + bin_number_list: NetSuite::Records::BinNumberList, + custom_field_list: NetSuite::Records::CustomFieldList, + item_number_options_list: NetSuite::Records::RecordRefList, + item_ship_method_list: NetSuite::Records::RecordRefList, + item_vendor_list: NetSuite::Records::ItemVendorList, + locations_list: NetSuite::Records::LocationsList, + matrix_option_list: NetSuite::Records::MatrixOptionList, + pricing_matrix: NetSuite::Records::PricingMatrix, + subsidiary_list: NetSuite::Records::RecordRefList, + }.each do |field, klass| + expect(item).to have_field(field, klass) + end + end + + it 'has all the right record refs' do + [ + :alternate_demand_source_item, + :asset_account, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :cogs_account, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferred_revenue_account, + :demand_source, + :department, + :dropship_expense_account, + :gain_loss_account, + :income_account, + :interco_cogs_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :planning_item_category, + :preferred_location, + :pricing_group, + :purchase_price_variance_acct, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :secondary_base_unit, + :secondary_consumption_unit, + :secondary_purchase_unit, + :secondary_sale_unit, + :secondary_stock_unit, + :secondary_units_type, + :ship_package, + :soft_descriptor, + :stock_unit, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :supply_lot_sizing_method, + :supply_replenishment_method, + :supply_type, + :tax_schedule, + :units_type, + :vendor, + ].each do |record_ref| + expect(item).to have_record_ref(record_ref) + end + end +end From 20f1ac3b2379233ac78e322802679b002984258a Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 23 Dec 2021 10:18:25 -0500 Subject: [PATCH 068/114] Update NonInventoryResaleItem fields/record_refs for 2021.2 (#508) A couple were missing for my use case, so I updated them based on 2021.2 The following "fields"/"record refs" were removed as "fields"/"record refs" since they require specialized record classes that haven't been implemented yet: * item_options_list * presentation_item_list * product_feed_list * site_category_list * translations_list I arbitrarily went back 5 years (to version 2016.1) and these were all using specialized types back then, so this doesn't appear to have been a recent change on the NetSuite side of things that might affect users of this gem. --- HISTORY.md | 1 + .../records/non_inventory_resale_item.rb | 176 +++++++++++++++-- .../records/non_inventory_resale_item_spec.rb | 183 +++++++++++++++--- 3 files changed, 316 insertions(+), 44 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index ae2135405..3299ce06b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -10,6 +10,7 @@ * Update ItemVendor record fields/record refs for 2021.1. `vendor` is now a record_ref instead of a field. (#505) * Update InventoryItem record fields/record refs for 2021.2. `member_list` was removed as a field as it doesn't belong to InventoryItem. (#506) * Update LotNumberedInventoryItem record fields/record refs for 2021.2. (#507) +* Update NonInventoryResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#508) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index 25c084aa6..0a939352a 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -9,32 +9,168 @@ class NonInventoryResaleItem actions :get, :get_list, :add, :delete, :search, :upsert, :update - fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, - :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, - :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable, - :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer, - :manufacturer_addr1, :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, - :manufacturer_zip, :matrix_option_list, :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, - :minimum_quantity_units, :mpn, :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, - :on_special, :out_of_stock_behavior, :out_of_stock_message, :overall_quantity_pricing_type, :page_title, - :preference_criterion, :presentation_item_list, :prices_include_tax, :producer, :product_feed_list, - :rate, :related_items_description, :sales_description, :schedule_b_code, :schedule_b_number, :schedule_b_quantity, - :search_keywords, :ship_individually, :shipping_cost, :shipping_cost_units, :shopping_dot_com_category, - :shopzilla_category_id, :show_default_donation_amount, :site_category_list, :sitemap_priority, :soft_descriptor, - :specials_description, :stock_description, :store_description, :store_detailed_description, :store_display_name, - :translations_list, :upc_code, :url_component, :use_marginal_rates, :vsoe_deferral, :vsoe_delivered, - :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + fields :amortization_period, + :available_to_partners, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :generate_accruals, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :is_donation_item, + :is_drop_ship_item, + :is_fulfillable, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_taxable, + :item_carrier, + :item_id, + :last_modified_date, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :preference_criterion, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :residual, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :soft_descriptor, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units - record_refs :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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 + record_refs :amortization_template, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferral_account, + :deferred_revenue_account, + :department, + :dropship_expense_account, + :expense_account, + :income_account, + :interco_expense_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :ship_package, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type, + :vendor field :custom_field_list, CustomFieldList + field :item_ship_method_list, RecordRefList + field :matrix_option_list, MatrixOptionList field :pricing_matrix, PricingMatrix field :subsidiary_list, RecordRefList field :item_vendor_list, ItemVendorList - + # TODO: field :accounting_book_detail_list, ItemAccountingBookDetailList + # TODO: field :hierarchy_versions_list, NonInventoryResaleItemHierarchyVersionsList + # TODO: field :item_options_list, ItemOptionsList + # TODO: field :presentation_item_list, PresentationItemList + # TODO: field :product_feed_list, ProductFeedList + # TODO: field :site_category_list, SiteCategoryList + # TODO: field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/spec/netsuite/records/non_inventory_resale_item_spec.rb b/spec/netsuite/records/non_inventory_resale_item_spec.rb index 2edd5d143..3b0a093b5 100644 --- a/spec/netsuite/records/non_inventory_resale_item_spec.rb +++ b/spec/netsuite/records/non_inventory_resale_item_spec.rb @@ -5,38 +5,173 @@ it 'has the right fields' do [ - :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, :created_date, - :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, - :featured_description, :handling_cost, :handling_cost_units, :include_children, :is_donation_item, :is_fulfillable, - :is_gco_compliant, :is_inactive, :is_online, :is_taxable, :item_id, :last_modified_date, :manufacturer, :manufacturer_addr1, - :manufacturer_city, :manufacturer_state, :manufacturer_tariff, :manufacturer_tax_id, :manufacturer_zip, :matrix_option_list, - :matrix_type, :max_donation_amount, :meta_tag_html, :minimum_quantity, :minimum_quantity_units, :mpn, - :mult_manufacture_addr, :nex_tag_category, :no_price_message, :offer_support, :on_special, :out_of_stock_behavior, - :out_of_stock_message, :overall_quantity_pricing_type, :page_title, :preference_criterion, :presentation_item_list, - :prices_include_tax, :producer, :product_feed_list, :rate, :related_items_description, :sales_description, - :schedule_b_code, :schedule_b_number, :schedule_b_quantity, :search_keywords, :ship_individually, :shipping_cost, - :shipping_cost_units, :shopping_dot_com_category, :shopzilla_category_id, :show_default_donation_amount, - :site_category_list, :sitemap_priority, :soft_descriptor, :specials_description, :stock_description, :store_description, - :store_detailed_description, :store_display_name, :translations_list, :upc_code, :url_component, :use_marginal_rates, - :vsoe_deferral, :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, :weight, :weight_unit, :weight_units + :amortization_period, + :available_to_partners, + :copy_description, + :cost, + :cost_estimate, + :cost_estimate_type, + :cost_estimate_units, + :cost_units, + :country_of_manufacture, + :created_date, + :currency, + :defer_rev_rec, + :direct_revenue_posting, + :display_name, + :dont_show_price, + :enforce_min_qty_internally, + :exclude_from_sitemap, + :featured_description, + :generate_accruals, + :handling_cost, + :handling_cost_units, + :hazmat_hazard_class, + :hazmat_id, + :hazmat_item_units, + :hazmat_item_units_qty, + :hazmat_packing_group, + :hazmat_shipping_name, + :include_children, + :is_donation_item, + :is_drop_ship_item, + :is_fulfillable, + :is_gco_compliant, + :is_hazmat_item, + :is_inactive, + :is_online, + :is_special_order_item, + :is_taxable, + :item_carrier, + :item_id, + :last_modified_date, + :manufacturer, + :manufacturer_addr1, + :manufacturer_city, + :manufacturer_state, + :manufacturer_tariff, + :manufacturer_tax_id, + :manufacturer_zip, + :matrix_item_name_template, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :meta_tag_html, + :minimum_quantity, + :minimum_quantity_units, + :mpn, + :mult_manufacture_addr, + :nex_tag_category, + :no_price_message, + :offer_support, + :on_special, + :out_of_stock_behavior, + :out_of_stock_message, + :overall_quantity_pricing_type, + :page_title, + :preference_criterion, + :prices_include_tax, + :producer, + :purchase_description, + :purchase_order_amount, + :purchase_order_quantity, + :purchase_order_quantity_diff, + :rate, + :receipt_amount, + :receipt_quantity, + :receipt_quantity_diff, + :related_items_description, + :residual, + :sales_description, + :schedule_b_code, + :schedule_b_number, + :schedule_b_quantity, + :search_keywords, + :ship_individually, + :shipping_cost, + :shipping_cost_units, + :shopping_dot_com_category, + :shopzilla_category_id, + :show_default_donation_amount, + :sitemap_priority, + :soft_descriptor, + :specials_description, + :stock_description, + :store_description, + :store_detailed_description, + :store_display_name, + :upc_code, + :url_component, + :use_marginal_rates, + :vendor_name, + :vsoe_deferral, + :vsoe_delivered, + :vsoe_permit_discount, + :vsoe_price, + :vsoe_sop_group, + :weight, + :weight_unit, + :weight_units, ].each do |field| expect(item).to have_field(field) end + end - # TODO there is a probably a more robust way to test this - expect(item.custom_field_list.class).to eq(NetSuite::Records::CustomFieldList) - expect(item.pricing_matrix.class).to eq(NetSuite::Records::PricingMatrix) - expect(item.subsidiary_list.class).to eq(NetSuite::Records::RecordRefList) - expect(item.item_vendor_list.class).to eq(NetSuite::Records::ItemVendorList) - + it 'has all the right fields with specific classes' do + { + custom_field_list: NetSuite::Records::CustomFieldList, + item_ship_method_list: NetSuite::Records::RecordRefList, + matrix_option_list: NetSuite::Records::MatrixOptionList, + pricing_matrix: NetSuite::Records::PricingMatrix, + subsidiary_list: NetSuite::Records::RecordRefList, + item_vendor_list: NetSuite::Records::ItemVendorList, + }.each do |field, klass| + expect(item).to have_field(field, klass) + end end it 'has the right record_refs' do [ - :billing_schedule, :cost_category, :custom_form, :deferred_revenue_account, :department, :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 + :amortization_template, + :bill_exch_rate_variance_acct, + :billing_schedule, + :bill_price_variance_acct, + :bill_qty_variance_acct, + :klass, + :consumption_unit, + :cost_category, + :create_revenue_plans_on, + :custom_form, + :default_item_ship_method, + :deferral_account, + :deferred_revenue_account, + :department, + :dropship_expense_account, + :expense_account, + :income_account, + :interco_expense_account, + :interco_income_account, + :issue_product, + :item_revenue_category, + :location, + :parent, + :pricing_group, + :purchase_tax_code, + :purchase_unit, + :quantity_pricing_schedule, + :revenue_allocation_group, + :revenue_recognition_rule, + :rev_rec_forecast_rule, + :rev_rec_schedule, + :sales_tax_code, + :sale_unit, + :ship_package, + :store_display_image, + :store_display_thumbnail, + :store_item_template, + :tax_schedule, + :units_type, + :vendor, ].each do |record_ref| expect(item).to have_record_ref(record_ref) end From eb4ecd702eeeeba8fde43be9e40d1798345ed3c0 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 30 Dec 2021 12:40:50 -0500 Subject: [PATCH 069/114] Support Attaching Files - Revised (#509) * Add support for attaching Files * Prevent fields from conflicting with other methods on records `Records#type` conflicted with the `search_only_field :type` on `Invoice`, such that when `AttachFile` called `@object.type`, you'd get the search-only field value (often `nil`), rather than the result of `Records#type`. `Records#type` was renamed to `Records#netsuite_type` to avoid such conflicts. Furthermore, I added a check to ensure that future fields and public/protected methods don't conflict. I tried to include private methods too for completeness, but since we want to check up the ancestor tree to see if a method is defined, `search_only_field :print` on `Invoice` conflicted with `Kernel#print` in the ancestor tree. For now I opted to turning a blind eye to conflicts with private methods, however the alternative would be to translate to another method name for `search_only_field :print`, similar to the `class/klass` translation. * Use lower_camelcase for `Records#netsuite_type` For a record like `SalesOrder`, this is expected to return `salesOrder`, at least for the `attach_file` call, which is the only one calling `Records#netsuite_type` currently. * Add to HISTORY.md Co-authored-by: Jordan Dedels --- HISTORY.md | 1 + lib/netsuite.rb | 1 + lib/netsuite/actions/attach_file.rb | 87 +++++++++++++++++++ lib/netsuite/records/invoice.rb | 2 +- lib/netsuite/records/sales_order.rb | 2 +- lib/netsuite/support/actions.rb | 2 + lib/netsuite/support/fields.rb | 2 + lib/netsuite/support/records.rb | 10 ++- spec/netsuite/actions/attach_file_spec.rb | 59 +++++++++++++ spec/netsuite/records/invoice_spec.rb | 29 +++++++ spec/netsuite/records/sales_order_spec.rb | 29 +++++++ spec/netsuite/support/fields_spec.rb | 20 ++++- .../attach/attach_file_to_sales_order.xml | 16 ++++ .../attach_file_to_sales_order_error.xml | 20 +++++ 14 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 lib/netsuite/actions/attach_file.rb create mode 100644 spec/netsuite/actions/attach_file_spec.rb create mode 100644 spec/support/fixtures/attach/attach_file_to_sales_order.xml create mode 100644 spec/support/fixtures/attach/attach_file_to_sales_order_error.xml diff --git a/HISTORY.md b/HISTORY.md index 3299ce06b..6fbf3e88c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -11,6 +11,7 @@ * Update InventoryItem record fields/record refs for 2021.2. `member_list` was removed as a field as it doesn't belong to InventoryItem. (#506) * Update LotNumberedInventoryItem record fields/record refs for 2021.2. (#507) * Update NonInventoryResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#508) +* Add `attach_file` action for Invoice and SalesOrder. (#509) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 4afe36b39..6ac44866b 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -49,6 +49,7 @@ module Support module Actions autoload :Add, 'netsuite/actions/add' + autoload :AttachFile, 'netsuite/actions/attach_file' autoload :Delete, 'netsuite/actions/delete' autoload :DeleteList, 'netsuite/actions/delete_list' autoload :Get, 'netsuite/actions/get' diff --git a/lib/netsuite/actions/attach_file.rb b/lib/netsuite/actions/attach_file.rb new file mode 100644 index 000000000..93f3a5a67 --- /dev/null +++ b/lib/netsuite/actions/attach_file.rb @@ -0,0 +1,87 @@ +module NetSuite + module Actions + class AttachFile + include Support::Requests + + def initialize(object, file) + @object = object + @file = file + end + + private + + def request(credentials = {}) + NetSuite::Configuration.connection({}, credentials).call(:attach, :message => request_body) + end + + # + # + # + # + # + # + # + # + # + + def request_body + { + 'platformCore:attachReference' => { + '@xsi:type' => 'platformCore:AttachBasicReference', + 'platformCore:attachTo' => { + '@internalId' => @object.internal_id, + '@type' => @object.netsuite_type, + '@xsi:type' => 'platformCore:RecordRef' + }, + 'platformCore:attachedRecord' => { + '@internalId' => @file.internal_id, + '@type' => 'file', + '@xsi:type' => 'platformCore:RecordRef' + } + } + } + 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_file(file, credentials = {}) + response = NetSuite::Actions::AttachFile.call([self, file], 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/invoice.rb b/lib/netsuite/records/invoice.rb index 997ed302f..085e0a096 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -9,7 +9,7 @@ class Invoice # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/invoice.html?mode=package - actions :get, :get_deleted, :get_list, :initialize, :add, :update, :delete, :upsert, :upsert_list, :search + actions :attach_file, :get, :get_deleted, :get_list, :initialize, :add, :update, :delete, :upsert, :upsert_list, :search fields :balance, :billing_schedule, :contrib_pct, :created_date, :currency_name, diff --git a/lib/netsuite/records/sales_order.rb b/lib/netsuite/records/sales_order.rb index 8b6059e47..2ef43643b 100644 --- a/lib/netsuite/records/sales_order.rb +++ b/lib/netsuite/records/sales_order.rb @@ -7,7 +7,7 @@ class SalesOrder include Support::Actions include Namespaces::TranSales - actions :get, :get_list, :add, :initialize, :delete, :update, :upsert, :upsert_list, :search + actions :attach_file, :get, :get_list, :add, :initialize, :delete, :update, :upsert, :upsert_list, :search fields :alt_handling_cost, :alt_shipping_cost, :amount_paid, :amount_remaining, :auto_apply, :balance, :bill_address, :cc_approved, :contrib_pct, :created_date, :currency_name, :deferred_revenue, :discount_rate, :email, :end_date, diff --git a/lib/netsuite/support/actions.rb b/lib/netsuite/support/actions.rb index 19d62c552..a7b9b3fc2 100644 --- a/lib/netsuite/support/actions.rb +++ b/lib/netsuite/support/actions.rb @@ -18,6 +18,8 @@ def actions(*args) def action(name) case name + when :attach_file + self.send(:include, NetSuite::Actions::AttachFile::Support) when :get self.send(:include, NetSuite::Actions::Get::Support) when :get_all diff --git a/lib/netsuite/support/fields.rb b/lib/netsuite/support/fields.rb index 56adb55dc..af478e541 100644 --- a/lib/netsuite/support/fields.rb +++ b/lib/netsuite/support/fields.rb @@ -22,6 +22,8 @@ def fields(*args) def field(name, klass = nil) name_sym = name.to_sym raise "#{name} already defined on #{self.name}" if fields.include?(name_sym) + raise "#{name} conflicts with a method defined on #{self.name}" if method_defined?(name_sym) + fields << name_sym if klass define_method(name_sym) do diff --git a/lib/netsuite/support/records.rb b/lib/netsuite/support/records.rb index 447755f55..b6f790063 100644 --- a/lib/netsuite/support/records.rb +++ b/lib/netsuite/support/records.rb @@ -49,7 +49,15 @@ def to_attributes!(hash, kname, v) end def record_type - "#{record_namespace}:#{self.class.to_s.split('::').last}" + "#{record_namespace}:#{record_type_without_namespace}" + end + + def netsuite_type + record_type_without_namespace.lower_camelcase + end + + def record_type_without_namespace + "#{self.class.to_s.split('::').last}" end def refresh(credentials = {}) diff --git a/spec/netsuite/actions/attach_file_spec.rb b/spec/netsuite/actions/attach_file_spec.rb new file mode 100644 index 000000000..3f2836ed3 --- /dev/null +++ b/spec/netsuite/actions/attach_file_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe NetSuite::Actions::AttachFile do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + + let(:sales_order) { NetSuite::Records::SalesOrder.new(internal_id: 999) } + let(:file) { double('file', internal_id: 111) } + let(:message) do + { + 'platformCore:attachReference' => { + '@xsi:type' => 'platformCore:AttachBasicReference', + 'platformCore:attachTo' => { + '@internalId' => sales_order.internal_id, + '@type' => 'salesOrder', + '@xsi:type' => 'platformCore:RecordRef' + }, + 'platformCore:attachedRecord' => { + '@internalId' => file.internal_id, + '@type' => 'file', + '@xsi:type' => 'platformCore:RecordRef' + } + } + } + end + + before do + savon.expects(:attach).with(:message => message).returns(envelope) + end + + context 'when successful' do + let(:envelope) { File.read('spec/support/fixtures/attach/attach_file_to_sales_order.xml') } + + it 'returns a valid Response object' do + response = NetSuite::Actions::AttachFile.call([sales_order, file]) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end + end + + context 'when not successful' do + let(:envelope) { File.read('spec/support/fixtures/attach/attach_file_to_sales_order_error.xml') } + + it 'provides an error method on the object with details about the error' do + sales_order.attach_file(file) + error = sales_order.errors.first + + expect(error).to be_kind_of(NetSuite::Error) + expect(error.type).to eq('ERROR') + expect(error.code).to eq('INVALID') + expect(error.message).to eq('Invalid request.') + end + + it 'provides an error method on the response' do + response = NetSuite::Actions::AttachFile.call([sales_order, file]) + expect(response.errors.first).to be_kind_of(NetSuite::Error) + end + end +end diff --git a/spec/netsuite/records/invoice_spec.rb b/spec/netsuite/records/invoice_spec.rb index 10753ce74..4156bc6ad 100644 --- a/spec/netsuite/records/invoice_spec.rb +++ b/spec/netsuite/records/invoice_spec.rb @@ -392,6 +392,35 @@ end end + describe '#attach_file' do + let(:test_data) { { :email => 'test@example.com', :fax => '1234567890' } } + let(:file) { double('file') } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + invoice = NetSuite::Records::Invoice.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([invoice, file], {}). + and_return(response) + expect(invoice.attach_file(file)).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + invoice = NetSuite::Records::Invoice.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([invoice, file], {}). + and_return(response) + expect(invoice.attach_file(file)).to be_falsey + end + end + end + describe '#delete' do context 'when the response is successful' do let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } diff --git a/spec/netsuite/records/sales_order_spec.rb b/spec/netsuite/records/sales_order_spec.rb index 37897a7d4..4c38c4c2e 100644 --- a/spec/netsuite/records/sales_order_spec.rb +++ b/spec/netsuite/records/sales_order_spec.rb @@ -174,6 +174,35 @@ end end + describe '#attach_file' do + let(:test_data) { { :email => 'test@example.com', :fax => '1234567890' } } + let(:file) { double('file') } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + sales_order = NetSuite::Records::SalesOrder.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([sales_order, file], {}). + and_return(response) + expect(sales_order.attach_file(file)).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + sales_order = NetSuite::Records::SalesOrder.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([sales_order, file], {}). + and_return(response) + expect(sales_order.attach_file(file)).to be_falsey + end + end + end + describe '#delete' do let(:test_data) { { :internal_id => '1' } } diff --git a/spec/netsuite/support/fields_spec.rb b/spec/netsuite/support/fields_spec.rb index bffe8ba5e..f888f4737 100644 --- a/spec/netsuite/support/fields_spec.rb +++ b/spec/netsuite/support/fields_spec.rb @@ -1,12 +1,13 @@ require 'spec_helper' describe NetSuite::Support::Fields do - DummyRecord = Class.new.send(:include, NetSuite::Support::Fields) - let(:klass) { DummyRecord } + let(:klass) do + Class.new do + include NetSuite::Support::Fields + end + end let(:instance) { klass.new } - before { klass.fields.clear } - describe '.fields' do context 'with arguments' do it 'calls .field with each argument passed to it' do @@ -34,10 +35,21 @@ end it 'errors when already a field' do + DummyRecord = klass + klass.field :one expect { klass.field :one }.to raise_error('one already defined on DummyRecord') end + + it 'errors when conflicting with a public method' do + DummyRecordWithMethod = Class.new(klass) do + def existing_method + end + end + + expect { DummyRecordWithMethod.field :existing_method }.to raise_error('existing_method conflicts with a method defined on DummyRecordWithMethod') + end end describe '.read_only_fields' do diff --git a/spec/support/fixtures/attach/attach_file_to_sales_order.xml b/spec/support/fixtures/attach/attach_file_to_sales_order.xml new file mode 100644 index 000000000..aabe25af6 --- /dev/null +++ b/spec/support/fixtures/attach/attach_file_to_sales_order.xml @@ -0,0 +1,16 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + + + + + + diff --git a/spec/support/fixtures/attach/attach_file_to_sales_order_error.xml b/spec/support/fixtures/attach/attach_file_to_sales_order_error.xml new file mode 100644 index 000000000..4be35e6ef --- /dev/null +++ b/spec/support/fixtures/attach/attach_file_to_sales_order_error.xml @@ -0,0 +1,20 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + + + INVALID + Invalid request. + + + + + + From 9f1000535d62045e1fcb6220192840c943eaba57 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 4 Jan 2022 22:28:45 -0500 Subject: [PATCH 070/114] Document uploading/attaching files in Readme (#510) --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 7dddf95dc..4364f3622 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ - [Token based Authentication](#token-based-authentication) - [Usage](#usage) - [CRUD Operations](#crud-operations) + - [Uploading/Attaching Files](#uploadingattaching-files) - [Custom Records & Fields](#custom-records--fields) - [Searching](#searching) - [Non-standard Operations](#non-standard-operations) @@ -238,6 +239,19 @@ options = NetSuite::Records::BaseRefList.get_select_value( options.base_refs.map(&:name) ``` +## Uploading/Attaching Files + +```ruby +file = NetSuite::Records::File.new( + content: Base64.encode64(File.read('/path/to/file')), + name: 'Invoice.pdf', +) +file.add + +invoice = NetSuite::Records::Invoice.get(internal_id: 1) +invoice.attach_file(NetSuite::Records::RecordRef.new(internal_id: file.internal_id)) +``` + ## Custom Records & Fields ```ruby From 60a8d6ba1e0d30cff472b179d39617b436ec5c45 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 20 Jan 2022 20:12:01 -0500 Subject: [PATCH 071/114] Move definition of `search_joins` attribute from records to search action (#511) Previously it was up to each record to define this attribute, if it offered the search action. This created scenarios where a record like [`Bin`](https://github.com/NetSweet/netsuite/blob/9f1000535d62045e1fcb6220192840c943eaba57/lib/netsuite/records/bin.rb) offered the `search` action, but didn't define the `search_joins` attribute and therefore searching bins would error: ``` undefined method `search_joins=' for #"WIP-Fabric"}> (NoMethodError) ``` Due to `SearchResult` assuming the record had such an attribute: https://github.com/NetSweet/netsuite/blob/9f1000535d62045e1fcb6220192840c943eaba57/lib/netsuite/support/search_result.rb#L112 Now adding the `search` action to a record automatically adds the necessary `search_joins` attribute. The attribute was previously defined on `AssemblyComponent`, `SerializedInventoryItemLocation`, and `WorkOrderItem`, however none of those support actions at all, let alone the `search` action. They're all records for sublist items. I suspect the attribute was erroneously introduced in the first place as a result of copy/pasting to create the record. --- HISTORY.md | 2 +- lib/netsuite/actions/search.rb | 2 ++ lib/netsuite/records/account.rb | 1 - lib/netsuite/records/accounting_period.rb | 2 +- lib/netsuite/records/assembly_component.rb | 2 -- lib/netsuite/records/assembly_item.rb | 1 - lib/netsuite/records/assembly_unbuild.rb | 1 - lib/netsuite/records/cash_refund.rb | 1 - lib/netsuite/records/cash_sale.rb | 1 - lib/netsuite/records/contact.rb | 1 - lib/netsuite/records/credit_memo.rb | 1 - lib/netsuite/records/currency_rate.rb | 1 - lib/netsuite/records/custom_record.rb | 1 - lib/netsuite/records/customer.rb | 1 - lib/netsuite/records/customer_deposit.rb | 1 - lib/netsuite/records/customer_payment.rb | 1 - lib/netsuite/records/customer_refund.rb | 1 - lib/netsuite/records/deposit.rb | 1 - lib/netsuite/records/deposit_application.rb | 1 - lib/netsuite/records/estimate.rb | 1 - lib/netsuite/records/inbound_shipment.rb | 1 - lib/netsuite/records/inventory_item.rb | 2 +- lib/netsuite/records/inventory_number.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/job.rb | 1 - lib/netsuite/records/location.rb | 1 - lib/netsuite/records/lot_numbered_inventory_item.rb | 2 +- lib/netsuite/records/non_inventory_sale_item.rb | 1 - lib/netsuite/records/opportunity.rb | 1 - lib/netsuite/records/payroll_item.rb | 1 - lib/netsuite/records/purchase_order.rb | 1 - lib/netsuite/records/sales_order.rb | 1 - lib/netsuite/records/serialized_inventory_item_location.rb | 1 - lib/netsuite/records/service_sale_item.rb | 1 - lib/netsuite/records/subsidiary.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/work_order.rb | 1 - lib/netsuite/records/work_order_item.rb | 1 - 42 files changed, 6 insertions(+), 42 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 6fbf3e88c..388831cff 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,7 +15,7 @@ ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) -* +* Moved definition of `search_joins` attribute from records to search action. The attribute was removed for AssemblyComponent, SerializedInventoryItemLocation, and WorkOrderItem as they don't offer the search action. (#511) ## 0.8.10 diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index e5f8420dd..5d14f18b3 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -235,6 +235,8 @@ def success? module Support def self.included(base) base.extend(ClassMethods) + + attr_accessor :search_joins end module ClassMethods diff --git a/lib/netsuite/records/account.rb b/lib/netsuite/records/account.rb index b749f9596..f69f4b855 100644 --- a/lib/netsuite/records/account.rb +++ b/lib/netsuite/records/account.rb @@ -18,7 +18,6 @@ class Account 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) diff --git a/lib/netsuite/records/accounting_period.rb b/lib/netsuite/records/accounting_period.rb index 74a240a15..b3546974a 100644 --- a/lib/netsuite/records/accounting_period.rb +++ b/lib/netsuite/records/accounting_period.rb @@ -13,7 +13,7 @@ class AccountingPeriod record_refs :parent attr_reader :internal_id - attr_accessor :external_id, :search_joins + attr_accessor :external_id def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) diff --git a/lib/netsuite/records/assembly_component.rb b/lib/netsuite/records/assembly_component.rb index d8ab8ca8f..74fce5641 100644 --- a/lib/netsuite/records/assembly_component.rb +++ b/lib/netsuite/records/assembly_component.rb @@ -15,7 +15,6 @@ class AssemblyComponent 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) @@ -25,4 +24,3 @@ def initialize(attributes = {}) end end end - diff --git a/lib/netsuite/records/assembly_item.rb b/lib/netsuite/records/assembly_item.rb index e259617dc..e7cce6372 100644 --- a/lib/netsuite/records/assembly_item.rb +++ b/lib/netsuite/records/assembly_item.rb @@ -50,7 +50,6 @@ class AssemblyItem 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) diff --git a/lib/netsuite/records/assembly_unbuild.rb b/lib/netsuite/records/assembly_unbuild.rb index 763cb0d73..10ed66df0 100644 --- a/lib/netsuite/records/assembly_unbuild.rb +++ b/lib/netsuite/records/assembly_unbuild.rb @@ -26,7 +26,6 @@ class AssemblyUnbuild 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) diff --git a/lib/netsuite/records/cash_refund.rb b/lib/netsuite/records/cash_refund.rb index a4c9b46ab..46eb02fc8 100644 --- a/lib/netsuite/records/cash_refund.rb +++ b/lib/netsuite/records/cash_refund.rb @@ -115,7 +115,6 @@ class CashRefund 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) diff --git a/lib/netsuite/records/cash_sale.rb b/lib/netsuite/records/cash_sale.rb index 97fe2d042..04d062199 100644 --- a/lib/netsuite/records/cash_sale.rb +++ b/lib/netsuite/records/cash_sale.rb @@ -36,7 +36,6 @@ class CashSale 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) diff --git a/lib/netsuite/records/contact.rb b/lib/netsuite/records/contact.rb index c107311ca..5dc01b3f4 100644 --- a/lib/netsuite/records/contact.rb +++ b/lib/netsuite/records/contact.rb @@ -24,7 +24,6 @@ class Contact 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) diff --git a/lib/netsuite/records/credit_memo.rb b/lib/netsuite/records/credit_memo.rb index d8134113f..704a2ed54 100644 --- a/lib/netsuite/records/credit_memo.rb +++ b/lib/netsuite/records/credit_memo.rb @@ -38,7 +38,6 @@ class CreditMemo 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) diff --git a/lib/netsuite/records/currency_rate.rb b/lib/netsuite/records/currency_rate.rb index 6ed7c962d..85163e93d 100644 --- a/lib/netsuite/records/currency_rate.rb +++ b/lib/netsuite/records/currency_rate.rb @@ -21,7 +21,6 @@ class CurrencyRate 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) diff --git a/lib/netsuite/records/custom_record.rb b/lib/netsuite/records/custom_record.rb index 60fd4f1de..4a8080407 100644 --- a/lib/netsuite/records/custom_record.rb +++ b/lib/netsuite/records/custom_record.rb @@ -22,7 +22,6 @@ class CustomRecord 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) diff --git a/lib/netsuite/records/customer.rb b/lib/netsuite/records/customer.rb index 055088713..709b0b799 100644 --- a/lib/netsuite/records/customer.rb +++ b/lib/netsuite/records/customer.rb @@ -44,7 +44,6 @@ class Customer 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) diff --git a/lib/netsuite/records/customer_deposit.rb b/lib/netsuite/records/customer_deposit.rb index 089627b35..3489cd9b8 100644 --- a/lib/netsuite/records/customer_deposit.rb +++ b/lib/netsuite/records/customer_deposit.rb @@ -29,7 +29,6 @@ class CustomerDeposit 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) diff --git a/lib/netsuite/records/customer_payment.rb b/lib/netsuite/records/customer_payment.rb index e2fef1996..a8e96f8d8 100644 --- a/lib/netsuite/records/customer_payment.rb +++ b/lib/netsuite/records/customer_payment.rb @@ -28,7 +28,6 @@ class CustomerPayment 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) diff --git a/lib/netsuite/records/customer_refund.rb b/lib/netsuite/records/customer_refund.rb index 4f6398e40..e96bcd9dc 100644 --- a/lib/netsuite/records/customer_refund.rb +++ b/lib/netsuite/records/customer_refund.rb @@ -24,7 +24,6 @@ class CustomerRefund 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) diff --git a/lib/netsuite/records/deposit.rb b/lib/netsuite/records/deposit.rb index 9f1eec3f8..9110dc77a 100644 --- a/lib/netsuite/records/deposit.rb +++ b/lib/netsuite/records/deposit.rb @@ -20,7 +20,6 @@ class Deposit 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) diff --git a/lib/netsuite/records/deposit_application.rb b/lib/netsuite/records/deposit_application.rb index 536778848..2dc67b500 100644 --- a/lib/netsuite/records/deposit_application.rb +++ b/lib/netsuite/records/deposit_application.rb @@ -37,7 +37,6 @@ class DepositApplication 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) diff --git a/lib/netsuite/records/estimate.rb b/lib/netsuite/records/estimate.rb index 41e11631b..426714b80 100644 --- a/lib/netsuite/records/estimate.rb +++ b/lib/netsuite/records/estimate.rb @@ -111,7 +111,6 @@ class Estimate 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) diff --git a/lib/netsuite/records/inbound_shipment.rb b/lib/netsuite/records/inbound_shipment.rb index 380fbc7db..b636dc806 100644 --- a/lib/netsuite/records/inbound_shipment.rb +++ b/lib/netsuite/records/inbound_shipment.rb @@ -20,7 +20,6 @@ class InboundShipment 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) diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index a0c2cda17..d16103d9e 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -325,7 +325,7 @@ class InventoryItem # TODO: :translations_list, TranslationList attr_reader :internal_id - attr_accessor :external_id, :search_joins + attr_accessor :external_id def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) diff --git a/lib/netsuite/records/inventory_number.rb b/lib/netsuite/records/inventory_number.rb index 83bf2e824..0e0a84377 100644 --- a/lib/netsuite/records/inventory_number.rb +++ b/lib/netsuite/records/inventory_number.rb @@ -19,7 +19,6 @@ class InventoryNumber 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) diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 085e0a096..a5c4e7213 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -141,7 +141,6 @@ class Invoice 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) diff --git a/lib/netsuite/records/item_fulfillment.rb b/lib/netsuite/records/item_fulfillment.rb index aa37b4546..b903c7f23 100644 --- a/lib/netsuite/records/item_fulfillment.rb +++ b/lib/netsuite/records/item_fulfillment.rb @@ -30,7 +30,6 @@ class ItemFulfillment 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) diff --git a/lib/netsuite/records/item_receipt.rb b/lib/netsuite/records/item_receipt.rb index 798b2b70c..5d92c65df 100644 --- a/lib/netsuite/records/item_receipt.rb +++ b/lib/netsuite/records/item_receipt.rb @@ -26,7 +26,6 @@ class ItemReceipt 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) diff --git a/lib/netsuite/records/job.rb b/lib/netsuite/records/job.rb index dcfb5e59f..f56da433d 100644 --- a/lib/netsuite/records/job.rb +++ b/lib/netsuite/records/job.rb @@ -29,7 +29,6 @@ class Job 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) diff --git a/lib/netsuite/records/location.rb b/lib/netsuite/records/location.rb index 3212dad9d..b7b3424d5 100644 --- a/lib/netsuite/records/location.rb +++ b/lib/netsuite/records/location.rb @@ -28,7 +28,6 @@ class Location 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) diff --git a/lib/netsuite/records/lot_numbered_inventory_item.rb b/lib/netsuite/records/lot_numbered_inventory_item.rb index 81103f88d..e5e14c301 100644 --- a/lib/netsuite/records/lot_numbered_inventory_item.rb +++ b/lib/netsuite/records/lot_numbered_inventory_item.rb @@ -243,7 +243,7 @@ class LotNumberedInventoryItem :weight_units attr_reader :internal_id - attr_accessor :external_id, :search_joins + attr_accessor :external_id def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index 2d786a7d8..d274c2116 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -150,7 +150,6 @@ class NonInventorySaleItem 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) diff --git a/lib/netsuite/records/opportunity.rb b/lib/netsuite/records/opportunity.rb index 7da4f0aef..3162b81bc 100644 --- a/lib/netsuite/records/opportunity.rb +++ b/lib/netsuite/records/opportunity.rb @@ -33,7 +33,6 @@ class Opportunity 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) diff --git a/lib/netsuite/records/payroll_item.rb b/lib/netsuite/records/payroll_item.rb index 0e00b148b..3f49af3cf 100644 --- a/lib/netsuite/records/payroll_item.rb +++ b/lib/netsuite/records/payroll_item.rb @@ -17,7 +17,6 @@ class PayrollItem 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) diff --git a/lib/netsuite/records/purchase_order.rb b/lib/netsuite/records/purchase_order.rb index fe5c0d12d..7a0a55aaf 100644 --- a/lib/netsuite/records/purchase_order.rb +++ b/lib/netsuite/records/purchase_order.rb @@ -31,7 +31,6 @@ class PurchaseOrder 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) diff --git a/lib/netsuite/records/sales_order.rb b/lib/netsuite/records/sales_order.rb index 2ef43643b..b586af0e5 100644 --- a/lib/netsuite/records/sales_order.rb +++ b/lib/netsuite/records/sales_order.rb @@ -43,7 +43,6 @@ class SalesOrder 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) diff --git a/lib/netsuite/records/serialized_inventory_item_location.rb b/lib/netsuite/records/serialized_inventory_item_location.rb index 1ce57e3b0..e5ff61cf0 100644 --- a/lib/netsuite/records/serialized_inventory_item_location.rb +++ b/lib/netsuite/records/serialized_inventory_item_location.rb @@ -24,7 +24,6 @@ class SerializedInventoryItemLocation 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) diff --git a/lib/netsuite/records/service_sale_item.rb b/lib/netsuite/records/service_sale_item.rb index 5a1b361f4..0bb8e6fb2 100644 --- a/lib/netsuite/records/service_sale_item.rb +++ b/lib/netsuite/records/service_sale_item.rb @@ -34,7 +34,6 @@ class ServiceSaleItem 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) diff --git a/lib/netsuite/records/subsidiary.rb b/lib/netsuite/records/subsidiary.rb index b35c4a407..b85b47ba4 100644 --- a/lib/netsuite/records/subsidiary.rb +++ b/lib/netsuite/records/subsidiary.rb @@ -27,7 +27,6 @@ class 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) diff --git a/lib/netsuite/records/transfer_order.rb b/lib/netsuite/records/transfer_order.rb index db43ce630..35aae2a94 100644 --- a/lib/netsuite/records/transfer_order.rb +++ b/lib/netsuite/records/transfer_order.rb @@ -24,7 +24,6 @@ class TransferOrder 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) diff --git a/lib/netsuite/records/vendor.rb b/lib/netsuite/records/vendor.rb index caff2fbf7..93277fc6b 100644 --- a/lib/netsuite/records/vendor.rb +++ b/lib/netsuite/records/vendor.rb @@ -35,7 +35,6 @@ class Vendor 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) diff --git a/lib/netsuite/records/vendor_bill.rb b/lib/netsuite/records/vendor_bill.rb index cebd7de7e..131f42d3f 100644 --- a/lib/netsuite/records/vendor_bill.rb +++ b/lib/netsuite/records/vendor_bill.rb @@ -25,7 +25,6 @@ class VendorBill 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) diff --git a/lib/netsuite/records/work_order.rb b/lib/netsuite/records/work_order.rb index 7807047e7..8f62250f0 100644 --- a/lib/netsuite/records/work_order.rb +++ b/lib/netsuite/records/work_order.rb @@ -26,7 +26,6 @@ class WorkOrder 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) diff --git a/lib/netsuite/records/work_order_item.rb b/lib/netsuite/records/work_order_item.rb index 0a8e5c7be..9da922a52 100644 --- a/lib/netsuite/records/work_order_item.rb +++ b/lib/netsuite/records/work_order_item.rb @@ -19,7 +19,6 @@ class WorkOrderItem 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) From f8566d6b3458864cdf030f7078d4059f1c51df6d Mon Sep 17 00:00:00 2001 From: Tim Barkley Date: Thu, 27 Jan 2022 11:45:28 -0500 Subject: [PATCH 072/114] add-record-ItemOptionCustomField (#512) Adding class for ItemOptionCustomField --- 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 6ac44866b..acc7cb6f8 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -201,6 +201,7 @@ module Records autoload :ItemGroup, 'netsuite/records/item_group' autoload :ItemMember, 'netsuite/records/item_member' autoload :ItemMemberList, 'netsuite/records/item_member_list' + autoload :ItemOptionCustomField, 'netsuite/records/item_option_custom_field' autoload :ItemReceipt, 'netsuite/records/item_receipt' autoload :ItemReceiptItemList, 'netsuite/records/item_receipt_item_list' autoload :ItemReceiptItem, 'netsuite/records/item_receipt_item' 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..cbe5dec0f --- /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 From 38cb8e91fc48ec3ebd4a1905419ebbf71e203e37 Mon Sep 17 00:00:00 2001 From: Tim Barkley Date: Thu, 27 Jan 2022 20:55:16 -0500 Subject: [PATCH 073/114] update-changelog-for-PR-512 (#513) Add change to HISTORY.md --- HISTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.md b/HISTORY.md index 388831cff..e02f83c44 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -12,6 +12,7 @@ * Update LotNumberedInventoryItem record fields/record refs for 2021.2. (#507) * Update NonInventoryResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#508) * Add `attach_file` action for Invoice and SalesOrder. (#509) +* Add ItemOptionCustomField recrd (#512) ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) From f1a7968d933068bf1b38a86e2b225c6594abef76 Mon Sep 17 00:00:00 2001 From: Eric Jensen Date: Thu, 3 Feb 2022 15:06:24 -0500 Subject: [PATCH 074/114] add httpclient timeout to backoff since it is the most preferred by httpi (#514) --- lib/netsuite/utilities.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index c8a1ca9de..9e25243a1 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -103,6 +103,7 @@ def backoff(options = {}) exceptions_to_retry << OpenSSL::SSL::SSLErrorWaitReadable if defined?(OpenSSL::SSL::SSLErrorWaitReadable) # depends on the http library chosen + exceptions_to_retry << HTTPClient::TimeoutError if defined?(HTTPClient::TimeoutError) exceptions_to_retry << Excon::Error::Timeout if defined?(Excon::Error::Timeout) exceptions_to_retry << Excon::Error::Socket if defined?(Excon::Error::Socket) From b866e731b81577b7e5326cce8e177eef42f7e1b7 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Wed, 9 Feb 2022 12:00:30 -0500 Subject: [PATCH 075/114] Consider externalId in search criteria when using RecordRef as value (#517) Given a criteria like: ```ruby { field: 'company', operator: 'anyOf', value: [ NetSuite::Records::RecordRef.new(external_id: "abc"), NetSuite::Records::RecordRef.new(external_id: "xyz"), ], } ``` The gem was never passing that external ID to NetSuite for the result, so you'd get a `INVALID_KEY_OR_REF` error as the XML line ended up looking like: ```xml ``` Compared to the same line if you defined your `RecordRef` with an internal ID: ```xml ``` Now that we pass the external ID too, that same line looks like: ```xml ``` If your `RecordRef` has both internal and external IDs, it seems safe to pass both and NetSuite seems to treat the internal ID as superseding the external ID. --- HISTORY.md | 1 + lib/netsuite/actions/search.rb | 23 ++- spec/netsuite/actions/search_spec.rb | 181 ++++++++++++++++++ .../fixtures/search/basic_search_contact.xml | 39 ++++ 4 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 spec/support/fixtures/search/basic_search_contact.xml diff --git a/HISTORY.md b/HISTORY.md index e02f83c44..cba4b00f4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -17,6 +17,7 @@ ### Fixed * Fix "undefined method `[]` for #" when adding File (#495) * Moved definition of `search_joins` attribute from records to search action. The attribute was removed for AssemblyComponent, SerializedInventoryItemLocation, and WorkOrderItem as they don't offer the search action. (#511) +* Consider externalId in search criteria when using RecordRef as value (#517) ## 0.8.10 diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index 5d14f18b3..450313775 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -144,12 +144,23 @@ def request_body h[element_name] = { '@operator' => condition[:operator], '@xsi:type' => 'platformCore:SearchMultiSelectField', - "platformCore:searchValue" => { - :content! => condition[:value].map(&:to_record), - '@internalId' => condition[:value].map(&:internal_id), - '@xsi:type' => 'platformCore:RecordRef', - '@type' => 'account' - } + "platformCore:searchValue" => condition[:value].map do |value| + search_value = { + :content! => value.to_record, + '@xsi:type' => 'platformCore:RecordRef', + '@type' => 'account' + } + + if value.internal_id + search_value['@internalId'] = value.internal_id + end + + if value.external_id + search_value['@externalId'] = value.external_id + end + + search_value + end } elsif condition[:value].is_a?(Array) && condition[:type] == 'SearchDateField' # date ranges are handled via searchValue (start range) and searchValue2 (end range) diff --git a/spec/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index b8babbfbd..2cb51f5d5 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -201,6 +201,187 @@ end context "basic search" do + it "should handle a basic search matching on RecordRef using internalId" do + response = File.read('spec/support/fixtures/search/basic_search_contact.xml') + savon.expects(:search) + .with(message: { + "searchRecord" => { + :content! => { + "listRel:basic" => { + "platformCommon:company" => { + "@operator" => "anyOf", + "@xsi:type" => "platformCore:SearchMultiSelectField", + "platformCore:searchValue" => [ + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@internalId" => 7497, + }, + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@internalId" => 7270, + }, + ], + }, + }, + }, + "@xsi:type" => "listRel:ContactSearch", + }, + }).returns(response) + + search = NetSuite::Records::Contact.search( + basic: [{ + field: 'company', + operator: 'anyOf', + value: [ + NetSuite::Records::RecordRef.new(internal_id: 7497), + NetSuite::Records::RecordRef.new(internal_id: 7270), + ], + }], + ) + + expect(search.results.size).to eq(1) + end + + it "should handle a basic search matching on RecordRef using externalId" do + response = File.read('spec/support/fixtures/search/basic_search_contact.xml') + savon.expects(:search) + .with(message: { + "searchRecord" => { + :content! => { + "listRel:basic" => { + "platformCommon:company" => { + "@operator" => "anyOf", + "@xsi:type" => "platformCore:SearchMultiSelectField", + "platformCore:searchValue" => [ + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@externalId" => "external_abc", + }, + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@externalId" => "external_xyz", + }, + ], + }, + }, + }, + "@xsi:type" => "listRel:ContactSearch", + }, + }).returns(response) + + search = NetSuite::Records::Contact.search( + basic: [{ + field: 'company', + operator: 'anyOf', + value: [ + NetSuite::Records::RecordRef.new(external_id: "external_abc"), + NetSuite::Records::RecordRef.new(external_id: "external_xyz"), + ], + }], + ) + + expect(search.results.size).to eq(1) + end + + it "should handle a basic search matching on RecordRef using mix of internalId and externalId" do + response = File.read('spec/support/fixtures/search/basic_search_contact.xml') + savon.expects(:search) + .with(message: { + "searchRecord" => { + :content! => { + "listRel:basic" => { + "platformCommon:company" => { + "@operator" => "anyOf", + "@xsi:type" => "platformCore:SearchMultiSelectField", + "platformCore:searchValue" => [ + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@internalId" => 7497, + }, + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@externalId" => "external_xyz", + }, + ], + }, + }, + }, + "@xsi:type" => "listRel:ContactSearch", + }, + }).returns(response) + + search = NetSuite::Records::Contact.search( + basic: [{ + field: 'company', + operator: 'anyOf', + value: [ + NetSuite::Records::RecordRef.new(internal_id: 7497), + NetSuite::Records::RecordRef.new(external_id: "external_xyz"), + ], + }], + ) + + expect(search.results.size).to eq(1) + end + + it "should handle a basic search matching on RecordRef using both internalId and externalId" do + response = File.read('spec/support/fixtures/search/basic_search_contact.xml') + savon.expects(:search) + .with(message: { + "searchRecord" => { + :content! => { + "listRel:basic" => { + "platformCommon:company" => { + "@operator" => "anyOf", + "@xsi:type" => "platformCore:SearchMultiSelectField", + "platformCore:searchValue" => [ + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@internalId" => 7497, + "@externalId" => "external_abc", + }, + { + :content! => {}, + "@xsi:type" => "platformCore:RecordRef", + "@type" => "account", + "@externalId" => 7270, + }, + ], + }, + }, + }, + "@xsi:type" => "listRel:ContactSearch", + }, + }).returns(response) + + search = NetSuite::Records::Contact.search( + basic: [{ + field: 'company', + operator: 'anyOf', + value: [ + NetSuite::Records::RecordRef.new(internal_id: 7497, external_id: "external_abc"), + NetSuite::Records::RecordRef.new(external_id: 7270), + ], + }], + ) + + expect(search.results.size).to eq(1) + end + skip "should handle searching basic fields" skip "should handle searching with joined fields" end diff --git a/spec/support/fixtures/search/basic_search_contact.xml b/spec/support/fixtures/search/basic_search_contact.xml new file mode 100644 index 000000000..f8a675591 --- /dev/null +++ b/spec/support/fixtures/search/basic_search_contact.xml @@ -0,0 +1,39 @@ + + + + WEBSERVICES_123456 + + + + + + + 1 + 1000 + 1 + 1 + WEBSERVICES_123456 + + + Mary + + 1357 What a Company + + President/CEO + (123) 555-1234 + ***FILTERED*** + 123 Main St + false + false + + Awesome Company + + _softOptOut + 2021-03-03T08:26:56.000-08:00 + 2021-07-07T09:49:51.000-07:00 + + + + + + From 3838e11157799bd61c9178c47d14ff03b07e7bb2 Mon Sep 17 00:00:00 2001 From: Fabien Sebban Date: Wed, 9 Feb 2022 18:01:02 +0100 Subject: [PATCH 076/114] Support translations records (#516) * translation record * use translation record where needed * tests * after review - non-dynamic translation's fields --- lib/netsuite.rb | 2 ++ lib/netsuite/records/custom_record.rb | 1 + lib/netsuite/records/description_item.rb | 2 +- lib/netsuite/records/inventory_item.rb | 2 +- lib/netsuite/records/item_group.rb | 2 +- lib/netsuite/records/kit_item.rb | 2 +- .../records/lot_numbered_inventory_item.rb | 2 +- .../records/non_inventory_resale_item.rb | 2 +- .../records/non_inventory_sale_item.rb | 2 +- .../records/other_charge_sale_item.rb | 2 +- lib/netsuite/records/payment_item.rb | 2 +- .../records/serialized_inventory_item.rb | 2 +- lib/netsuite/records/service_resale_item.rb | 2 +- lib/netsuite/records/subtotal_item.rb | 2 +- lib/netsuite/records/translation.rb | 17 ++++++++++ lib/netsuite/records/translation_list.rb | 11 ++++++ .../lot_numbered_inventory_item_spec.rb | 1 + .../netsuite/records/translation_list_spec.rb | 34 +++++++++++++++++++ spec/netsuite/records/translation_spec.rb | 28 +++++++++++++++ 19 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 lib/netsuite/records/translation.rb create mode 100644 lib/netsuite/records/translation_list.rb create mode 100644 spec/netsuite/records/translation_list_spec.rb create mode 100644 spec/netsuite/records/translation_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index acc7cb6f8..6773b13af 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -285,6 +285,8 @@ module Records autoload :TransferOrder, 'netsuite/records/transfer_order' autoload :TransferOrderItemList, 'netsuite/records/transfer_order_item_list' autoload :TransferOrderItem, 'netsuite/records/transfer_order_item' + autoload :Translation, 'netsuite/records/translation' + autoload :TranslationList, 'netsuite/records/translation_list' autoload :UnitsType, 'netsuite/records/units_type' autoload :UnitsTypeUomList, 'netsuite/records/units_type_uom_list' autoload :UnitsTypeUom, 'netsuite/records/units_type_uom' diff --git a/lib/netsuite/records/custom_record.rb b/lib/netsuite/records/custom_record.rb index 4a8080407..18e66ee91 100644 --- a/lib/netsuite/records/custom_record.rb +++ b/lib/netsuite/records/custom_record.rb @@ -17,6 +17,7 @@ class CustomRecord :show_last_modified, :show_notes, :show_owner, :show_owner_allow_change, :show_owner_on_list, :use_permissions field :custom_field_list, CustomFieldList + field :translations_list, TranslationList record_refs :custom_form, :owner, :rec_type, :parent diff --git a/lib/netsuite/records/description_item.rb b/lib/netsuite/records/description_item.rb index 7a4d3a442..cda6de627 100644 --- a/lib/netsuite/records/description_item.rb +++ b/lib/netsuite/records/description_item.rb @@ -15,7 +15,7 @@ class SubtotalItem field :custom_field_list, CustomFieldList field :subsidiary_list, RecordRefList - # TODO field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index d16103d9e..f68177218 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -322,7 +322,7 @@ class InventoryItem # TODO: :presentation_item_list, PresentationItemList # TODO: :product_feed_list, ProductFeedList # TODO: :site_category_list, SiteCategoryList - # TODO: :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/item_group.rb b/lib/netsuite/records/item_group.rb index 3cda03efb..f2dff8b73 100644 --- a/lib/netsuite/records/item_group.rb +++ b/lib/netsuite/records/item_group.rb @@ -18,7 +18,7 @@ class ItemGroup # TODO field :item_carrier, ShippingCarrier field :member_list, ItemMemberList field :subsidiary_list, RecordRefList - # TODO field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/kit_item.rb b/lib/netsuite/records/kit_item.rb index 34dd2c7c2..e711f4099 100644 --- a/lib/netsuite/records/kit_item.rb +++ b/lib/netsuite/records/kit_item.rb @@ -49,7 +49,7 @@ class KitItem # field :product_feed_list, ProductFeedList # field :site_category_list, SiteCategoryList # field :sitemap_priority, SitemapPriority - # field :translations_list, TranslationList + field :translations_list, TranslationList # field :vsoe_deferral, VsoeDeferral # field :vsoe_permit_discount, VsoePermitDiscount # field :vsoe_sop_group, VsoeSopGroup diff --git a/lib/netsuite/records/lot_numbered_inventory_item.rb b/lib/netsuite/records/lot_numbered_inventory_item.rb index e5e14c301..6a7b2336f 100644 --- a/lib/netsuite/records/lot_numbered_inventory_item.rb +++ b/lib/netsuite/records/lot_numbered_inventory_item.rb @@ -25,7 +25,7 @@ class LotNumberedInventoryItem # TODO: field :presentation_item_list, PresentationItemList # TODO: field :product_feed_list, ProductFeedList # TODO: field :site_category_list, SiteCategoryList - # TODO: field :translations_list, TranslationList + field :translations_list, TranslationList actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index 0a939352a..b1f025309 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -170,7 +170,7 @@ class NonInventoryResaleItem # TODO: field :presentation_item_list, PresentationItemList # TODO: field :product_feed_list, ProductFeedList # TODO: field :site_category_list, SiteCategoryList - # TODO: field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index d274c2116..d7e6fac90 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -146,7 +146,7 @@ class NonInventorySaleItem # TODO: field :presentation_item_list, PresentationItemList # TODO: field :product_feed_list, ProductFeedList # TODO: field :site_category_list, SiteCategoryList - # TODO: field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/other_charge_sale_item.rb b/lib/netsuite/records/other_charge_sale_item.rb index 874643327..ad885773e 100644 --- a/lib/netsuite/records/other_charge_sale_item.rb +++ b/lib/netsuite/records/other_charge_sale_item.rb @@ -53,7 +53,7 @@ class OtherChargeSaleItem field :custom_field_list, CustomFieldList field :pricing_matrix, PricingMatrix - # :translations_list, + field :translations_list, TranslationList # :matrix_option_list, # :item_options_list field :subsidiary_list, RecordRefList diff --git a/lib/netsuite/records/payment_item.rb b/lib/netsuite/records/payment_item.rb index d58a0268d..e0151157b 100644 --- a/lib/netsuite/records/payment_item.rb +++ b/lib/netsuite/records/payment_item.rb @@ -17,7 +17,7 @@ class PaymentItem field :subsidiary_list, RecordRefList # TODO custom records need to be implemented - # field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/serialized_inventory_item.rb b/lib/netsuite/records/serialized_inventory_item.rb index 6ce9a46a8..01b3e41aa 100644 --- a/lib/netsuite/records/serialized_inventory_item.rb +++ b/lib/netsuite/records/serialized_inventory_item.rb @@ -214,7 +214,7 @@ class SerializedInventoryItem # site_category_list SiteCategoryList # sitemap_priority SitemapPriority # subsidiary_list RecordRefList - # translations_list TranslationList + field :translations_list, TranslationList # vsoe_deferral VsoeDeferral # vsoe_permit_discount VsoePermitDiscount # vsoe_sop_group VsoeSopGroup diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index 3b68e04df..6df1ef8a5 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -134,7 +134,7 @@ class ServiceResaleItem # TODO: field :hierarchy_versions_list, ServiceResaleItemHierarchyVersionsList # TODO: field :presentation_item_list, PresentationItemList # TODO: field :site_category_list, SiteCategoryList - # TODO: field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/subtotal_item.rb b/lib/netsuite/records/subtotal_item.rb index 85cb546a2..1932f4f03 100644 --- a/lib/netsuite/records/subtotal_item.rb +++ b/lib/netsuite/records/subtotal_item.rb @@ -15,7 +15,7 @@ class DescriptionItem field :custom_field_list, CustomFieldList field :subsidiary_list, RecordRefList - # TODO field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/translation.rb b/lib/netsuite/records/translation.rb new file mode 100644 index 000000000..ad43bf0b6 --- /dev/null +++ b/lib/netsuite/records/translation.rb @@ -0,0 +1,17 @@ +module NetSuite + module Records + class Translation + include Support::Fields + include Support::Records + include Namespaces::ListAcct + + fields :description, :display_name, :featured_description, :language, :locale, :locale_description, :name, + :no_price_message, :out_of_stock_message, :page_title, :replace_all, :sales_description, + :specials_description, :store_description, :store_detailed_description, :store_display_name + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + end + end +end diff --git a/lib/netsuite/records/translation_list.rb b/lib/netsuite/records/translation_list.rb new file mode 100644 index 000000000..699304cbf --- /dev/null +++ b/lib/netsuite/records/translation_list.rb @@ -0,0 +1,11 @@ +module NetSuite + module Records + class TranslationList < Support::Sublist + include NetSuite::Namespaces::ListAcct + + sublist :translation, NetSuite::Records::Translation + + alias translations translation + end + end +end diff --git a/spec/netsuite/records/lot_numbered_inventory_item_spec.rb b/spec/netsuite/records/lot_numbered_inventory_item_spec.rb index c10821bf3..cc27f5eec 100644 --- a/spec/netsuite/records/lot_numbered_inventory_item_spec.rb +++ b/spec/netsuite/records/lot_numbered_inventory_item_spec.rb @@ -176,6 +176,7 @@ matrix_option_list: NetSuite::Records::MatrixOptionList, pricing_matrix: NetSuite::Records::PricingMatrix, subsidiary_list: NetSuite::Records::RecordRefList, + translations_list: NetSuite::Records::TranslationList, }.each do |field, klass| expect(item).to have_field(field, klass) end diff --git a/spec/netsuite/records/translation_list_spec.rb b/spec/netsuite/records/translation_list_spec.rb new file mode 100644 index 000000000..ff2988090 --- /dev/null +++ b/spec/netsuite/records/translation_list_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe NetSuite::Records::TranslationList do + let(:list) { NetSuite::Records::TranslationList.new } + + it 'has a translations attribute' do + expect(list.translations).to be_kind_of(Array) + end + + describe '#to_record' do + before do + list.translations << NetSuite::Records::Translation.new( + locale: '_englishUK', + language: 'English (UK)', + display_name: 'display name', + sales_description: 'sales description' + ) + end + + it 'can represent itself as a SOAP record' do + record = { + "listAcct:translation" => [ + { + "listAcct:locale" => "_englishUK", + "listAcct:language" => "English (UK)", + "listAcct:displayName" => "display name", + "listAcct:salesDescription" => "sales description" + } + ] + } + expect(list.to_record).to eql(record) + end + end +end diff --git a/spec/netsuite/records/translation_spec.rb b/spec/netsuite/records/translation_spec.rb new file mode 100644 index 000000000..aa4436d44 --- /dev/null +++ b/spec/netsuite/records/translation_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe NetSuite::Records::Translation do + let(:translation) { NetSuite::Records::Translation.new } + + it 'has dynamic fields' do + [ + :description, + :display_name, + :featured_description, + :language, + :locale, + :locale_description, + :name, + :no_price_message, + :out_of_stock_message, + :page_title, + :replace_all, + :sales_description, + :specials_description, + :store_description, + :store_detailed_description, + :store_display_name + ].each do |field| + expect(translation).to have_field(field) + end + end +end From 73c96186699dff487bb401dd2f957830497647cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Feb 2022 14:14:23 -0700 Subject: [PATCH 077/114] Update rspec requirement from ~> 3.10.0 to ~> 3.11.0 (#518) Updates the requirements on [rspec](https://github.com/rspec/rspec-metagem) to permit the latest version. - [Release notes](https://github.com/rspec/rspec-metagem/releases) - [Commits](https://github.com/rspec/rspec-metagem/compare/v3.10.0...v3.11.0) --- updated-dependencies: - dependency-name: rspec dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- netsuite.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netsuite.gemspec b/netsuite.gemspec index 8504bceaf..39459f46f 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -19,6 +19,6 @@ Gem::Specification.new do |gem| gem.add_dependency 'savon', '>= 2.3.0' - gem.add_development_dependency 'rspec', '~> 3.10.0' + gem.add_development_dependency 'rspec', '~> 3.11.0' gem.add_development_dependency 'rake' end From 7a73c6d209f518ce8eaac49eb19eaff5b3c9ccb7 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 1 Mar 2022 04:49:16 -0700 Subject: [PATCH 078/114] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..d08e5491e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [NetSweet] From ea9347d81ece8a0bb403748464ab1fc3065a7f71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 20:33:12 -0700 Subject: [PATCH 079/114] Bump actions/checkout from 2 to 3 (#520) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 024b919b4..a40573f41 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: env: BUNDLE_TZINFO: "${{ matrix.bundle-tzinfo }}" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Ruby ${{ matrix.ruby-version }} uses: ruby/setup-ruby@v1 with: From 197d4e63e85d6a9fcd0ee0d45a1ee8a8b0ece05c Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 15 Mar 2022 21:01:52 -0600 Subject: [PATCH 080/114] Adding test for single result return --- spec/netsuite/support/search_result_spec.rb | 12 +++++ .../fixtures/search/single_search_result.xml | 46 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 spec/support/fixtures/search/single_search_result.xml diff --git a/spec/netsuite/support/search_result_spec.rb b/spec/netsuite/support/search_result_spec.rb index 53256e58c..8ef2c32ef 100644 --- a/spec/netsuite/support/search_result_spec.rb +++ b/spec/netsuite/support/search_result_spec.rb @@ -1,6 +1,9 @@ require 'spec_helper' describe NetSuite::Support::SearchResult do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + describe '#results' do context 'empty page' do it 'returns empty array' do @@ -20,5 +23,14 @@ expect(results).to eq [] end end + + it 'handles a recordList with a single element' do + response = File.read('spec/support/fixtures/search/single_search_result.xml') + savon.expects(:search).with(message: {}).returns(response) + + results = NetSuite::Records::Account.search(basic: []) + + expect(results.results.count).to eq 1 + end end end diff --git a/spec/support/fixtures/search/single_search_result.xml b/spec/support/fixtures/search/single_search_result.xml new file mode 100644 index 000000000..84f324269 --- /dev/null +++ b/spec/support/fixtures/search/single_search_result.xml @@ -0,0 +1,46 @@ + + + + WEBSERVICES_3603434_08292013908151921913870884_2f1b68b787b4d + + + + + + + 1 + 1000 + 1 + 1 + WEBSERVICES_3603434_08292013908151921913870884_2f1b68b787b4d + + + _costOfGoodsSold + 4508 + Selling Fees/Commissions - COS + false + _average + + 4500 Cost of Sales + + _average + false + false + false + + + false + + + false + + + false + + + + + + + + From 686cfcde76f0f0395b8992ab717550a4c1c8ce1d Mon Sep 17 00:00:00 2001 From: Fabien Sebban Date: Fri, 18 Mar 2022 21:32:12 +0100 Subject: [PATCH 081/114] add upsert list action for cash sales (#523) --- lib/netsuite/records/cash_sale.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/cash_sale.rb b/lib/netsuite/records/cash_sale.rb index 04d062199..ba12a0f79 100644 --- a/lib/netsuite/records/cash_sale.rb +++ b/lib/netsuite/records/cash_sale.rb @@ -7,7 +7,7 @@ class CashSale include Support::Actions include Namespaces::TranSales - actions :get, :add, :initialize, :delete, :update, :upsert, :search + actions :get, :add, :initialize, :delete, :update, :upsert, :upsert_list, :search fields :alt_handling_cost, :alt_shipping_cost, :auth_code, :bill_address, :cc_approved, :cc_expire_date, :cc_is_purchase_card_bin, :cc_name, :cc_number, :cc_process_as_purchas_card, :cc_security_code, :cc_street, :cc_zip_code, :charge_it, :contrib_pct, :created_date, From ca4d449279f4d7b31115731ab95cfaef8fcef4ea Mon Sep 17 00:00:00 2001 From: Eric Jensen Date: Wed, 23 Mar 2022 09:22:19 -0400 Subject: [PATCH 082/114] retry http client error subclasses since we use include? instead of is_a? on these (#524) * add httpclient timeout to backoff since it is the most preferred by httpi * retry http client error subclasses since we use include? instead of is_a? on these --- lib/netsuite/utilities.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index 9e25243a1..caee1239e 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -104,6 +104,9 @@ def backoff(options = {}) # depends on the http library chosen exceptions_to_retry << HTTPClient::TimeoutError if defined?(HTTPClient::TimeoutError) + exceptions_to_retry << HTTPClient::ConnectTimeoutError if defined?(HTTPClient::ConnectTimeoutError) + exceptions_to_retry << HTTPClient::ReceiveTimeoutError if defined?(HTTPClient::ReceiveTimeoutError) + exceptions_to_retry << HTTPClient::SendTimeoutError if defined?(HTTPClient::SendTimeoutError) exceptions_to_retry << Excon::Error::Timeout if defined?(Excon::Error::Timeout) exceptions_to_retry << Excon::Error::Socket if defined?(Excon::Error::Socket) From 91b2b2402d427943f6ba754e7f6d985fbddde030 Mon Sep 17 00:00:00 2001 From: Justin Dunn <92949245+JustinDunnWahoo@users.noreply.github.com> Date: Thu, 24 Mar 2022 19:05:42 -0500 Subject: [PATCH 083/114] Issue-521: Add Ship Address to Return Authorization (#525) --- lib/netsuite/records/return_authorization.rb | 1 + .../records/return_authorization_spec.rb | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 spec/netsuite/records/return_authorization_spec.rb diff --git a/lib/netsuite/records/return_authorization.rb b/lib/netsuite/records/return_authorization.rb index dc92e0cc9..12f34eb5e 100644 --- a/lib/netsuite/records/return_authorization.rb +++ b/lib/netsuite/records/return_authorization.rb @@ -105,6 +105,7 @@ class ReturnAuthorization # :ship_address_list, field :billing_address, Address + field :shipping_address, Address field :custom_field_list, CustomFieldList field :item_list, ReturnAuthorizationItemList diff --git a/spec/netsuite/records/return_authorization_spec.rb b/spec/netsuite/records/return_authorization_spec.rb new file mode 100644 index 000000000..5d2c4a149 --- /dev/null +++ b/spec/netsuite/records/return_authorization_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe NetSuite::Records::ReturnAuthorization do + let(:return_authorization) { NetSuite::Records::ReturnAuthorization.new } + + + describe '#shipping_address' do + it 'can be set from attributes' do + attributes = { + :country => "_unitedStates", + :attention => "William Sanders", + :addressee => "William Sanders", + :addr1 => "test1", + :addr2 => "test2", + :city => "San Francisco", + :state => "CA", + :zip => "94131", + :addr_text => "William Sanders
William Sanders
test1
test2
San Francisco CA 94131", + :override => false, + :"@xmlns:platform_common" => "urn:common_2016_1.platform.webservices.netsuite.com" + } + + return_authorization.shipping_address = attributes + expect(return_authorization.shipping_address).to be_kind_of(NetSuite::Records::Address) + expect(return_authorization.shipping_address.addressee).to eql("William Sanders") + end + + it 'can be set from a ItemVendorList object' do + shipping_address = NetSuite::Records::Address.new + return_authorization.shipping_address = shipping_address + expect(return_authorization.shipping_address).to eql(shipping_address) + end + end + + describe '#billing_address' do + it 'can be set from attributes' do + attributes = { + :country => "_unitedStates", + :attention => "William Sanders", + :addressee => "William Sanders", + :addr1 => "test1", + :addr2 => "test2", + :city => "San Francisco", + :state => "CA", + :zip => "94131", + :addr_text => "William Sanders
William Sanders
test1
test2
San Francisco CA 94131", + :override => false, + :"@xmlns:platform_common" => "urn:common_2016_1.platform.webservices.netsuite.com" + } + + return_authorization.billing_address = attributes + expect(return_authorization.billing_address).to be_kind_of(NetSuite::Records::Address) + expect(return_authorization.billing_address.addressee).to eql("William Sanders") + end + + it 'can be set from a ItemVendorList object' do + billing_address = NetSuite::Records::Address.new + return_authorization.billing_address = billing_address + expect(return_authorization.billing_address).to eql(billing_address) + end + end +end From e10ea560587299c6ceac027bf32f32fe6c8648c0 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:49:01 -0600 Subject: [PATCH 084/114] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..8b120d5e7 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '32 15 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'ruby' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 4cc7fb85958febe822809d4e7a32515cee4975ad Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:50:21 -0600 Subject: [PATCH 085/114] Remove autogenerated TOC GH has this built in now --- README.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/README.md b/README.md index 4364f3622..1cfc0b09f 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,3 @@ - - -**Table of Contents** - -- [NetSuite SuiteTalk API Ruby Gem](#netsuite-suitetalk-api-ruby-gem) -- [Help & Support](#help--support) -- [Testing](#testing) -- [Installation](#installation) - - [Configuration](#configuration) - - [Token based Authentication](#token-based-authentication) -- [Usage](#usage) - - [CRUD Operations](#crud-operations) - - [Uploading/Attaching Files](#uploadingattaching-files) - - [Custom Records & Fields](#custom-records--fields) - - [Searching](#searching) - - [Non-standard Operations](#non-standard-operations) - - - [![Ruby](https://github.com/NetSweet/netsuite/actions/workflows/main.yml/badge.svg)](https://github.com/NetSweet/netsuite/actions/workflows/main.yml) [![Slack Status](https://opensuite-slackin.herokuapp.com/badge.svg)](http://opensuite-slackin.herokuapp.com) [![Gem Version](https://badge.fury.io/rb/netsuite.svg)](http://badge.fury.io/rb/netsuite) From 4bad5bd12d30598453ffe661a1e98754b3e4f7a2 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:50:48 -0600 Subject: [PATCH 086/114] Adding ruby 3.1 to ci run --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a40573f41..ebc8f9f6f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: [3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] + ruby-version: [3.1, 3.0, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1] bundle-tzinfo: [true, false] env: BUNDLE_TZINFO: "${{ matrix.bundle-tzinfo }}" From a67b0e53aa5b56aac5ac297d6ffe002a56c5d6d2 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:52:35 -0600 Subject: [PATCH 087/114] Adding service sale resale item to item get utility --- lib/netsuite/utilities.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index caee1239e..7708857cd 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -174,6 +174,7 @@ def get_item(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::ServiceSaleItem, ns_item_internal_id, opts) + ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::ServiceResaleItem, 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) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedInventoryItem, ns_item_internal_id, opts) From aab7a0a9c7ee7391e258e88b78a87908c05a1f0a Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:55:18 -0600 Subject: [PATCH 088/114] Bumping changelog --- HISTORY.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index cba4b00f4..838a5e850 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,9 +1,16 @@ ## Unreleased ### Added + +### Fixed + +## 0.8.11 + +### Added + * Update ServiceResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#500) * Dependabot to CI -* CI run for Ruby 3 +* CI run for Ruby 3.0 & 3.1 * Add CI run for an environment with and without `tzinfo` installed * Update NonInventorySaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#503) * Implement MatrixOptionList#to_record (#504) @@ -13,11 +20,16 @@ * Update NonInventoryResaleItem record fields/record refs for 2021.2. `item_options_list`, `presentation_item_list`, `product_feed_list`, `site_category_list`, `translations_list` were all removed as fields as the are not simple fields, they require special classes. (#508) * Add `attach_file` action for Invoice and SalesOrder. (#509) * Add ItemOptionCustomField recrd (#512) +* Add Ship Address to Return Authorization (#525) +* Support translations records (#516) ### Fixed + * Fix "undefined method `[]` for #" when adding File (#495) * Moved definition of `search_joins` attribute from records to search action. The attribute was removed for AssemblyComponent, SerializedInventoryItemLocation, and WorkOrderItem as they don't offer the search action. (#511) * Consider externalId in search criteria when using RecordRef as value (#517) +* Retry http client error subclasses +* Add upsert list action for cash sales (#523) ## 0.8.10 From 6f956fcafb20c61cd9a8063f4a9340bf09f8d487 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:57:13 -0600 Subject: [PATCH 089/114] Bumping version --- lib/netsuite/version.rb | 2 +- netsuite.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index 98c3aebd2..c88a0301c 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.10' + VERSION = '0.8.11' end diff --git a/netsuite.gemspec b/netsuite.gemspec index 39459f46f..205b6faa0 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |gem| gem.add_dependency 'savon', '>= 2.3.0' gem.add_development_dependency 'rspec', '~> 3.11.0' - gem.add_development_dependency 'rake' + gem.add_development_dependency 'rake', '~> 13' end From 3c9e7f3164573f3fdefdf732abc8bc9b1bacffbb Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 08:59:55 -0600 Subject: [PATCH 090/114] Dropping rake gemspec --- netsuite.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netsuite.gemspec b/netsuite.gemspec index 205b6faa0..aaa3d7dc9 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |gem| gem.add_dependency 'savon', '>= 2.3.0' gem.add_development_dependency 'rspec', '~> 3.11.0' - gem.add_development_dependency 'rake', '~> 13' + gem.add_development_dependency 'rake', '~> 10' end From 49581518a6a6ed6509ffc66bdd9325fa606dd08b Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sun, 27 Mar 2022 09:02:13 -0600 Subject: [PATCH 091/114] Minimum rake version for security fix --- netsuite.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netsuite.gemspec b/netsuite.gemspec index aaa3d7dc9..9102e627f 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |gem| gem.add_dependency 'savon', '>= 2.3.0' gem.add_development_dependency 'rspec', '~> 3.11.0' - gem.add_development_dependency 'rake', '~> 10' + gem.add_development_dependency 'rake', '~> 12.3.3' end From e6c10abec74132142b2ed87f03c9134e14ef0ac2 Mon Sep 17 00:00:00 2001 From: Zack Kanter Date: Sun, 27 Mar 2022 17:30:38 -0400 Subject: [PATCH 092/114] Minor readme updates (#526) --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1cfc0b09f..e853172c6 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ # NetSuite SuiteTalk API Ruby Gem -* This gem will act as a wrapper around the NetSuite SuiteTalk WebServices API. +* This gem will act as a wrapper around the NetSuite SuiteTalk Web Services API. * The gem does not cover the entire API, only the subset contributors have used so far. Please submit a PR for any functionality that's missing! * NetSuite is a complex system. There's a lot to learn and sparse resources available to learn from. Here's a list of [NetSuite Development Resources](https://github.com/NetSweet/netsuite/wiki/NetSuite-Development-Resources). # Help & Support -Join the [slack channel](http://opensuite-slackin.herokuapp.com) for help with any NetSuite issues. Please do not post usage questions as issues in GitHub. +Join the [Slack channel](http://opensuite-slackin.herokuapp.com) for help with any NetSuite issues. Please do not post usage questions as issues in GitHub. There is some additional helpful resources for NetSuite development [listed here](https://dashboard.suitesync.io/docs/resources#netsuite). @@ -36,20 +36,20 @@ gem 'netsuite' If you'd like more accurate time conversion support, include the `tzinfo` gem. -This gem is built for ruby 2.6.x+, but should work on older versions down to 1.9. There's a [1-8-stable](https://github.com/NetSweet/netsuite/tree/1-8-stable) branch for ruby 1.8.x support. +This gem is built for Ruby 2.6.x+, but should work on older versions down to 1.9. There's a [1-8-stable](https://github.com/NetSweet/netsuite/tree/1-8-stable) branch for Ruby 1.8.x support. ## Configuration -The most important thing you'll need is your NetSuite account ID. Not sure how to find your account id? [Here's a guide.](http://mikebian.co/find-netsuite-web-services-account-number/) +The most important thing you'll need is your NetSuite account ID. Not sure how to find your account ID? [Here's a guide.](http://mikebian.co/find-netsuite-web-services-account-number/) How you connect to NetSuite has changed a lot over the years and differs between API versions. For instance: * Older API versions (~2015) allowed authentication via username and password -* Newever API versions (> 2016) still allowed for username and password authentication, but required an application ID +* Newer API versions (> 2016) still allowed for username and password authentication, but required an application ID * "OAuth", which requires four separate keys to be manually generated, was supported sometime after 2015 * API versions greater than 2018_2 require `endpoint` to be set directly ([more info](https://github.com/NetSweet/netsuite/pull/473)) -Here's an example connection configuration. You don't want to actually use username + password config; token based authentication is detailed below in a separate section: +Here's an example connection configuration. You don't want to actually use username + password config; Token Based Authentication is detailed [in a separate section](#token-based-authentication): ```ruby NetSuite.configure do @@ -60,13 +60,13 @@ NetSuite.configure do api_version '2018_2' # password-based login information - # in most cases you should use token based authentication instead + # in most cases you should use Token Based Authentication instead email 'email@example.com' password 'password' role 10 - # recent API versions require a account-specific endpoint o be set - # use `NetSuite::Utilities.data_center_url('TSTDRV1576318')` to retrieve wsdl URL + # recent API versions require an account-specific endpoint to be set + # use `NetSuite::Utilities.data_center_url('TSTDRV1576318')` to retrieve WSDL URL # you'll want to do this in a background process and strip the protocol out of the return string wsdl_domain 'tstdrv1576318.suitetalk.api.netsuite.com' @@ -87,17 +87,17 @@ NetSuite.configure do api_version '2018_2' - # optionally specify full wsdl URL (to switch to sandbox, for example) + # optionally specify full WSDL URL (to switch to sandbox, for example) wsdl "https://webservices.sandbox.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl" - # if your datacenter is being switched, you'll have to manually set your wsdl location + # if your datacenter is being switched, you'll have to manually set your WSDL location wsdl "https://webservices.na2.netsuite.com/wsdl/v#{api_version}_0/netsuite.wsdl" # or specify the wsdl_domain if you want to specify the datacenter and let the configuration # construct the full wsdl location - e.g. "https://#{wsdl_domain}/wsdl/v#{api_version}_0/netsuite.wsdl" wsdl_domain "webservices.na2.netsuite.com" - # often the netsuite servers will hang which would cause a timeout exception to be raised + # often the NetSuite servers will hang which would cause a timeout exception to be raised # if you don't mind waiting (e.g. processing NS via a background worker), increasing the timeout should fix the issue read_timeout 100_000 @@ -111,7 +111,7 @@ NetSuite.configure do # log_level :debug # password-based login information - # in most cases you should use token based authentication instead + # in most cases you should use Token Based Authentication instead email 'email@domain.com' password 'password' account '12345' @@ -124,7 +124,7 @@ NetSuite.configure do end ``` -If are using username + password authentication (which you shouldn't be!) *and* you'd like to use a API endpoints greater than 2015_1 you'll need to specify an application ID: +If you are using username + password authentication (which you shouldn't be!) *and* you'd like to use an API endpoint greater than 2015_1, you'll need to specify an application ID: ```ruby NetSuite::Configuration.soap_header = { @@ -134,9 +134,9 @@ NetSuite::Configuration.soap_header = { } ``` -### Token based Authentication +### Token Based Authentication -OAuth credentials are supported and the recommended authentication approach. [Learn more about how to set up token based authentication here](http://mikebian.co/using-netsuites-token-based-authentication-with-suitetalk/). +OAuth credentials are supported and the recommended authentication approach. [Learn more about how to set up Token Based Authentication here](http://mikebian.co/using-netsuites-token-based-authentication-with-suitetalk/). ```ruby NetSuite.configure do @@ -152,7 +152,7 @@ NetSuite.configure do # oauth does not work with API versions less than 2015_2 api_version '2016_2' - # the endpoint indicated in the > 2018_2 wsdl is invalid + # the endpoint indicated in the > 2018_2 WSDL is invalid # you must set the endpoint directly # https://github.com/NetSweet/netsuite/pull/473 endpoint "https://#{wsdl_domain}/services/NetSuitePort_#{api_version}" @@ -300,7 +300,7 @@ search = NetSuite::Records::Customer.search({ `open https://system.netsuite.com/app/common/entity/custjob.nl?id=#{search.results.first.internal_id}` -# find the avalara tax item. Some records don't support search. +# find the Avalara tax item. Some records don't support search. all_sales_taxes = NetSuite::Utilities.backoff { NetSuite::Records::SalesTaxItem.get_all } ns_tax_code = all_sales_taxes.detect { |st| st.item_id == 'AVATAX' } @@ -411,7 +411,7 @@ NetSuite::Records::SalesOrder.search({ ] }, - # the column syntax is a WIP. This will change in the future + # the column syntax is a WIP. This will change in the future. columns: { 'tranSales:basic' => [ 'platformCommon:internalId/' => {}, From 2ec2400c9e7ed46e4322d56db9bf8c34a5fd3775 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 07:39:11 -0600 Subject: [PATCH 093/114] Bump actions/checkout from 2 to 3 (#527) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8b120d5e7..c72628c14 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From 6c81f30d567cd8e0ecc1e507831fe01d28095cd3 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Thu, 7 Apr 2022 07:41:54 -0400 Subject: [PATCH 094/114] Add support for NullFieldList (starting with credit memos and invoices) (#529) NullFieldList is used to either clear an existing value on update, or avoid a default being applied on adding a record. My use case only required support for credit memos and invoices, so I started there, but this could likely be added to most records. This was heavily inspired by @gmike11's work in #481, but that seems to lump a bunch of changes together. This also solves #398. Where #481 manipulated the XML request body to address that the `` needs to always use the `platformCore` namespace, as opposed to the record's normal namespace (ie `transSale` for invoice) as happens for any other field, I tried to address that on the `#to_record` side. --- HISTORY.md | 2 + README.md | 16 +++++++- lib/netsuite.rb | 1 + lib/netsuite/records/credit_memo.rb | 1 + lib/netsuite/records/invoice.rb | 1 + lib/netsuite/records/null_field_list.rb | 15 +++++++ lib/netsuite/support/records.rb | 2 +- spec/netsuite/records/credit_memo_spec.rb | 14 +++++++ spec/netsuite/records/invoice_spec.rb | 14 +++++++ spec/netsuite/records/null_field_list_spec.rb | 30 ++++++++++++++ spec/netsuite/support/records_spec.rb | 40 +++++++++++++++---- 11 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 lib/netsuite/records/null_field_list.rb create mode 100644 spec/netsuite/records/null_field_list_spec.rb diff --git a/HISTORY.md b/HISTORY.md index 838a5e850..6f8b33057 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,8 @@ ### Added +* Add NullFieldList record (to credit memos and invoices) (#529) + ### Fixed ## 0.8.11 diff --git a/README.md b/README.md index e853172c6..d56d1df1c 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,20 @@ NetSuite::Records::BaseRefList.get_select_value( ) ``` +## Null Fields + +```ruby +# updating a field on a record to be null +invoice = NetSuite::Records::Invoice.get(12345) +invoice.update(null_field_list: 'shipMethod') + +# updating multiple fields on a record to be null +invoice.update(null_field_list: ['shipAddressList', 'shipMethod']) + +# updating a custom fields on a record to be null, using custom field ID +invoice.update(null_field_list: 'custBody9') +``` + ## Searching ```ruby @@ -417,7 +431,7 @@ NetSuite::Records::SalesOrder.search({ 'platformCommon:internalId/' => {}, 'platformCommon:email/' => {}, 'platformCommon:tranDate/' => {}, - # If you include columns that are only part of the *SearchRowBasic (ie. TransactionSearchRowBasic), + # If you include columns that are only part of the *SearchRowBasic (ie. TransactionSearchRowBasic), # they'll be readable on the resulting record just like regular fields (my_record.close_date). 'platformCommon:closeDate/' => {} ], diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 6773b13af..5c385c6b2 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -225,6 +225,7 @@ module Records autoload :NonInventoryResaleItem, 'netsuite/records/non_inventory_resale_item' autoload :Note, 'netsuite/records/note' autoload :NoteType, 'netsuite/records/note_type' + 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/credit_memo.rb b/lib/netsuite/records/credit_memo.rb index 704a2ed54..887bcac1c 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/invoice.rb b/lib/netsuite/records/invoice.rb index a5c4e7213..eb2aeec43 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/null_field_list.rb b/lib/netsuite/records/null_field_list.rb new file mode 100644 index 000000000..3d6f8cb51 --- /dev/null +++ b/lib/netsuite/records/null_field_list.rb @@ -0,0 +1,15 @@ +module NetSuite + module Records + class NullFieldList + include Support::Fields + include Support::Records + include Namespaces::PlatformCore + + fields :name + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + end + end +end diff --git a/lib/netsuite/support/records.rb b/lib/netsuite/support/records.rb index b6f790063..917bd729b 100644 --- a/lib/netsuite/support/records.rb +++ b/lib/netsuite/support/records.rb @@ -6,7 +6,7 @@ module Records def to_record attributes.reject { |k,v| self.class.read_only_fields.include?(k) || self.class.search_only_fields.include?(k) }.inject({}) do |hash, (k,v)| - kname = "#{record_namespace}:" + kname = "#{v.is_a?(NetSuite::Records::NullFieldList) ? v.record_namespace : record_namespace}:" kname += k == :klass ? 'class' : k.to_s.lower_camelcase to_attributes!(hash, kname, v) diff --git a/spec/netsuite/records/credit_memo_spec.rb b/spec/netsuite/records/credit_memo_spec.rb index 0c79c2f29..1a3058865 100644 --- a/spec/netsuite/records/credit_memo_spec.rb +++ b/spec/netsuite/records/credit_memo_spec.rb @@ -20,6 +20,20 @@ end end + it 'has all the right fields with specific classes' do + { + custom_field_list: NetSuite::Records::CustomFieldList, + item_list: NetSuite::Records::CreditMemoItemList, + apply_list: NetSuite::Records::CreditMemoApplyList, + ship_group_list: NetSuite::Records::SalesOrderShipGroupList, + null_field_list: NetSuite::Records::NullFieldList, + transaction_bill_address: NetSuite::Records::BillAddress, + billing_address: NetSuite::Records::Address, + }.each do |field, klass| + expect(memo).to have_field(field, klass) + end + end + it 'has all the right record refs' do [ :account, :bill_address_list, :created_from, :custom_form, :department, :discount_item, :entity, :gift_cert, diff --git a/spec/netsuite/records/invoice_spec.rb b/spec/netsuite/records/invoice_spec.rb index 4156bc6ad..e903459b6 100644 --- a/spec/netsuite/records/invoice_spec.rb +++ b/spec/netsuite/records/invoice_spec.rb @@ -32,6 +32,20 @@ end end + it 'has all the right fields with specific classes' do + { + transaction_bill_address: NetSuite::Records::BillAddress, + transaction_ship_address: NetSuite::Records::ShipAddress, + item_list: NetSuite::Records::InvoiceItemList, + custom_field_list: NetSuite::Records::CustomFieldList, + shipping_address: NetSuite::Records::Address, + billing_address: NetSuite::Records::Address, + null_field_list: NetSuite::Records::NullFieldList, + }.each do |field, klass| + expect(invoice).to have_field(field, klass) + end + end + it 'has all the right read_only_fields' do [ :sub_total, :discount_total, :total, :alt_handling_cost, :alt_shipping_cost, :gift_cert_applied, diff --git a/spec/netsuite/records/null_field_list_spec.rb b/spec/netsuite/records/null_field_list_spec.rb new file mode 100644 index 000000000..c6e0ada6b --- /dev/null +++ b/spec/netsuite/records/null_field_list_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe NetSuite::Records::RecordRef do + let(:null_field_list) { NetSuite::Records::NullFieldList.new } + + describe '#to_record' do + it 'can represent itself as a SOAP record for single value' do + null_field_list.name = 'blah' + record = { + 'platformCore:name' => 'blah' + } + expect(null_field_list.to_record).to eql(record) + end + + it 'can represent itself as a SOAP record for multiple values' do + null_field_list.name = ['blah', 'foo'] + record = { + 'platformCore:name' => ['blah', 'foo'] + } + expect(null_field_list.to_record).to eql(record) + end + end + + describe '#record_type' do + it 'returns a string of the SOAP type' do + expect(null_field_list.record_type).to eql('platformCore:NullFieldList') + end + end + +end diff --git a/spec/netsuite/support/records_spec.rb b/spec/netsuite/support/records_spec.rb index bc4fcea68..8db40dfb2 100644 --- a/spec/netsuite/support/records_spec.rb +++ b/spec/netsuite/support/records_spec.rb @@ -4,11 +4,14 @@ module Foo module Bar class Baz include NetSuite::Support::Fields + include NetSuite::Support::RecordRefs include NetSuite::Support::Records + include NetSuite::Namespaces::TranSales - def attributes - { :source => 'Google', :total => 100.0 } - end + fields :source, :total + field :null_field_list, NetSuite::Records::NullFieldList + + record_ref :related_record end end end @@ -16,18 +19,41 @@ def attributes describe NetSuite::Support::Records do let(:instance) { Foo::Bar::Baz.new } - describe '#record_type' do + describe '#to_record' do it 'returns a hash of attributes to be used in a SOAP request' do + instance.source = 'Google' + instance.total = 100.0 + expect(instance.to_record).to eql({ - 'platformCore:source' => 'Google', - 'platformCore:total' => 100.0 + 'tranSales:source' => 'Google', + 'tranSales:total' => 100.0 + }) + end + + it 'uses the records namespace for the outer elements namespace and the field values namespace for the inner elements namespace' do + instance.related_record = NetSuite::Records::RecordRef.new(name: 'blah') + + expect(instance.to_record).to eq({ + 'tranSales:relatedRecord' => { + 'platformCore:name' => 'blah', + }, + }) + end + + it 'uses the fields namespace for the outer elements namespace for NullFieldList value' do + instance.null_field_list.name = 'source' + + expect(instance.to_record).to eq({ + 'platformCore:nullFieldList' => { + 'platformCore:name' => 'source', + }, }) end end describe '#record_type' do it 'returns a string of the record type to be used in a SOAP request' do - expect(instance.record_type).to eql('platformCore:Baz') + expect(instance.record_type).to eql('tranSales:Baz') end end From 2ae63b9e46d897f75a2c187ff93bd4529d995906 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 12 Apr 2022 17:22:35 -0400 Subject: [PATCH 095/114] Add `get_deleted` action to item records (#530) I also added some documentation about how to use the action. The documentation reveals a few rough parts around this action. Notably: The response you get back is very raw, and not a typical record. Given how little data is returned, I'm not sure if it'd be better to instantiate a full record for consistency, or if there should be a new `DeletedRecord`-style record, with a field for `deleted_date` and a record_ref for `record`, making it a little easier to work with. You have to paginate yourself. Eventually it'd be nice if something like `SearchResult#results_in_batches` were offered to do it for you, though that'd be a breaking change to the return value of the action currently. The record class you call `get_deleted` on has no influence on the request actually performed, so without any criteria, you'll get records back that are totally unrelated to the record class it was called upon. This goes beyond how search works where an inventory item search returns all item types, this includes even non-items that were deleted. Perhaps it'd be less surprising if the gem set a type criteria for you based on the calling record type, though perhaps there's some value in the current behavior of wanting to get all deleted records regardless of type? --- HISTORY.md | 1 + README.md | 47 +++++++++++++++++++ lib/netsuite/records/assembly_item.rb | 2 +- lib/netsuite/records/description_item.rb | 4 +- lib/netsuite/records/discount_item.rb | 2 +- lib/netsuite/records/inventory_item.rb | 2 +- lib/netsuite/records/item_group.rb | 4 +- lib/netsuite/records/kit_item.rb | 2 +- .../records/lot_numbered_assembly_item.rb | 2 +- .../records/lot_numbered_inventory_item.rb | 2 +- .../records/non_inventory_purchase_item.rb | 2 +- .../records/non_inventory_resale_item.rb | 2 +- .../records/non_inventory_sale_item.rb | 2 +- .../records/other_charge_sale_item.rb | 2 +- lib/netsuite/records/payment_item.rb | 4 +- .../records/serialized_assembly_item.rb | 2 +- .../records/serialized_inventory_item.rb | 2 +- lib/netsuite/records/service_resale_item.rb | 2 +- lib/netsuite/records/service_sale_item.rb | 2 +- lib/netsuite/records/subtotal_item.rb | 5 +- 20 files changed, 70 insertions(+), 23 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 6f8b33057..592d97ab1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ ### Added * Add NullFieldList record (to credit memos and invoices) (#529) +* Add `get_deleted` action to item records (#530) ### Fixed diff --git a/README.md b/README.md index d56d1df1c..c3de3c7b3 100644 --- a/README.md +++ b/README.md @@ -607,6 +607,53 @@ deposit.payment = 20 deposit.add ``` +## Getting Deleted Records + +```ruby +response = NetSuite::Records::LotNumberedInventoryItem.get_deleted({ + criteria: [ + { + # If you don't specify a type criteria, you'll get all deleted records, + # regardless of the type of record you called this on. + field: 'type', + operator: 'anyOf', + value: 'lotNumberedInventoryItem', + } + ], +}) + +Array(response.body.fetch(:deleted_record_list)).first +# => { +# :deleted_date => Wed, 16 Feb 2022 17:43:45 -0800, +# :record => { +# :name => "My Item", +# :@internal_id => "12485", +# :@type => "lotNumberedInventoryItem", +# :"@xsi:type" => "platformCore:RecordRef" +# } +# } + +# deleted_record_list could be: +# nil - No records matching criteria were deleted +# Hash - A single record matching criteria was deleted +# Array - Multiple records matching criteria were deleted + +# Simple pagination +page = 1 +begin + response = NetSuite::Records::LotNumberedInventoryItem.get_deleted({ + criteria: [ + # your criteria + ], + page: page, + }) + + # Do your thing with response.body.fetch(:deleted_record_list) + + page += 1 +end until page > Integer(response.fetch(:total_pages)) +``` + ## Non-standard Operations ```ruby diff --git a/lib/netsuite/records/assembly_item.rb b/lib/netsuite/records/assembly_item.rb index e7cce6372..4b1743f1d 100644 --- a/lib/netsuite/records/assembly_item.rb +++ b/lib/netsuite/records/assembly_item.rb @@ -7,7 +7,7 @@ class AssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search + actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, :build_entire_assembly, :copy_description, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, diff --git a/lib/netsuite/records/description_item.rb b/lib/netsuite/records/description_item.rb index cda6de627..b11ae2a50 100644 --- a/lib/netsuite/records/description_item.rb +++ b/lib/netsuite/records/description_item.rb @@ -7,12 +7,12 @@ class SubtotalItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :item_id, :last_modified_date record_refs :custom_form, :department, :issue_product, :klass, :location - + field :custom_field_list, CustomFieldList field :subsidiary_list, RecordRefList field :translations_list, TranslationList diff --git a/lib/netsuite/records/discount_item.rb b/lib/netsuite/records/discount_item.rb index db1cc7827..ae626a4d2 100644 --- a/lib/netsuite/records/discount_item.rb +++ b/lib/netsuite/records/discount_item.rb @@ -7,7 +7,7 @@ class DiscountItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :update, :delete, :search, :upsert + actions :get, :get_deleted, :get_list, :add, :update, :delete, :search, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :is_pre_tax, :item_id, :last_modified_date, :non_posting, :rate, :upc_code, :vendor_name diff --git a/lib/netsuite/records/inventory_item.rb b/lib/netsuite/records/inventory_item.rb index f68177218..e8473c963 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -20,7 +20,7 @@ class InventoryItem # } # ] # - actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert, :update_list fields :auto_lead_time, :auto_preferred_stock_level, diff --git a/lib/netsuite/records/item_group.rb b/lib/netsuite/records/item_group.rb index f2dff8b73..d92f7c1e3 100644 --- a/lib/netsuite/records/item_group.rb +++ b/lib/netsuite/records/item_group.rb @@ -7,13 +7,13 @@ class ItemGroup include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :include_start_end_lines, :is_inactive, :is_vsoe_bundle, :item_id, :last_modified_date, :print_items, :upc_code, :vendor_name record_refs :custom_form, :default_item_ship_method, :department, :issue_product, :item_ship_method_list, :klass, :location, :parent - + field :custom_field_list, CustomFieldList # TODO field :item_carrier, ShippingCarrier field :member_list, ItemMemberList diff --git a/lib/netsuite/records/kit_item.rb b/lib/netsuite/records/kit_item.rb index e711f4099..2eb059559 100644 --- a/lib/netsuite/records/kit_item.rb +++ b/lib/netsuite/records/kit_item.rb @@ -7,7 +7,7 @@ class KitItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :cost_estimate, :created_date, :defer_rev_rec, :description, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, :handling_cost, diff --git a/lib/netsuite/records/lot_numbered_assembly_item.rb b/lib/netsuite/records/lot_numbered_assembly_item.rb index 67c7d07f3..b3509833b 100644 --- a/lib/netsuite/records/lot_numbered_assembly_item.rb +++ b/lib/netsuite/records/lot_numbered_assembly_item.rb @@ -7,7 +7,7 @@ class LotNumberedAssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search + actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, :build_entire_assembly, :copy_description, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, diff --git a/lib/netsuite/records/lot_numbered_inventory_item.rb b/lib/netsuite/records/lot_numbered_inventory_item.rb index 6a7b2336f..02d2ddc49 100644 --- a/lib/netsuite/records/lot_numbered_inventory_item.rb +++ b/lib/netsuite/records/lot_numbered_inventory_item.rb @@ -27,7 +27,7 @@ class LotNumberedInventoryItem # TODO: field :site_category_list, SiteCategoryList field :translations_list, TranslationList - actions :get, :get_list, :add, :delete, :search, :update, :upsert, :update_list + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert, :update_list record_refs :alternate_demand_source_item, :asset_account, diff --git a/lib/netsuite/records/non_inventory_purchase_item.rb b/lib/netsuite/records/non_inventory_purchase_item.rb index 12d831eb0..85d0e5c66 100644 --- a/lib/netsuite/records/non_inventory_purchase_item.rb +++ b/lib/netsuite/records/non_inventory_purchase_item.rb @@ -7,7 +7,7 @@ class NonInventoryPurchaseItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :upsert fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index b1f025309..2d018a665 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -7,7 +7,7 @@ class NonInventoryResaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :upsert, :update + actions :get, :get_deleted, :get_list, :add, :delete, :search, :upsert, :update fields :amortization_period, :available_to_partners, diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index d7e6fac90..216452ae2 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -7,7 +7,7 @@ class NonInventorySaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :contingent_revenue_handling, diff --git a/lib/netsuite/records/other_charge_sale_item.rb b/lib/netsuite/records/other_charge_sale_item.rb index ad885773e..e595b097c 100644 --- a/lib/netsuite/records/other_charge_sale_item.rb +++ b/lib/netsuite/records/other_charge_sale_item.rb @@ -7,7 +7,7 @@ class OtherChargeSaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/payment_item.rb b/lib/netsuite/records/payment_item.rb index e0151157b..d740f649c 100644 --- a/lib/netsuite/records/payment_item.rb +++ b/lib/netsuite/records/payment_item.rb @@ -7,7 +7,7 @@ class PaymentItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :item_id, :last_modified_date, :undep_funds @@ -15,7 +15,7 @@ class PaymentItem field :custom_field_list, CustomFieldList field :subsidiary_list, RecordRefList - + # TODO custom records need to be implemented field :translations_list, TranslationList diff --git a/lib/netsuite/records/serialized_assembly_item.rb b/lib/netsuite/records/serialized_assembly_item.rb index 60c0c5866..6f5d04ab9 100644 --- a/lib/netsuite/records/serialized_assembly_item.rb +++ b/lib/netsuite/records/serialized_assembly_item.rb @@ -7,7 +7,7 @@ class SerializedAssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :alternate_demand_source_item, :asset_account, diff --git a/lib/netsuite/records/serialized_inventory_item.rb b/lib/netsuite/records/serialized_inventory_item.rb index 01b3e41aa..25ba32ee6 100644 --- a/lib/netsuite/records/serialized_inventory_item.rb +++ b/lib/netsuite/records/serialized_inventory_item.rb @@ -7,7 +7,7 @@ class SerializedInventoryItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert record_refs :soft_descriptor, :stock_unit, diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index 6df1ef8a5..529b6f519 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -7,7 +7,7 @@ class ServiceResaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search fields :amortization_period, :available_to_partners, diff --git a/lib/netsuite/records/service_sale_item.rb b/lib/netsuite/records/service_sale_item.rb index 0bb8e6fb2..8b7800cf1 100644 --- a/lib/netsuite/records/service_sale_item.rb +++ b/lib/netsuite/records/service_sale_item.rb @@ -7,7 +7,7 @@ class ServiceSaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :create_job, :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, diff --git a/lib/netsuite/records/subtotal_item.rb b/lib/netsuite/records/subtotal_item.rb index 1932f4f03..d79aabb46 100644 --- a/lib/netsuite/records/subtotal_item.rb +++ b/lib/netsuite/records/subtotal_item.rb @@ -7,12 +7,12 @@ class DescriptionItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert fields :available_to_partners, :created_date, :description, :include_children, :is_inactive, :item_id, :last_modified_date record_refs :custom_form, :department, :issue_product, :klass, :location - + field :custom_field_list, CustomFieldList field :subsidiary_list, RecordRefList field :translations_list, TranslationList @@ -32,4 +32,3 @@ def self.search_class_name end end end - \ No newline at end of file From 7e3391e77575773880b2e7a97d703054ac960ec8 Mon Sep 17 00:00:00 2001 From: Fabien Sebban Date: Fri, 15 Apr 2022 16:44:18 +0200 Subject: [PATCH 096/114] add gross_amt field in cash refund item (#532) --- lib/netsuite/records/cash_refund_item.rb | 2 +- spec/netsuite/records/cash_refund_item_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/netsuite/records/cash_refund_item.rb b/lib/netsuite/records/cash_refund_item.rb index 76736f881..44b743158 100644 --- a/lib/netsuite/records/cash_refund_item.rb +++ b/lib/netsuite/records/cash_refund_item.rb @@ -6,7 +6,7 @@ class CashRefundItem include Support::Records include Namespaces::TranCust - fields :amount, :rate, :quantity, :is_taxable, :order_line, :line, :description + fields :amount, :gross_amt, :rate, :quantity, :is_taxable, :order_line, :line, :description field :custom_field_list, CustomFieldList record_refs :item, :klass, :price diff --git a/spec/netsuite/records/cash_refund_item_spec.rb b/spec/netsuite/records/cash_refund_item_spec.rb index 73f1a079a..b21d9db50 100644 --- a/spec/netsuite/records/cash_refund_item_spec.rb +++ b/spec/netsuite/records/cash_refund_item_spec.rb @@ -5,7 +5,7 @@ it 'has all the right fields' do [ - :amount + :amount, :gross_amt, :rate, :quantity, :is_taxable, :order_line, :line, :description ].each do |field| expect(item).to have_field(field) end From eb4b8e337aa5a0abfd6b23a4aca691dc8b682dd7 Mon Sep 17 00:00:00 2001 From: dbecker-stripe <88861694+dbecker-stripe@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:49:01 -0700 Subject: [PATCH 097/114] Remove monkey patched `lower_camelcase` method on String (#533) Our company enforces that we do not depend on gems that monkey patch core Ruby classes. To enable us to depend on this gem, this change moves the `lower_camelcase` to be a static method on a new utility class `NetSuite::Utilities::Strings`. There are many places where `lower_camelcase` is used to generate a `record_type` so this change consolidates the logic in `NetSuite::Support::Records` and uses it where a record type is expected. --- lib/netsuite.rb | 2 +- lib/netsuite/actions/delete.rb | 2 +- lib/netsuite/actions/delete_list.rb | 2 +- lib/netsuite/actions/get.rb | 2 +- lib/netsuite/actions/get_deleted.rb | 2 +- lib/netsuite/actions/get_list.rb | 2 +- lib/netsuite/actions/initialize.rb | 4 ++-- lib/netsuite/actions/search.rb | 2 +- .../core_ext/string/lower_camelcase.rb | 9 --------- lib/netsuite/records/record_ref.rb | 2 +- lib/netsuite/support/records.rb | 19 ++++++++++++++----- lib/netsuite/support/sublist.rb | 2 +- lib/netsuite/utilities/strings.rb | 15 +++++++++++++++ 13 files changed, 40 insertions(+), 25 deletions(-) delete mode 100644 lib/netsuite/core_ext/string/lower_camelcase.rb create mode 100644 lib/netsuite/utilities/strings.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index 5c385c6b2..aa1f502c4 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -5,9 +5,9 @@ require 'netsuite/errors' require 'netsuite/utilities' require 'netsuite/utilities/data_center' +require 'netsuite/utilities/strings' require 'netsuite/rest/utilities/roles' require 'netsuite/rest/utilities/request' -require 'netsuite/core_ext/string/lower_camelcase' module NetSuite autoload :Configuration, 'netsuite/configuration' diff --git a/lib/netsuite/actions/delete.rb b/lib/netsuite/actions/delete.rb index d79aafb05..cabc58eb4 100644 --- a/lib/netsuite/actions/delete.rb +++ b/lib/netsuite/actions/delete.rb @@ -21,7 +21,7 @@ def request(credentials={}) end def soap_type - @object.class.to_s.split('::').last.lower_camelcase + NetSuite::Support::Records.netsuite_type(@object) end # diff --git a/lib/netsuite/actions/delete_list.rb b/lib/netsuite/actions/delete_list.rb index 36eb4ecfe..0b37a7ebb 100644 --- a/lib/netsuite/actions/delete_list.rb +++ b/lib/netsuite/actions/delete_list.rb @@ -40,7 +40,7 @@ def request_body } end else - type = @klass.to_s.split('::').last.lower_camelcase + type = NetSuite::Support::Records.netsuite_type(@klass) record_type = 'platformCore:RecordRef' list.map do |internal_id| diff --git a/lib/netsuite/actions/get.rb b/lib/netsuite/actions/get.rb index 6674ef0c9..1d442e093 100644 --- a/lib/netsuite/actions/get.rb +++ b/lib/netsuite/actions/get.rb @@ -21,7 +21,7 @@ def request(credentials={}) end def soap_type - @klass.to_s.split('::').last.lower_camelcase + NetSuite::Support::Records.netsuite_type(@klass) end # diff --git a/lib/netsuite/actions/get_deleted.rb b/lib/netsuite/actions/get_deleted.rb index c13b936d9..17d270de5 100644 --- a/lib/netsuite/actions/get_deleted.rb +++ b/lib/netsuite/actions/get_deleted.rb @@ -20,7 +20,7 @@ def request(credentials={}) end def soap_type - @object.class.to_s.split('::').last.lower_camelcase + NetSuite::Support::Records.netsuite_type(@object) end # diff --git a/lib/netsuite/actions/get_list.rb b/lib/netsuite/actions/get_list.rb index 2fc18105f..cb93b2111 100644 --- a/lib/netsuite/actions/get_list.rb +++ b/lib/netsuite/actions/get_list.rb @@ -33,7 +33,7 @@ def request_body } end else - type = @klass.to_s.split('::').last.lower_camelcase + type = NetSuite::Support::Records.netsuite_type(@klass) record_type = 'platformCore:RecordRef' list.map do |internal_id| diff --git a/lib/netsuite/actions/initialize.rb b/lib/netsuite/actions/initialize.rb index 8e5ab949c..40af41d4c 100644 --- a/lib/netsuite/actions/initialize.rb +++ b/lib/netsuite/actions/initialize.rb @@ -28,12 +28,12 @@ def request(credentials={}) def request_body { 'platformMsgs:initializeRecord' => { - 'platformCore:type' => @klass.to_s.split('::').last.lower_camelcase, + 'platformCore:type' => NetSuite::Support::Records.netsuite_type(@klass), 'platformCore:reference' => {}, :attributes! => { 'platformCore:reference' => { 'internalId' => @object.internal_id, - :type => @object.class.to_s.split('::').last.lower_camelcase + :type => NetSuite::Support::Records.netsuite_type(@object) } } } diff --git a/lib/netsuite/actions/search.rb b/lib/netsuite/actions/search.rb index 450313775..69adec43c 100644 --- a/lib/netsuite/actions/search.rb +++ b/lib/netsuite/actions/search.rb @@ -26,7 +26,7 @@ def request(credentials={}) .update(NetSuite::Configuration.soap_header) .merge( (@options.delete(:preferences) || {}).inject({'platformMsgs:SearchPreferences' => {}}) do |h, (k, v)| - h['platformMsgs:SearchPreferences'][k.to_s.lower_camelcase] = v + h['platformMsgs:SearchPreferences'][NetSuite::Utilities::Strings.lower_camelcase(k.to_s)] = v h end ) diff --git a/lib/netsuite/core_ext/string/lower_camelcase.rb b/lib/netsuite/core_ext/string/lower_camelcase.rb deleted file mode 100644 index 63a2e0adf..000000000 --- a/lib/netsuite/core_ext/string/lower_camelcase.rb +++ /dev/null @@ -1,9 +0,0 @@ -class String - def lower_camelcase - str = dup - str.gsub!(/\/(.?)/) { "::#{$1.upcase}" } - str.gsub!(/(?:_+|-+)([a-z]|[0-9])/) { $1.upcase } - str.gsub!(/(\A|\s)([A-Z])/) { $1 + $2.downcase } - str - end -end diff --git a/lib/netsuite/records/record_ref.rb b/lib/netsuite/records/record_ref.rb index f83bac8cd..1ada59644 100644 --- a/lib/netsuite/records/record_ref.rb +++ b/lib/netsuite/records/record_ref.rb @@ -21,7 +21,7 @@ def initialize(attributes_or_record = {}) record = attributes_or_record @internal_id = record.internal_id if record.respond_to?(:internal_id) @external_id = record.external_id if record.respond_to?(:external_id) - @type = record.class.to_s.split('::').last.lower_camelcase + @type = NetSuite::Support::Records.netsuite_type(record) end end diff --git a/lib/netsuite/support/records.rb b/lib/netsuite/support/records.rb index 917bd729b..43065247f 100644 --- a/lib/netsuite/support/records.rb +++ b/lib/netsuite/support/records.rb @@ -7,7 +7,7 @@ module Records def to_record attributes.reject { |k,v| self.class.read_only_fields.include?(k) || self.class.search_only_fields.include?(k) }.inject({}) do |hash, (k,v)| kname = "#{v.is_a?(NetSuite::Records::NullFieldList) ? v.record_namespace : record_namespace}:" - kname += k == :klass ? 'class' : k.to_s.lower_camelcase + kname += k == :klass ? 'class' : NetSuite::Utilities::Strings.lower_camelcase(k.to_s) to_attributes!(hash, kname, v) @@ -38,13 +38,13 @@ def to_attributes!(hash, kname, v) if v.kind_of?(NetSuite::Records::RecordRef) && v.type hash[:attributes!] ||= {} hash[:attributes!][kname] ||= {} - hash[:attributes!][kname]['type'] = v.type.lower_camelcase + hash[:attributes!][kname]['type'] = NetSuite::Utilities::Strings.lower_camelcase(v.type) end if v.kind_of?(NetSuite::Records::CustomRecordRef) && v.type_id hash[:attributes!] ||= {} hash[:attributes!][kname] ||= {} - hash[:attributes!][kname]['typeId'] = v.type_id.lower_camelcase + hash[:attributes!][kname]['typeId'] = NetSuite::Utilities::Strings.lower_camelcase(v.type_id) end end @@ -53,11 +53,11 @@ def record_type end def netsuite_type - record_type_without_namespace.lower_camelcase + Records.netsuite_type(self) end def record_type_without_namespace - "#{self.class.to_s.split('::').last}" + Records.record_type_without_namespace(self) end def refresh(credentials = {}) @@ -75,6 +75,15 @@ def refresh(credentials = {}) self end + def self.netsuite_type(obj) + NetSuite::Utilities::Strings.lower_camelcase(record_type_without_namespace(obj)) + end + + def self.record_type_without_namespace(obj) + klass = obj.is_a?(Class) ? obj : obj.class + "#{klass.to_s.split('::').last}" + end + end end end diff --git a/lib/netsuite/support/sublist.rb b/lib/netsuite/support/sublist.rb index 4266f09d1..60ccf1cc5 100644 --- a/lib/netsuite/support/sublist.rb +++ b/lib/netsuite/support/sublist.rb @@ -35,7 +35,7 @@ def initialize(attributes = {}) end def to_record - rec = { "#{record_namespace}:#{sublist_key.to_s.lower_camelcase}" => send(self.sublist_key).map(&:to_record) } + rec = { "#{record_namespace}:#{NetSuite::Utilities::Strings.lower_camelcase(sublist_key.to_s)}" => send(self.sublist_key).map(&:to_record) } if !replace_all.nil? rec["#{record_namespace}:replaceAll"] = !!replace_all diff --git a/lib/netsuite/utilities/strings.rb b/lib/netsuite/utilities/strings.rb new file mode 100644 index 000000000..2aaeeeb46 --- /dev/null +++ b/lib/netsuite/utilities/strings.rb @@ -0,0 +1,15 @@ +module NetSuite + module Utilities + module Strings + class << self + def lower_camelcase(obj) + str = obj.is_a?(String) ? obj.dup : obj.to_s + str.gsub!(/\/(.?)/) { "::#{$1.upcase}" } + str.gsub!(/(?:_+|-+)([a-z]|[0-9])/) { $1.upcase } + str.gsub!(/(\A|\s)([A-Z])/) { $1 + $2.downcase } + str + end + end + end + end +end \ No newline at end of file From a2d0a3503f3df7d1dc849a57b88a94a510c845cf Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 19 Apr 2022 20:49:10 -0400 Subject: [PATCH 098/114] Add `get_deleted` action to Employee (#531) --- HISTORY.md | 1 + lib/netsuite/records/employee.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 592d97ab1..939f23ccf 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,7 @@ * Add NullFieldList record (to credit memos and invoices) (#529) * Add `get_deleted` action to item records (#530) +* Add `get_deleted` action to Employee records (#531) ### Fixed diff --git a/lib/netsuite/records/employee.rb b/lib/netsuite/records/employee.rb index 4df2f03d0..1cccd51e6 100644 --- a/lib/netsuite/records/employee.rb +++ b/lib/netsuite/records/employee.rb @@ -9,7 +9,7 @@ class Employee # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/script/record/employee.html - actions :get, :get_list, :add, :update, :upsert, :upsert_list, :delete, :search + actions :get, :get_deleted, :get_list, :add, :update, :upsert, :upsert_list, :delete, :search fields :alt_name, :phone, :first_name, :last_name, :is_inactive, :email, :give_access, :send_email, :is_support_rep, :birth_date, :hire_date, :last_review_date, :next_review_date, :title, :home_phone, :office_phone, From 261d3495f08534a765dc88eb9adc79742128100f Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 21 Apr 2022 15:10:30 -0600 Subject: [PATCH 099/114] Version bump --- HISTORY.md | 9 +++++++-- lib/netsuite/version.rb | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 939f23ccf..f16f7472a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,11 +2,16 @@ ### Added +### Fixed + +## 0.8.12 + +### Added + * Add NullFieldList record (to credit memos and invoices) (#529) * Add `get_deleted` action to item records (#530) * Add `get_deleted` action to Employee records (#531) - -### Fixed +* Remove monkey patched `lower_camelcase` method on String (#533) ## 0.8.11 diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index c88a0301c..ecf1526e5 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.11' + VERSION = '0.8.12' end From c429d17e9977ec7fa69f9975d63dbc9ea36f7fcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Apr 2022 09:10:30 -0600 Subject: [PATCH 100/114] Bump github/codeql-action from 1 to 2 (#534) --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c72628c14..efb59187e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +53,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +67,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From b64079bd94cea623a0823e4821c75c3421576eb8 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 5 May 2022 10:47:06 -0600 Subject: [PATCH 101/114] Adding payment option to customer refund --- lib/netsuite/records/customer_refund.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/customer_refund.rb b/lib/netsuite/records/customer_refund.rb index e96bcd9dc..8c768d3ab 100644 --- a/lib/netsuite/records/customer_refund.rb +++ b/lib/netsuite/records/customer_refund.rb @@ -20,7 +20,7 @@ class CustomerRefund read_only_fields :balance, :total record_refs :account, :ar_acct, :credit_card, :credit_card_processor, :custom_form, :customer, :department, :klass, - :location, :payment_method, :posting_period, :subsidiary, :void_journal, :currency + :location, :payment_method, :posting_period, :subsidiary, :void_journal, :currency, :payment_option attr_reader :internal_id attr_accessor :external_id From 9014cecb35a9613dfa4aca6ddb093cc7a8f7b9c2 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Sat, 7 May 2022 17:06:40 -0400 Subject: [PATCH 102/114] Update customer record (update fields, add search only fields) (#535) * Rename CustomerSubscriptionsList to SubscriptionsList and CustomerSubscription to Subscription At least as far back as 2014.1, NetSuite used these names, without the Customer prefix, so this aligns the gems naming with NetSuite. This would be a breaking change for anyone using the old name. * Update `Customer` record fields/record refs for 2021.2 The following were moved from `fields` to `record_refs`: - buying_reason - buying_time_frame - campaign_category - image - opening_balance_account - pref_cc_processor - representing_subsidiary - sales_group - sales_readiness The following were removed as `fields` since their sublist class is not yet implemented: - download_list - group_pricing_list - item_pricing_list I didn't update read-only fields as I don't trust NetSuite's documentation. They say `creditHoldOverride` is read-only, for example, but I can very clearly edit it. Therefore opting to leave this list as-is to avoid breaking changes. * Add search-only fields to `Customer` --- HISTORY.md | 7 + lib/netsuite.rb | 4 +- lib/netsuite/records/customer.rb | 246 ++++++++++++++-- .../records/customer_subscriptions_list.rb | 10 - ...stomer_subscription.rb => subscription.rb} | 2 +- lib/netsuite/records/subscriptions_list.rb | 10 + spec/netsuite/records/customer_spec.rb | 278 ++++++++++++++++-- ...scription_spec.rb => subscription_spec.rb} | 4 +- ...ist_spec.rb => subscriptions_list_spec.rb} | 4 +- 9 files changed, 506 insertions(+), 59 deletions(-) delete mode 100644 lib/netsuite/records/customer_subscriptions_list.rb rename lib/netsuite/records/{customer_subscription.rb => subscription.rb} (92%) create mode 100644 lib/netsuite/records/subscriptions_list.rb rename spec/netsuite/records/{customer_subscription_spec.rb => subscription_spec.rb} (89%) rename spec/netsuite/records/{customer_subscriptions_list_spec.rb => subscriptions_list_spec.rb} (72%) diff --git a/HISTORY.md b/HISTORY.md index f16f7472a..0df67442e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,9 +1,16 @@ ## Unreleased ### Added +* Update `Customer` record fields/record refs for 2021.2. (#535) +The following were moved from `fields` to `record_refs`: `buying_reason`, `buying_time_frame`, `campaign_category`, `image`, `opening_balance_account`, `pref_cc_processor`, `representing_subsidiary`, `sales_group`, `sales_readiness` +The following were removed as `fields` since their sublist class is not yet implemented: `download_list`, `group_pricing_list`, `item_pricing_list` +* Add search-only fields to `Customer` (#535) ### Fixed +### Breaking Changes +* Rename `CustomerSubscriptionsList` to `SubscriptionsList` and `CustomerSubscription` to `Subscription` to match NetSuite naming (#535) + ## 0.8.12 ### Added diff --git a/lib/netsuite.rb b/lib/netsuite.rb index aa1f502c4..dbe6b3eb1 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -133,8 +133,6 @@ module Records autoload :CustomerRefundApplyList, 'netsuite/records/customer_refund_apply_list' autoload :CustomerRefundDeposit, 'netsuite/records/customer_refund_deposit' autoload :CustomerRefundDepositList, 'netsuite/records/customer_refund_deposit_list' - autoload :CustomerSubscription, 'netsuite/records/customer_subscription' - autoload :CustomerSubscriptionsList, 'netsuite/records/customer_subscriptions_list' autoload :CustomerStatus, 'netsuite/records/customer_status' autoload :CustomerPartner, 'netsuite/records/customer_partner' autoload :CustomerSalesTeam, 'netsuite/records/customer_sales_team' @@ -271,6 +269,8 @@ module Records autoload :SerializedInventoryItemLocationsList, 'netsuite/records/serialized_inventory_item_locations_list' autoload :ShipAddress, 'netsuite/records/ship_address' autoload :SiteCategory, 'netsuite/records/site_category' + autoload :Subscription, 'netsuite/records/subscription' + autoload :SubscriptionsList, 'netsuite/records/subscriptions_list' autoload :Subsidiary, 'netsuite/records/subsidiary' autoload :SubtotalItem, 'netsuite/records/subtotal_item' autoload :SupportCase, 'netsuite/records/support_case' diff --git a/lib/netsuite/records/customer.rb b/lib/netsuite/records/customer.rb index 709b0b799..f3a1b3548 100644 --- a/lib/netsuite/records/customer.rb +++ b/lib/netsuite/records/customer.rb @@ -11,36 +11,238 @@ class Customer # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/customer.html - fields :account_number, :aging, :alt_email, :alt_name, :alt_phone, :bill_pay, - :buying_reason, :buying_time_frame, :campaign_category, :click_stream, :comments, :company_name, - :consol_aging, :consol_days_overdue, :contrib_pct, :credit_hold_override, - :credit_limit, :date_created, :days_overdue, :default_address, - :download_list, :email, :email_preference, :email_transactions, :end_date, :entity_id, - :estimated_budget, :fax, :fax_transactions, :first_name, :first_visit, :give_access, :global_subscription_status, - :group_pricing_list, :home_phone, :image, :is_budget_approved, :is_inactive, :is_person, :item_pricing_list, :keywords, - :language, :last_modified_date, :last_name, :last_page_visited, :last_visit, :middle_name, :mobile_phone, - :opening_balance, :opening_balance_account, :opening_balance_date, - :password, :password2, :phone, :phonetic_name, :pref_cc_processor, :print_on_check_as, - :print_transactions, :referrer, :reminder_days, :representing_subsidiary, :require_pwd_change, :resale_number, - :sales_group, :sales_readiness, :salutation, :send_email, :ship_complete, - :stage, :start_date, :sync_partner_teams, :tax_exempt, :taxable, - :third_party_acct, :third_party_country, :third_party_zipcode, :title, :url, - :vat_reg_number, :visits, :web_lead - - field :addressbook_list, CustomerAddressbookList - field :credit_cards_list, CustomerCreditCardsList - field :custom_field_list, CustomFieldList + fields :account_number, + :aging, + :aging1, + :aging2, + :aging3, + :aging4, + :alcohol_recipient_type, + :alt_email, + :alt_name, + :alt_phone, + :bill_pay, + :click_stream, + :comments, + :company_name, + :consol_aging, + :consol_aging1, + :consol_aging2, + :consol_aging3, + :consol_aging4, + :consol_days_overdue, + :contrib_pct, + :credit_hold_override, + :credit_limit, + :date_created, + :days_overdue, + :default_address, + :default_order_priority, + :display_symbol, + :email, + :email_preference, + :email_transactions, + :end_date, + :entity_id, + :estimated_budget, + :fax, + :fax_transactions, + :first_name, + :first_visit, + :give_access, + :global_subscription_status, + :home_phone, + :is_budget_approved, + :is_inactive, + :is_person, + :keywords, + :language, + :last_modified_date, + :last_name, + :last_page_visited, + :last_visit, + :middle_name, + :mobile_phone, + :monthly_closing, + :negative_number_format, + :number_format, + :opening_balance, + :opening_balance_date, + :override_currency_format, + :password, + :password2, + :phone, + :phonetic_name, + :print_on_check_as, + :print_transactions, + :referrer, + :reminder_days, + :require_pwd_change, + :resale_number, + :salutation, + :send_email, + :ship_complete, + :stage, + :start_date, + :symbol_placement, + :sync_partner_teams, + :taxable, + :tax_exempt, + :third_party_acct, + :third_party_country, + :third_party_zipcode, + :title, + :url, + :vat_reg_number, + :visits, + :web_lead + + field :addressbook_list, CustomerAddressbookList field :contact_roles_list, ContactAccessRolesList + field :credit_cards_list, CustomerCreditCardsList field :currency_list, CustomerCurrencyList + field :custom_field_list, CustomFieldList + # field :download_list, CustomerDownloadList # TODO Implement me + # field :group_pricing_list, CustomerGroupPricingList # TODO: Implement me + # field :item_pricing_list, CustomerItemPricingList # TODO: Implement me field :partners_list, CustomerPartnersList - field :subscriptions_list, CustomerSubscriptionsList field :sales_team_list, CustomerSalesTeamList + field :subscriptions_list, SubscriptionsList + # field :tax_registration_list, CustomerTaxRegistrationList # TODO: Implement me read_only_fields :balance, :consol_balance, :deposit_balance, :consol_deposit_balance, :overdue_balance, :consol_overdue_balance, :unbilled_orders, :consol_unbilled_orders - record_refs :access_role, :custom_form, :currency, :entity_status, :partner, :category, :lead_source, - :price_level, :sales_rep, :subsidiary, :terms, :parent, :territory, :tax_item, :shipping_item, :receivables_account + search_only_fields :address, + :address1, + :address2, + :address3, + :addressee, + :address_internal_id, + :address_label, + :address_phone, + :alt_contact, + :assigned_site, + :assigned_site_id, + :attention, + :available_offline, + :bill_address, + :bill_address1, + :bill_address2, + :bill_address3, + :bill_addressee, + :bill_attention, + :bill_city, + :bill_country, + :bill_country_code, + :bill_phone, + :bill_state, + :bill_zip_code, + :cc_customer_code, + :cc_default, + :cc_exp_date, + :cc_holder_name, + :cc_internal_id, + :cc_number, + :cc_state, + :cc_state_from, + :cc_type, + :city, + :contact, + :contribution, + :contribution_primary, + :conversion_date, + :country, + :country_code, + :credit_hold, + :date_closed, + :entity_number, + :explicit_conversion, + :first_order_date, + :first_sale_date, + :fx_balance, + :fx_consol_balance, + :fx_consol_unbilled_orders, + :fx_unbilled_orders, + :group_pricing_level, + :has_duplicates, + :is_default_billing, + :is_default_shipping, + :is_ship_address, + :item_pricing_level, + :item_pricing_unit_price, + :job_end_date, + :job_projected_end, + :job_start_date, + :job_type, + :last_order_date, + :last_sale_date, + :lead_date, + :level, + :manual_credit_hold, + :on_credit_hold, + :partner_contribution, + :partner_role, + :partner_team_member, + :pec, + :permission, + :pricing_group, + :pricing_item, + :prospect_date, + :role, + :sales_team_member, + :sales_team_role, + :ship_address, + :ship_address1, + :ship_address2, + :ship_address3, + :ship_addressee, + :ship_attention, + :ship_city, + :ship_country, + :ship_country_code, + :ship_phone, + :ship_state, + :ship_zip, + :source_site, + :source_site_id, + :state, + :subscription, + :subscription_date, + :subscription_status, + :zip_code + + record_refs :access_role, + :assigned_web_site, + :buying_reason, + :buying_time_frame, + :campaign_category, + :category, + :currency, + :custom_form, + :default_allocation_strategy, + :default_tax_reg, + :dr_account, + :entity_status, + :fx_account, + :image, + :lead_source, + :opening_balance_account, + :parent, + :partner, + :pref_cc_processor, + :price_level, + :receivables_account, + :representing_subsidiary, + :sales_group, + :sales_readiness, + :sales_rep, + :shipping_item, + :source_web_site, + :subsidiary, + :tax_item, + :terms, + :territory attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/customer_subscriptions_list.rb b/lib/netsuite/records/customer_subscriptions_list.rb deleted file mode 100644 index 1f1c727e9..000000000 --- a/lib/netsuite/records/customer_subscriptions_list.rb +++ /dev/null @@ -1,10 +0,0 @@ -module NetSuite - module Records - class CustomerSubscriptionsList < Support::Sublist - include Namespaces::ListRel - - sublist :subscriptions, CustomerSubscription - - end - end -end diff --git a/lib/netsuite/records/customer_subscription.rb b/lib/netsuite/records/subscription.rb similarity index 92% rename from lib/netsuite/records/customer_subscription.rb rename to lib/netsuite/records/subscription.rb index 07d254d3a..849c60b79 100644 --- a/lib/netsuite/records/customer_subscription.rb +++ b/lib/netsuite/records/subscription.rb @@ -1,6 +1,6 @@ module NetSuite module Records - class CustomerSubscription + class Subscription include Support::Fields include Support::Records include Support::RecordRefs diff --git a/lib/netsuite/records/subscriptions_list.rb b/lib/netsuite/records/subscriptions_list.rb new file mode 100644 index 000000000..7d25d4426 --- /dev/null +++ b/lib/netsuite/records/subscriptions_list.rb @@ -0,0 +1,10 @@ +module NetSuite + module Records + class SubscriptionsList < Support::Sublist + include Namespaces::ListRel + + sublist :subscriptions, Subscription + + end + end +end diff --git a/spec/netsuite/records/customer_spec.rb b/spec/netsuite/records/customer_spec.rb index 37c1add94..d03c5e24e 100644 --- a/spec/netsuite/records/customer_spec.rb +++ b/spec/netsuite/records/customer_spec.rb @@ -5,30 +5,268 @@ it 'has all the right fields' do [ - :account_number, :aging, :alt_email, :alt_name, :alt_phone, :balance, :bill_pay, - :buying_reason, :buying_time_frame, :campaign_category, :click_stream, :comments, :company_name, - :consol_aging, :consol_balance, :consol_days_overdue, :consol_deposit_balance, :consol_overdue_balance, - :consol_unbilled_orders, :contrib_pct, :credit_hold_override, :credit_limit, - :date_created, :days_overdue, :default_address, - :deposit_balance, :download_list, :email, :email_preference, :email_transactions, :end_date, :entity_id, - :estimated_budget, :fax, :fax_transactions, :first_name, :first_visit, :give_access, :global_subscription_status, - :group_pricing_list, :home_phone, :image, :is_budget_approved, :is_inactive, :is_person, :item_pricing_list, :keywords, - :language, :last_modified_date, :last_name, :last_page_visited, :last_visit, :middle_name, :mobile_phone, - :opening_balance, :opening_balance_account, :opening_balance_date, :overdue_balance, - :password, :password2, :phone, :phonetic_name, :pref_cc_processor,:print_on_check_as, - :print_transactions, :referrer, :reminder_days, :representing_subsidiary, :require_pwd_change, :resale_number, - :sales_group, :sales_readiness, :salutation, :send_email, :ship_complete, - :stage, :start_date, :sync_partner_teams, :tax_exempt, :taxable, - :third_party_acct, :third_party_country, :third_party_zipcode, :title, :unbilled_orders, :url, - :vat_reg_number, :visits, :web_lead + :account_number, + :aging, + :aging1, + :aging2, + :aging3, + :aging4, + :alcohol_recipient_type, + :alt_email, + :alt_name, + :alt_phone, + :bill_pay, + :click_stream, + :comments, + :company_name, + :consol_aging, + :consol_aging1, + :consol_aging2, + :consol_aging3, + :consol_aging4, + :consol_days_overdue, + :contrib_pct, + :credit_hold_override, + :credit_limit, + :date_created, + :days_overdue, + :default_address, + :default_order_priority, + :display_symbol, + :email, + :email_preference, + :email_transactions, + :end_date, + :entity_id, + :estimated_budget, + :fax, + :fax_transactions, + :first_name, + :first_visit, + :give_access, + :global_subscription_status, + :home_phone, + :is_budget_approved, + :is_inactive, + :is_person, + :keywords, + :language, + :last_modified_date, + :last_name, + :last_page_visited, + :last_visit, + :middle_name, + :mobile_phone, + :monthly_closing, + :negative_number_format, + :number_format, + :opening_balance, + :opening_balance_date, + :override_currency_format, + :password, + :password2, + :phone, + :phonetic_name, + :print_on_check_as, + :print_transactions, + :referrer, + :reminder_days, + :require_pwd_change, + :resale_number, + :salutation, + :send_email, + :ship_complete, + :stage, + :start_date, + :symbol_placement, + :sync_partner_teams, + :taxable, + :tax_exempt, + :third_party_acct, + :third_party_country, + :third_party_zipcode, + :title, + :url, + :vat_reg_number, + :visits, + :web_lead, ].each do |field| expect(customer).to have_field(field) end end + it 'has all the right fields with specific classes' do + { + addressbook_list: NetSuite::Records::CustomerAddressbookList, + contact_roles_list: NetSuite::Records::ContactAccessRolesList, + credit_cards_list: NetSuite::Records::CustomerCreditCardsList, + currency_list: NetSuite::Records::CustomerCurrencyList, + custom_field_list: NetSuite::Records::CustomFieldList, + # download_list: NetSuite::Records::CustomerDownloadList, # TODO Implement me + # group_pricing_list: NetSuite::Records::CustomerGroupPricingList, # TODO: Implement me + # item_pricing_list: NetSuite::Records::CustomerItemPricingList, # TODO: Implement me + partners_list: NetSuite::Records::CustomerPartnersList, + sales_team_list: NetSuite::Records::CustomerSalesTeamList, + subscriptions_list: NetSuite::Records::SubscriptionsList, + # tax_registration_list: NetSuite::Records::CustomerTaxRegistrationList, # TODO: Implement me + }.each do |field, klass| + expect(customer).to have_field(field, klass) + end + end + + it 'has all the right read_only_fields' do + [ + :balance, + :consol_balance, + :deposit_balance, + :consol_deposit_balance, + :overdue_balance, + :consol_overdue_balance, + :unbilled_orders, + :consol_unbilled_orders, + ].each do |field| + expect(NetSuite::Records::Customer).to have_read_only_field(field) + end + end + + it 'has all the right search_only_fields' do + [ + :address, + :address1, + :address2, + :address3, + :addressee, + :address_internal_id, + :address_label, + :address_phone, + :alt_contact, + :assigned_site, + :assigned_site_id, + :attention, + :available_offline, + :bill_address, + :bill_address1, + :bill_address2, + :bill_address3, + :bill_addressee, + :bill_attention, + :bill_city, + :bill_country, + :bill_country_code, + :bill_phone, + :bill_state, + :bill_zip_code, + :cc_customer_code, + :cc_default, + :cc_exp_date, + :cc_holder_name, + :cc_internal_id, + :cc_number, + :cc_state, + :cc_state_from, + :cc_type, + :city, + :contact, + :contribution, + :contribution_primary, + :conversion_date, + :country, + :country_code, + :credit_hold, + :date_closed, + :entity_number, + :explicit_conversion, + :first_order_date, + :first_sale_date, + :fx_balance, + :fx_consol_balance, + :fx_consol_unbilled_orders, + :fx_unbilled_orders, + :group_pricing_level, + :has_duplicates, + :is_default_billing, + :is_default_shipping, + :is_ship_address, + :item_pricing_level, + :item_pricing_unit_price, + :job_end_date, + :job_projected_end, + :job_start_date, + :job_type, + :last_order_date, + :last_sale_date, + :lead_date, + :level, + :manual_credit_hold, + :on_credit_hold, + :partner_contribution, + :partner_role, + :partner_team_member, + :pec, + :permission, + :pricing_group, + :pricing_item, + :prospect_date, + :role, + :sales_team_member, + :sales_team_role, + :ship_address, + :ship_address1, + :ship_address2, + :ship_address3, + :ship_addressee, + :ship_attention, + :ship_city, + :ship_country, + :ship_country_code, + :ship_phone, + :ship_state, + :ship_zip, + :source_site, + :source_site_id, + :state, + :subscription, + :subscription_date, + :subscription_status, + :zip_code, + ].each do |field| + expect(NetSuite::Records::Customer).to have_search_only_field(field) + end + end + it 'has the right record_refs' do [ - :access_role, :currency, :custom_form, :entity_status, :partner, :sales_rep, :terms, :parent, :territory, :shipping_item, :tax_item + :access_role, + :assigned_web_site, + :buying_reason, + :buying_time_frame, + :campaign_category, + :category, + :currency, + :custom_form, + :default_allocation_strategy, + :default_tax_reg, + :dr_account, + :entity_status, + :fx_account, + :image, + :lead_source, + :opening_balance_account, + :parent, + :partner, + :pref_cc_processor, + :price_level, + :receivables_account, + :representing_subsidiary, + :sales_group, + :sales_readiness, + :sales_rep, + :shipping_item, + :source_web_site, + :subsidiary, + :tax_item, + :terms, + :territory, ].each do |record_ref| expect(customer).to have_record_ref(record_ref) end @@ -115,12 +353,12 @@ } ] } - expect(customer.subscriptions_list).to be_kind_of(NetSuite::Records::CustomerSubscriptionsList) + expect(customer.subscriptions_list).to be_kind_of(NetSuite::Records::SubscriptionsList) expect(customer.subscriptions_list.subscriptions.length).to eql(1) end - it 'can be set from a CustomerSubscriptionsList object' do - customer_subscriptions_list = NetSuite::Records::CustomerSubscriptionsList.new + it 'can be set from a SubscriptionsList object' do + customer_subscriptions_list = NetSuite::Records::SubscriptionsList.new customer.subscriptions_list = customer_subscriptions_list expect(customer.subscriptions_list).to eql(customer_subscriptions_list) end diff --git a/spec/netsuite/records/customer_subscription_spec.rb b/spec/netsuite/records/subscription_spec.rb similarity index 89% rename from spec/netsuite/records/customer_subscription_spec.rb rename to spec/netsuite/records/subscription_spec.rb index fecbdb8a2..8dc326ae1 100644 --- a/spec/netsuite/records/customer_subscription_spec.rb +++ b/spec/netsuite/records/subscription_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NetSuite::Records::CustomerSubscription do +describe NetSuite::Records::Subscription do before do NetSuite::Configuration.api_version = '2014_2' @@ -16,7 +16,7 @@ } end - let(:list) { NetSuite::Records::CustomerSubscription.new(attributes) } + let(:list) { NetSuite::Records::Subscription.new(attributes) } it 'has all the right fields' do [ diff --git a/spec/netsuite/records/customer_subscriptions_list_spec.rb b/spec/netsuite/records/subscriptions_list_spec.rb similarity index 72% rename from spec/netsuite/records/customer_subscriptions_list_spec.rb rename to spec/netsuite/records/subscriptions_list_spec.rb index 12457faab..81a20871e 100644 --- a/spec/netsuite/records/customer_subscriptions_list_spec.rb +++ b/spec/netsuite/records/subscriptions_list_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe NetSuite::Records::CustomerSubscriptionsList do - let(:list) { NetSuite::Records::CustomerSubscriptionsList.new } +describe NetSuite::Records::SubscriptionsList do + let(:list) { NetSuite::Records::SubscriptionsList.new } it 'has a subscriptions attribute' do expect(list.subscriptions).to be_kind_of(Array) From 74ff67ce7d29196c57907c9f55fa6f992125aeb4 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Wed, 11 May 2022 22:11:54 +0200 Subject: [PATCH 103/114] Add ship_group attribute to SalesOrderItem (#536) * Add ship_group * Add spec for ship_group field --- lib/netsuite/records/sales_order_item.rb | 3 ++- spec/netsuite/records/sales_order_item_spec.rb | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/netsuite/records/sales_order_item.rb b/lib/netsuite/records/sales_order_item.rb index 0b659a5ea..2a8a09c11 100644 --- a/lib/netsuite/records/sales_order_item.rb +++ b/lib/netsuite/records/sales_order_item.rb @@ -17,7 +17,8 @@ class SalesOrderItem :rev_rec_start_date, :rev_rec_term_in_months, :serial_numbers, :shipping_cost, :tax1_amt, :tax_rate1, :tax_rate2, :vsoe_allocation, :vsoe_amount, :vsoe_deferral, - :vsoe_delivered, :vsoe_permit_discount, :vsoe_price + :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, + :ship_group field :custom_field_list, CustomFieldList diff --git a/spec/netsuite/records/sales_order_item_spec.rb b/spec/netsuite/records/sales_order_item_spec.rb index 59d4266e7..34981921d 100644 --- a/spec/netsuite/records/sales_order_item_spec.rb +++ b/spec/netsuite/records/sales_order_item_spec.rb @@ -13,9 +13,10 @@ :quantity, :quantity_back_ordered, :quantity_billed, :quantity_committed, :quantity_fulfilled, :rate, :rev_rec_end_date, :rev_rec_start_date, - :rev_rec_term_in_months, :serial_numbers, :tax1_amt, :tax_rate1, - :tax_rate2, :vsoe_allocation, :vsoe_amount, :vsoe_deferral, - :vsoe_delivered, :vsoe_permit_discount, :vsoe_price + :rev_rec_term_in_months, :serial_numbers, :ship_group, + :tax1_amt, :tax_rate1, :tax_rate2, + :vsoe_allocation, :vsoe_amount, :vsoe_deferral, + :vsoe_delivered, :vsoe_permit_discount, :vsoe_price, ].each do |field| expect(item).to have_field(field) end From 86c01547e38812810373417586ed71ab00186961 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Tue, 17 May 2022 14:04:45 +0200 Subject: [PATCH 104/114] Add ItemAvailability (#538) * Add ItemAvailability * Add basic specs to ItemAvailability --- lib/netsuite.rb | 1 + lib/netsuite/records/item_availability.rb | 24 ++++++++++++++++++ .../records/item_availability_spec.rb | 25 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 lib/netsuite/records/item_availability.rb create mode 100644 spec/netsuite/records/item_availability_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index dbe6b3eb1..c8b2b73ff 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -191,6 +191,7 @@ module Records autoload :Invoice, 'netsuite/records/invoice' autoload :InvoiceItem, 'netsuite/records/invoice_item' autoload :InvoiceItemList, 'netsuite/records/invoice_item_list' + autoload :ItemAvailability, 'netsuite/records/item_availability' 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_availability.rb b/lib/netsuite/records/item_availability.rb new file mode 100644 index 000000000..b3f1275bb --- /dev/null +++ b/lib/netsuite/records/item_availability.rb @@ -0,0 +1,24 @@ +module NetSuite + module Records + class ItemAvailability + include Support::Fields + include Support::RecordRefs + include Support::Records + + field :item, InventoryItem + field :location_id, Location + alias_method :location, :location_id + + field :quantity_on_hand + field :on_hand_value_mli + field :reorder_point + field :quantity_on_order + field :quantity_committed + field :quantity_available + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + end + end +end diff --git a/spec/netsuite/records/item_availability_spec.rb b/spec/netsuite/records/item_availability_spec.rb new file mode 100644 index 000000000..1def12d13 --- /dev/null +++ b/spec/netsuite/records/item_availability_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +module NetSuite + module Records + describe ItemAvailability do + let(:item_availability) { NetSuite::Records::ItemAvailability.new } + + it 'has all the right fields' do + [ + :quantity_on_hand, + :on_hand_value_mli, + :reorder_point, + :quantity_on_order, + :quantity_committed, + :quantity_available, + ].each do |field| + expect(item_availability).to have_field(field) + end + end + + it { expect(item_availability).to have_field(:item, InventoryItem) } + it { expect(item_availability).to have_field(:location_id, Location) } + end + end +end From 3c4410c6ef326970aec62af08860d2ea7288fd4f Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Tue, 17 May 2022 14:05:03 +0200 Subject: [PATCH 105/114] Add fedex/usps/ups package types (#537) Co-authored-by: Karl Falconer --- lib/netsuite.rb | 6 ++++ lib/netsuite/records/item_fulfillment.rb | 3 ++ .../item_fulfillment_package_fed_ex.rb | 28 ++++++++++++++++ .../item_fulfillment_package_fed_ex_list.rb | 32 +++++++++++++++++++ .../records/item_fulfillment_package_ups.rb | 27 ++++++++++++++++ .../item_fulfillment_package_ups_list.rb | 32 +++++++++++++++++++ .../records/item_fulfillment_package_usps.rb | 26 +++++++++++++++ .../item_fulfillment_package_usps_list.rb | 32 +++++++++++++++++++ ...em_fulfillment_package_fed_ex_list_spec.rb | 27 ++++++++++++++++ .../item_fulfillment_package_ups_list_spec.rb | 27 ++++++++++++++++ ...item_fulfillment_package_usps_list_spec.rb | 27 ++++++++++++++++ 11 files changed, 267 insertions(+) create mode 100644 lib/netsuite/records/item_fulfillment_package_fed_ex.rb create mode 100644 lib/netsuite/records/item_fulfillment_package_fed_ex_list.rb create mode 100644 lib/netsuite/records/item_fulfillment_package_ups.rb create mode 100644 lib/netsuite/records/item_fulfillment_package_ups_list.rb create mode 100644 lib/netsuite/records/item_fulfillment_package_usps.rb create mode 100644 lib/netsuite/records/item_fulfillment_package_usps_list.rb create mode 100644 spec/netsuite/records/item_fulfillment_package_fed_ex_list_spec.rb create mode 100644 spec/netsuite/records/item_fulfillment_package_ups_list_spec.rb create mode 100644 spec/netsuite/records/item_fulfillment_package_usps_list_spec.rb diff --git a/lib/netsuite.rb b/lib/netsuite.rb index c8b2b73ff..baff263f0 100644 --- a/lib/netsuite.rb +++ b/lib/netsuite.rb @@ -197,6 +197,12 @@ 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 :ItemFulfillmentPackageFedEx, 'netsuite/records/item_fulfillment_package_fed_ex' + autoload :ItemFulfillmentPackageUps, 'netsuite/records/item_fulfillment_package_ups' + autoload :ItemFulfillmentPackageUsps, 'netsuite/records/item_fulfillment_package_usps' + autoload :ItemFulfillmentPackageFedExList, 'netsuite/records/item_fulfillment_package_fed_ex_list' + autoload :ItemFulfillmentPackageUpsList, 'netsuite/records/item_fulfillment_package_ups_list' + autoload :ItemFulfillmentPackageUspsList, 'netsuite/records/item_fulfillment_package_usps_list' 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_fulfillment.rb b/lib/netsuite/records/item_fulfillment.rb index b903c7f23..ed9265afd 100644 --- a/lib/netsuite/records/item_fulfillment.rb +++ b/lib/netsuite/records/item_fulfillment.rb @@ -26,6 +26,9 @@ class ItemFulfillment field :item_list, ItemFulfillmentItemList field :package_list, ItemFulfillmentPackageList + field :package_fed_ex_list, ItemFulfillmentPackageFedExList + field :package_ups_list, ItemFulfillmentPackageUpsList + field :package_usps_list, ItemFulfillmentPackageUspsList field :custom_field_list, CustomFieldList attr_reader :internal_id diff --git a/lib/netsuite/records/item_fulfillment_package_fed_ex.rb b/lib/netsuite/records/item_fulfillment_package_fed_ex.rb new file mode 100644 index 000000000..48e8f1446 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_fed_ex.rb @@ -0,0 +1,28 @@ +module NetSuite + module Records + class ItemFulfillmentPackageFedEx + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :authorization_number_fed_ex, :cod_amount_fed_ex, :dry_ice_weight_fed_ex, :insured_value_fed_ex, :is_alcohol_fed_ex, + :is_non_haz_lithium_fed_ex, :is_non_standard_container_fed_ex, :package_height_fed_ex, :package_length_fed_ex, + :package_tracking_number_fed_ex, :package_weight_fed_ex, :package_width_fed_ex, :priority_alert_content_fed_ex, + :reference1_fed_ex, :signature_releasefed_ex, :use_cod_fed_ex, :use_insured_value_fed_ex + + + 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/item_fulfillment_package_fed_ex_list.rb b/lib/netsuite/records/item_fulfillment_package_fed_ex_list.rb new file mode 100644 index 000000000..070f97b13 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_fed_ex_list.rb @@ -0,0 +1,32 @@ +module NetSuite + module Records + class ItemFulfillmentPackageFedExList + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :package_fed_ex + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + + def package_fed_ex=(packages) + case packages + when Hash + self.packages << ItemFulfillmentPackageFedEx.new(packages) + when Array + packages.each { |package| self.packages << ItemFulfillmentPackageFedEx.new(package) } + end + end + + def packages + @packages ||= [] + end + + def to_record + { "#{record_namespace}:packageFedEx" => packages.map(&:to_record) } + end + end + end +end diff --git a/lib/netsuite/records/item_fulfillment_package_ups.rb b/lib/netsuite/records/item_fulfillment_package_ups.rb new file mode 100644 index 000000000..235292080 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_ups.rb @@ -0,0 +1,27 @@ +module NetSuite + module Records + class ItemFulfillmentPackageUps + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :additional_handling_ups, :cod_amount_ups, :cod_method_ups, :delivery_conf_ups, :insured_value_ups, :package_descr_ups, + :package_height_ups, :package_length_ups, :package_tracking_number_ups, :package_weight_ups, :package_width_ups, + :packaging_ups, :reference1_ups, :reference2_ups, :use_cod_ups + + + 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/item_fulfillment_package_ups_list.rb b/lib/netsuite/records/item_fulfillment_package_ups_list.rb new file mode 100644 index 000000000..22b0455d4 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_ups_list.rb @@ -0,0 +1,32 @@ +module NetSuite + module Records + class ItemFulfillmentPackageUpsList + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :package_ups + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + + def package_ups=(packages) + case packages + when Hash + self.packages << ItemFulfillmentPackageUps.new(packages) + when Array + packages.each { |package| self.packages << ItemFulfillmentPackageUps.new(package) } + end + end + + def packages + @packages ||= [] + end + + def to_record + { "#{record_namespace}:packageUps" => packages.map(&:to_record) } + end + end + end +end diff --git a/lib/netsuite/records/item_fulfillment_package_usps.rb b/lib/netsuite/records/item_fulfillment_package_usps.rb new file mode 100644 index 000000000..e8df42da1 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_usps.rb @@ -0,0 +1,26 @@ +module NetSuite + module Records + class ItemFulfillmentPackageUsps + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :insured_value_usps, :package_descr_usps, :package_height_usps, :package_length_usps, + :package_tracking_number_usps, :package_weight_usps, :package_width_usps, :reference1_usps, :reference2_usps, :use_insured_value_usps + + + 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/item_fulfillment_package_usps_list.rb b/lib/netsuite/records/item_fulfillment_package_usps_list.rb new file mode 100644 index 000000000..0daa01622 --- /dev/null +++ b/lib/netsuite/records/item_fulfillment_package_usps_list.rb @@ -0,0 +1,32 @@ +module NetSuite + module Records + class ItemFulfillmentPackageUspsList + include Support::Fields + include Support::Records + include Namespaces::TranSales + + fields :package_usps + + def initialize(attributes = {}) + initialize_from_attributes_hash(attributes) + end + + def package_usps=(packages) + case packages + when Hash + self.packages << ItemFulfillmentPackageUsps.new(packages) + when Array + packages.each { |package| self.packages << ItemFulfillmentPackageUsps.new(package) } + end + end + + def packages + @packages ||= [] + end + + def to_record + { "#{record_namespace}:packageUsps" => packages.map(&:to_record) } + end + end + end +end diff --git a/spec/netsuite/records/item_fulfillment_package_fed_ex_list_spec.rb b/spec/netsuite/records/item_fulfillment_package_fed_ex_list_spec.rb new file mode 100644 index 000000000..165ac3dae --- /dev/null +++ b/spec/netsuite/records/item_fulfillment_package_fed_ex_list_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe NetSuite::Records::ItemFulfillmentPackageFedExList do + let(:list) { NetSuite::Records::ItemFulfillmentPackageFedExList.new } + + it 'has a packages attribute' do + expect(list.packages).to be_kind_of(Array) + end + + describe '#to_record' do + before do + list.packages << NetSuite::Records::ItemFulfillmentPackageFedEx.new( + :package_tracking_number_fed_ex => '1Z12354645757686786' + ) + end + + it 'can represent itself as a SOAP record' do + record = { + 'tranSales:packageFedEx' => [ + 'tranSales:packageTrackingNumberFedEx' => '1Z12354645757686786' + ] + } + + expect(list.to_record).to eql(record) + end + end +end diff --git a/spec/netsuite/records/item_fulfillment_package_ups_list_spec.rb b/spec/netsuite/records/item_fulfillment_package_ups_list_spec.rb new file mode 100644 index 000000000..d98473551 --- /dev/null +++ b/spec/netsuite/records/item_fulfillment_package_ups_list_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe NetSuite::Records::ItemFulfillmentPackageUpsList do + let(:list) { NetSuite::Records::ItemFulfillmentPackageUpsList.new } + + it 'has a packages attribute' do + expect(list.packages).to be_kind_of(Array) + end + + describe '#to_record' do + before do + list.packages << NetSuite::Records::ItemFulfillmentPackageUps.new( + :package_tracking_number_ups => '1Z12354645757686786' + ) + end + + it 'can represent itself as a SOAP record' do + record = { + 'tranSales:packageUps' => [ + 'tranSales:packageTrackingNumberUps' => '1Z12354645757686786' + ] + } + + expect(list.to_record).to eql(record) + end + end +end diff --git a/spec/netsuite/records/item_fulfillment_package_usps_list_spec.rb b/spec/netsuite/records/item_fulfillment_package_usps_list_spec.rb new file mode 100644 index 000000000..1a9516cbd --- /dev/null +++ b/spec/netsuite/records/item_fulfillment_package_usps_list_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe NetSuite::Records::ItemFulfillmentPackageUspsList do + let(:list) { NetSuite::Records::ItemFulfillmentPackageUspsList.new } + + it 'has a packages attribute' do + expect(list.packages).to be_kind_of(Array) + end + + describe '#to_record' do + before do + list.packages << NetSuite::Records::ItemFulfillmentPackageUsps.new( + :package_tracking_number_usps => '1Z12354645757686786' + ) + end + + it 'can represent itself as a SOAP record' do + record = { + 'tranSales:packageUsps' => [ + 'tranSales:packageTrackingNumberUsps' => '1Z12354645757686786' + ] + } + + expect(list.to_record).to eql(record) + end + end +end From 71350e0db3f182fba272682dc7c0fb161d403d51 Mon Sep 17 00:00:00 2001 From: Fabien Sebban Date: Wed, 18 May 2022 18:48:47 +0200 Subject: [PATCH 106/114] translation list to assembly_item (#540) --- lib/netsuite/records/assembly_item.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/records/assembly_item.rb b/lib/netsuite/records/assembly_item.rb index 4b1743f1d..5ff5e37ac 100644 --- a/lib/netsuite/records/assembly_item.rb +++ b/lib/netsuite/records/assembly_item.rb @@ -47,6 +47,7 @@ class AssemblyItem field :pricing_matrix, PricingMatrix field :member_list, MemberList field :subsidiary_list, RecordRefList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id From fbddd026afd11374f15168e6d3be413bd2a39f05 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Sat, 21 May 2022 15:48:55 +0200 Subject: [PATCH 107/114] Add get_item_availability operation (#539) --- lib/netsuite/records/item_availability.rb | 22 ++++++ .../records/item_availability_spec.rb | 70 ++++++++++++++----- .../get_item_availability.xml | 46 ++++++++++++ 3 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 spec/support/fixtures/get_item_availability/get_item_availability.xml diff --git a/lib/netsuite/records/item_availability.rb b/lib/netsuite/records/item_availability.rb index b3f1275bb..ea9cb542f 100644 --- a/lib/netsuite/records/item_availability.rb +++ b/lib/netsuite/records/item_availability.rb @@ -16,6 +16,28 @@ class ItemAvailability field :quantity_committed field :quantity_available + def self.get_item_availability(ref_list, credentials={}) + connection = NetSuite::Configuration.connection({}, credentials) + response = connection.call :get_item_availability, message: { + "platformMsgs:itemAvailabilityFilter" => { + "platformCore:item" => ref_list.to_record + } + } + return false unless response.success? + + result = response.body[:get_item_availability_response][:get_item_availability_result] + unless result[:status][:@is_success] == "true" + return false + end + if result[:item_availability_list] + result[:item_availability_list][:item_availability].map do |row| + NetSuite::Records::ItemAvailability.new(row) + end + else + [] + end + end + def initialize(attributes = {}) initialize_from_attributes_hash(attributes) end diff --git a/spec/netsuite/records/item_availability_spec.rb b/spec/netsuite/records/item_availability_spec.rb index 1def12d13..d91beecec 100644 --- a/spec/netsuite/records/item_availability_spec.rb +++ b/spec/netsuite/records/item_availability_spec.rb @@ -1,25 +1,59 @@ require 'spec_helper' -module NetSuite - module Records - describe ItemAvailability do - let(:item_availability) { NetSuite::Records::ItemAvailability.new } +describe NetSuite::Records::ItemAvailability do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } - it 'has all the right fields' do - [ - :quantity_on_hand, - :on_hand_value_mli, - :reorder_point, - :quantity_on_order, - :quantity_committed, - :quantity_available, - ].each do |field| - expect(item_availability).to have_field(field) - end - end + let(:item_availability) { NetSuite::Records::ItemAvailability.new } - it { expect(item_availability).to have_field(:item, InventoryItem) } - it { expect(item_availability).to have_field(:location_id, Location) } + it 'has all the right fields' do + [ + :quantity_on_hand, + :on_hand_value_mli, + :reorder_point, + :quantity_on_order, + :quantity_committed, + :quantity_available, + ].each do |field| + expect(item_availability).to have_field(field) + end + end + + it { expect(item_availability).to have_field(:item, NetSuite::Records::InventoryItem) } + it { expect(item_availability).to have_field(:location_id, NetSuite::Records::Location) } + + describe 'get_item_availability' do + let(:inventory_item_ref_list) { + NetSuite::Records::RecordRefList.new( + record_ref: [ + NetSuite::Records::RecordRef.new(internal_id: 57) + ] + ) + } + let(:result) { NetSuite::Records::ItemAvailability.get_item_availability(inventory_item_ref_list) } + + before do + savon.expects(:get_item_availability).with(:message => { + "platformMsgs:itemAvailabilityFilter" => { + "platformCore:item"=>{"platformCore:recordRef"=>[{:@internalId=>57}]} + } + }).returns(File.read('spec/support/fixtures/get_item_availability/get_item_availability.xml')) + end + + it 'returns ItemAvailability records' do + expect(result).to be_kind_of(Array) + expect(result).not_to be_empty + expect(result[0]).to be_kind_of(NetSuite::Records::ItemAvailability) + expect(result[0]).to have_attributes( + item: be_kind_of(NetSuite::Records::InventoryItem), + location_id: NetSuite::Records::Location, + quantity_on_hand: '264.0', + on_hand_value_mli: '129.36', + reorder_point: '50.0', + quantity_on_order: '0.0', + quantity_committed: '0.0', + quantity_available: '264.0', + ) end end end diff --git a/spec/support/fixtures/get_item_availability/get_item_availability.xml b/spec/support/fixtures/get_item_availability/get_item_availability.xml new file mode 100644 index 000000000..b20136d87 --- /dev/null +++ b/spec/support/fixtures/get_item_availability/get_item_availability.xml @@ -0,0 +1,46 @@ + + + + WEBSERVICES_3868171_122020162073815481885806769_24761121647f + + + + + + + + + + CD-R + + 2022-05-05T03:40:06.000-07:00 + + Warehouse - East Coast + + 264.0 + 129.36 + 50.0 + 0.0 + 0.0 + 264.0 + + + + CD-R + + 2020-04-27T08:38:20.000-07:00 + + Warehouse - West Coast + + -1.0 + 0.0 + 50.0 + 0.0 + 0.0 + 0.0 + + + + + + From 64e36ed726a0ce0ef8f549fc0e40492fba20f332 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Mon, 23 May 2022 15:40:02 +0200 Subject: [PATCH 108/114] Add ItemGroup type to get_item utility (#542) --- lib/netsuite/utilities.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netsuite/utilities.rb b/lib/netsuite/utilities.rb index 7708857cd..b0cc1c982 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -177,6 +177,7 @@ def get_item(ns_item_internal_id, opts = {}) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::ServiceResaleItem, 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) + ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::ItemGroup, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedInventoryItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::SerializedAssemblyItem, ns_item_internal_id, opts) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedAssemblyItem, ns_item_internal_id, opts) From 998673d22d7f48aa35170532474157a0b186d637 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Mon, 23 May 2022 15:40:52 +0200 Subject: [PATCH 109/114] Add created_from_ship_group field to ItemFulfillment (#541) --- lib/netsuite/records/item_fulfillment.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netsuite/records/item_fulfillment.rb b/lib/netsuite/records/item_fulfillment.rb index ed9265afd..53e9e2877 100644 --- a/lib/netsuite/records/item_fulfillment.rb +++ b/lib/netsuite/records/item_fulfillment.rb @@ -9,7 +9,7 @@ class ItemFulfillment actions :get, :get_list, :add, :initialize, :update, :delete, :search, :upsert, :upsert_list - fields :tran_date, :tran_id, :shipping_cost, :memo, :ship_company, :ship_attention, :ship_addr1, + fields :created_from_ship_group, :tran_date, :tran_id, :shipping_cost, :memo, :ship_company, :ship_attention, :ship_addr1, :ship_addr2, :ship_city, :ship_state, :ship_zip, :ship_phone, :ship_is_residential, :ship_status, :last_modified_date, :created_date, :status From a3cd17c4bbaa7f6f8ba6ba709f9a11a6ee78c152 Mon Sep 17 00:00:00 2001 From: Wojtek Kruszewski Date: Thu, 26 May 2022 14:10:33 +0200 Subject: [PATCH 110/114] Handle empty result in get_select_value (#543) * Add basic spec for get_select_value * Reproduce an exception with empty result * Initialize an empty sublist from nil --- lib/netsuite/support/sublist.rb | 2 +- .../netsuite/actions/get_select_value_spec.rb | 43 +++++++++++++++++++ .../get_select_value/empty_result.xml | 22 ++++++++++ .../item_fulfillment_ship_method.xml | 43 +++++++++++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 spec/netsuite/actions/get_select_value_spec.rb create mode 100644 spec/support/fixtures/get_select_value/empty_result.xml create mode 100644 spec/support/fixtures/get_select_value/item_fulfillment_ship_method.xml diff --git a/lib/netsuite/support/sublist.rb b/lib/netsuite/support/sublist.rb index 60ccf1cc5..b8d6a1fa1 100644 --- a/lib/netsuite/support/sublist.rb +++ b/lib/netsuite/support/sublist.rb @@ -31,7 +31,7 @@ def sublist(key, klass) end def initialize(attributes = {}) - initialize_from_attributes_hash(attributes) + initialize_from_attributes_hash(attributes || {}) end def to_record diff --git a/spec/netsuite/actions/get_select_value_spec.rb b/spec/netsuite/actions/get_select_value_spec.rb new file mode 100644 index 000000000..52c08db26 --- /dev/null +++ b/spec/netsuite/actions/get_select_value_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe NetSuite::Actions::GetSelectValue do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + + describe 'fulfillment ship method' do + subject do + NetSuite::Records::BaseRefList.get_select_value(recordType: 'itemFulfillment', field: 'shipMethod') + end + + let(:response) { File.read('spec/support/fixtures/get_select_value/item_fulfillment_ship_method.xml') } + + before do + savon.expects(:get_select_value).with(:message => { + pageIndex: 1, + fieldDescription: { + 'platformCore:recordType' => 'itemFulfillment', + 'platformCore:field' => 'shipMethod' + } + }).returns(response) + end + + it 'makes a valid request to the NetSuite API' do + subject + end + + it 'returns a BaseRefList object' do + expect(subject).to be_kind_of(NetSuite::Records::BaseRefList) + expect(subject.base_refs[0].internal_id).to eq('94') + expect(subject.base_refs[0].name).to eq('Ground (Custom)') + end + + context 'with empty result' do + let(:response) { File.read('spec/support/fixtures/get_select_value/empty_result.xml') } + + it 'returns an empty list' do + expect(subject).to be_kind_of(NetSuite::Records::BaseRefList) + expect(subject.base_refs).to be_empty + end + end + end +end diff --git a/spec/support/fixtures/get_select_value/empty_result.xml b/spec/support/fixtures/get_select_value/empty_result.xml new file mode 100644 index 000000000..075ef6189 --- /dev/null +++ b/spec/support/fixtures/get_select_value/empty_result.xml @@ -0,0 +1,22 @@ + + + + + REDACTED + + + + + + + + WARNING + Results are incomplete. You must provide a value for field entity. + + + 0 + 0 + + + + diff --git a/spec/support/fixtures/get_select_value/item_fulfillment_ship_method.xml b/spec/support/fixtures/get_select_value/item_fulfillment_ship_method.xml new file mode 100644 index 000000000..d1bde34e3 --- /dev/null +++ b/spec/support/fixtures/get_select_value/item_fulfillment_ship_method.xml @@ -0,0 +1,43 @@ + + + + + REDACTED + + + + + + + 8 + 1 + + + Ground (Custom) + + + Pick-up + + + Special Delivery + + + UPS 2nd Day Air AM&#174; + + + UPS Ground + + + UPS Next Day Air? + + + UPS Next Day Air® Early A.M.® + + + UPS® Ground + + + + + + From 9a343fbfd2745596054b6005e31a5bce73053ba1 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Fri, 3 Jun 2022 22:16:01 -0400 Subject: [PATCH 111/114] Add Customer#attach_file and File#update actions (#544) --- HISTORY.md | 2 ++ lib/netsuite/records/customer.rb | 2 +- lib/netsuite/records/file.rb | 2 +- spec/netsuite/records/customer_spec.rb | 29 ++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 0df67442e..37bb82472 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,8 @@ The following were moved from `fields` to `record_refs`: `buying_reason`, `buying_time_frame`, `campaign_category`, `image`, `opening_balance_account`, `pref_cc_processor`, `representing_subsidiary`, `sales_group`, `sales_readiness` The following were removed as `fields` since their sublist class is not yet implemented: `download_list`, `group_pricing_list`, `item_pricing_list` * Add search-only fields to `Customer` (#535) +* Add `attach_file` action to `Customer` records (#544) +* Add `update` action to `File` records (#544) ### Fixed diff --git a/lib/netsuite/records/customer.rb b/lib/netsuite/records/customer.rb index f3a1b3548..6af3a8065 100644 --- a/lib/netsuite/records/customer.rb +++ b/lib/netsuite/records/customer.rb @@ -7,7 +7,7 @@ class Customer include Support::Actions include Namespaces::ListRel - actions :get, :get_list, :add, :update, :upsert, :upsert_list, :delete, :delete_list, :search + actions :get, :get_list, :add, :update, :upsert, :upsert_list, :delete, :delete_list, :search, :attach_file # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/customer.html diff --git a/lib/netsuite/records/file.rb b/lib/netsuite/records/file.rb index 096bd7af3..d8c13bb8d 100644 --- a/lib/netsuite/records/file.rb +++ b/lib/netsuite/records/file.rb @@ -9,7 +9,7 @@ class File # https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2014_1/schema/record/file.html - actions :get, :add, :delete, :search, :get_list + actions :get, :add, :delete, :search, :get_list, :update fields :content, :description, :name, :media_type_name, :file_type, :text_file_encoding, :created_date, :last_modified_date diff --git a/spec/netsuite/records/customer_spec.rb b/spec/netsuite/records/customer_spec.rb index d03c5e24e..4ebab27c8 100644 --- a/spec/netsuite/records/customer_spec.rb +++ b/spec/netsuite/records/customer_spec.rb @@ -440,6 +440,35 @@ end end + describe '#attach_file' do + let(:test_data) { { :email => 'test@example.com', :fax => '1234567890' } } + let(:file) { double('file') } + + context 'when the response is successful' do + let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) } + + it 'returns true' do + customer = NetSuite::Records::Customer.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([customer, file], {}). + and_return(response) + expect(customer.attach_file(file)).to be_truthy + end + end + + context 'when the response is unsuccessful' do + let(:response) { NetSuite::Response.new(:success => false, :body => {}) } + + it 'returns false' do + customer = NetSuite::Records::Customer.new(test_data) + expect(NetSuite::Actions::AttachFile).to receive(:call). + with([customer, file], {}). + and_return(response) + expect(customer.attach_file(file)).to be_falsey + end + end + end + describe '#to_record' do let(:customer) { NetSuite::Records::Customer.new(:entity_id => 'TEST CUSTOMER', :is_person => true) } From 7767aa62f2d5dcef93b66380989d71f780772c92 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Tue, 7 Jun 2022 10:02:17 -0400 Subject: [PATCH 112/114] Expose `errors` after calls to `delete` action (#545) If the `delete` action returned false due to a NetSuite error, there wasn't a way to access those errors. Now you can call `errors` on the instance you tried deleting to access them, just like when adding, updating, etc. instances. --- HISTORY.md | 1 + lib/netsuite/actions/delete.rb | 17 ++++ spec/netsuite/actions/delete_spec.rb | 88 ++++++++++++++++--- .../fixtures/delete/delete_customer_error.xml | 21 +++++ .../delete_customer_multiple_errors.xml | 25 ++++++ 5 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 spec/support/fixtures/delete/delete_customer_error.xml create mode 100644 spec/support/fixtures/delete/delete_customer_multiple_errors.xml diff --git a/HISTORY.md b/HISTORY.md index 37bb82472..e6df53912 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,6 +7,7 @@ The following were removed as `fields` since their sublist class is not yet impl * Add search-only fields to `Customer` (#535) * Add `attach_file` action to `Customer` records (#544) * Add `update` action to `File` records (#544) +* Expose `errors` after calls to `delete` action (#545) ### Fixed diff --git a/lib/netsuite/actions/delete.rb b/lib/netsuite/actions/delete.rb index cabc58eb4..8a11cb3fb 100644 --- a/lib/netsuite/actions/delete.rb +++ b/lib/netsuite/actions/delete.rb @@ -65,6 +65,20 @@ 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 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 delete(options = {}, credentials={}) response = if options.empty? @@ -72,6 +86,9 @@ def delete(options = {}, credentials={}) else NetSuite::Actions::Delete.call([self, options], credentials) end + + @errors = response.errors + response.success? end end diff --git a/spec/netsuite/actions/delete_spec.rb b/spec/netsuite/actions/delete_spec.rb index 43a5cbd02..c618dc07f 100644 --- a/spec/netsuite/actions/delete_spec.rb +++ b/spec/netsuite/actions/delete_spec.rb @@ -9,24 +9,84 @@ NetSuite::Records::Customer.new(:internal_id => '980', :entity_id => 'Shutter Fly', :company_name => 'Shutter Fly, Inc.') end - before do - savon.expects(:delete).with(:message => { - 'platformMsgs:baseRef' => { - '@internalId' => '980', - '@type' => 'customer', - '@xsi:type' => 'platformCore:RecordRef' - }, - }).returns(File.read('spec/support/fixtures/delete/delete_customer.xml')) + context 'when successful' do + before do + savon.expects(:delete).with(:message => { + 'platformMsgs:baseRef' => { + '@internalId' => '980', + '@type' => 'customer', + '@xsi:type' => 'platformCore:RecordRef' + }, + }).returns(File.read('spec/support/fixtures/delete/delete_customer.xml')) + end + + it 'makes a valid request to the NetSuite API' do + NetSuite::Actions::Delete.call([customer]) + end + + it 'returns a valid Response object' do + response = NetSuite::Actions::Delete.call([customer]) + expect(response).to be_kind_of(NetSuite::Response) + expect(response).to be_success + end end - it 'makes a valid request to the NetSuite API' do - NetSuite::Actions::Delete.call([customer]) + context 'when not successful' do + before do + savon.expects(:delete).with(:message => { + 'platformMsgs:baseRef' => { + '@xsi:type' => 'platformCore:RecordRef', + '@internalId' => '980', + '@type' => 'customer', + }, + }).returns(File.read('spec/support/fixtures/delete/delete_customer_error.xml')) + end + + it 'provides an error method on the object with details about the error' do + customer.delete + error = customer.errors.first + + expect(error).to be_kind_of(NetSuite::Error) + expect(error.type).to eq('ERROR') + expect(error.code).to eq('INSUFFICIENT_PERMISSION') + expect(error.message).to eq("Permission Violation: You need a higher level of the 'Lists -> Documents and Files' permission to access this page. Please contact your account administrator.") + end + + it 'provides an error method on the response' do + response = NetSuite::Actions::Delete.call([customer]) + expect(response.errors.first).to be_kind_of(NetSuite::Error) + end end - it 'returns a valid Response object' do - response = NetSuite::Actions::Delete.call([customer]) - expect(response).to be_kind_of(NetSuite::Response) - expect(response).to be_success + context 'when not successful with multiple errors' do + before do + savon.expects(:delete).with(:message => { + 'platformMsgs:baseRef' => { + '@xsi:type' => 'platformCore:RecordRef', + '@internalId' => '980', + '@type' => 'customer', + }, + }).returns(File.read('spec/support/fixtures/delete/delete_customer_multiple_errors.xml')) + end + + it 'provides an error method on the object with details about the error' do + customer.delete + expect(customer.errors.length).to eq(2) + + error = customer.errors.first + + expect(error).to be_kind_of(NetSuite::Error) + expect(error.type).to eq('ERROR') + expect(error.code).to eq('INSUFFICIENT_PERMISSION') + expect(error.message).to eq("Permission Violation: You need a higher level of the 'Lists -> Documents and Files' permission to access this page. Please contact your account administrator.") + + error = customer.errors[1] + + expect(error).to be_kind_of(NetSuite::Error) + expect(error.type).to eq('ERROR') + expect(error.code).to eq('SOMETHING_ELSE') + expect(error.message).to eq('Another error.') + end end end diff --git a/spec/support/fixtures/delete/delete_customer_error.xml b/spec/support/fixtures/delete/delete_customer_error.xml new file mode 100644 index 000000000..000a4de26 --- /dev/null +++ b/spec/support/fixtures/delete/delete_customer_error.xml @@ -0,0 +1,21 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + + + INSUFFICIENT_PERMISSION + Permission Violation: You need a higher level of the 'Lists -> Documents and Files' permission to access this page. Please contact your account administrator. + + + + + + + diff --git a/spec/support/fixtures/delete/delete_customer_multiple_errors.xml b/spec/support/fixtures/delete/delete_customer_multiple_errors.xml new file mode 100644 index 000000000..22c6adef7 --- /dev/null +++ b/spec/support/fixtures/delete/delete_customer_multiple_errors.xml @@ -0,0 +1,25 @@ + + + + + WEBSERVICES_3392464_1220201115821392011296470399_67055c545d0 + + + + + + + + INSUFFICIENT_PERMISSION + Permission Violation: You need a higher level of the 'Lists -> Documents and Files' permission to access this page. Please contact your account administrator. + + + SOMETHING_ELSE + Another error. + + + + + + + From a291ac392f115c3c83e6dd10227a3405669fb864 Mon Sep 17 00:00:00 2001 From: Chris Gunther Date: Mon, 13 Jun 2022 15:38:04 -0400 Subject: [PATCH 113/114] Add `update_list` action where missing on supported item records (#546) --- HISTORY.md | 1 + lib/netsuite/records/assembly_item.rb | 2 +- lib/netsuite/records/description_item.rb | 2 +- lib/netsuite/records/discount_item.rb | 2 +- lib/netsuite/records/gift_certificate_item.rb | 2 +- lib/netsuite/records/item_group.rb | 2 +- lib/netsuite/records/kit_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 +- lib/netsuite/records/non_inventory_sale_item.rb | 2 +- lib/netsuite/records/other_charge_sale_item.rb | 2 +- lib/netsuite/records/payment_item.rb | 2 +- lib/netsuite/records/serialized_assembly_item.rb | 2 +- lib/netsuite/records/serialized_inventory_item.rb | 2 +- lib/netsuite/records/service_resale_item.rb | 2 +- lib/netsuite/records/service_sale_item.rb | 2 +- lib/netsuite/records/subtotal_item.rb | 2 +- 18 files changed, 18 insertions(+), 17 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index e6df53912..48f4c319e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -8,6 +8,7 @@ The following were removed as `fields` since their sublist class is not yet impl * Add `attach_file` action to `Customer` records (#544) * Add `update` action to `File` records (#544) * Expose `errors` after calls to `delete` action (#545) +* Add `update_list` action where missing on supported item records (#546) ### Fixed diff --git a/lib/netsuite/records/assembly_item.rb b/lib/netsuite/records/assembly_item.rb index 5ff5e37ac..f0d4d4207 100644 --- a/lib/netsuite/records/assembly_item.rb +++ b/lib/netsuite/records/assembly_item.rb @@ -7,7 +7,7 @@ class AssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search + actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :update_list, :upsert, :upsert_list, :search fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, :build_entire_assembly, :copy_description, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, diff --git a/lib/netsuite/records/description_item.rb b/lib/netsuite/records/description_item.rb index b11ae2a50..5c7c5c31f 100644 --- a/lib/netsuite/records/description_item.rb +++ b/lib/netsuite/records/description_item.rb @@ -7,7 +7,7 @@ class SubtotalItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :item_id, :last_modified_date diff --git a/lib/netsuite/records/discount_item.rb b/lib/netsuite/records/discount_item.rb index ae626a4d2..8f83956bb 100644 --- a/lib/netsuite/records/discount_item.rb +++ b/lib/netsuite/records/discount_item.rb @@ -7,7 +7,7 @@ class DiscountItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :update, :delete, :search, :upsert + actions :get, :get_deleted, :get_list, :add, :update, :update_list, :delete, :search, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :is_pre_tax, :item_id, :last_modified_date, :non_posting, :rate, :upc_code, :vendor_name diff --git a/lib/netsuite/records/gift_certificate_item.rb b/lib/netsuite/records/gift_certificate_item.rb index beb52f11b..065b8392b 100644 --- a/lib/netsuite/records/gift_certificate_item.rb +++ b/lib/netsuite/records/gift_certificate_item.rb @@ -7,7 +7,7 @@ class GiftCertificateItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_list, :add, :delete, :search, :upsert + actions :get, :get_list, :add, :delete, :search, :update_list, :upsert fields :auth_codes_list, :available_to_partners, diff --git a/lib/netsuite/records/item_group.rb b/lib/netsuite/records/item_group.rb index d92f7c1e3..64f9755e8 100644 --- a/lib/netsuite/records/item_group.rb +++ b/lib/netsuite/records/item_group.rb @@ -7,7 +7,7 @@ class ItemGroup include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :include_start_end_lines, :is_inactive, :is_vsoe_bundle, :item_id, :last_modified_date, :print_items, :upc_code, :vendor_name diff --git a/lib/netsuite/records/kit_item.rb b/lib/netsuite/records/kit_item.rb index 2eb059559..cb7be1f54 100644 --- a/lib/netsuite/records/kit_item.rb +++ b/lib/netsuite/records/kit_item.rb @@ -7,7 +7,7 @@ class KitItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :cost_estimate, :created_date, :defer_rev_rec, :description, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, :handling_cost, diff --git a/lib/netsuite/records/lot_numbered_assembly_item.rb b/lib/netsuite/records/lot_numbered_assembly_item.rb index b3509833b..f4249a822 100644 --- a/lib/netsuite/records/lot_numbered_assembly_item.rb +++ b/lib/netsuite/records/lot_numbered_assembly_item.rb @@ -7,7 +7,7 @@ class LotNumberedAssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :upsert, :upsert_list, :search + actions :get, :get_deleted, :get_list, :get_select_value, :add, :delete, :update, :update_list, :upsert, :upsert_list, :search fields :auto_lead_time, :auto_preferred_stock_level, :auto_reorder_point, :available_to_partners, :average_cost, :build_entire_assembly, :copy_description, :cost, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :cost_units, :costing_method, diff --git a/lib/netsuite/records/non_inventory_purchase_item.rb b/lib/netsuite/records/non_inventory_purchase_item.rb index 85d0e5c66..249ccd95b 100644 --- a/lib/netsuite/records/non_inventory_purchase_item.rb +++ b/lib/netsuite/records/non_inventory_purchase_item.rb @@ -7,7 +7,7 @@ class NonInventoryPurchaseItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update_list, :upsert fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :country_of_manufacture, :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, diff --git a/lib/netsuite/records/non_inventory_resale_item.rb b/lib/netsuite/records/non_inventory_resale_item.rb index 2d018a665..f40833824 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -7,7 +7,7 @@ class NonInventoryResaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :upsert, :update + actions :get, :get_deleted, :get_list, :add, :delete, :search, :upsert, :update, :update_list fields :amortization_period, :available_to_partners, diff --git a/lib/netsuite/records/non_inventory_sale_item.rb b/lib/netsuite/records/non_inventory_sale_item.rb index 216452ae2..8d2a44577 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -7,7 +7,7 @@ class NonInventorySaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :contingent_revenue_handling, diff --git a/lib/netsuite/records/other_charge_sale_item.rb b/lib/netsuite/records/other_charge_sale_item.rb index e595b097c..be5f4bde9 100644 --- a/lib/netsuite/records/other_charge_sale_item.rb +++ b/lib/netsuite/records/other_charge_sale_item.rb @@ -7,7 +7,7 @@ class OtherChargeSaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :update_list, :delete, :upsert, :search attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/payment_item.rb b/lib/netsuite/records/payment_item.rb index d740f649c..254684b16 100644 --- a/lib/netsuite/records/payment_item.rb +++ b/lib/netsuite/records/payment_item.rb @@ -7,7 +7,7 @@ class PaymentItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :created_date, :description, :display_name, :include_children, :is_inactive, :item_id, :last_modified_date, :undep_funds diff --git a/lib/netsuite/records/serialized_assembly_item.rb b/lib/netsuite/records/serialized_assembly_item.rb index 6f5d04ab9..6e99b6f77 100644 --- a/lib/netsuite/records/serialized_assembly_item.rb +++ b/lib/netsuite/records/serialized_assembly_item.rb @@ -7,7 +7,7 @@ class SerializedAssemblyItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :alternate_demand_source_item, :asset_account, diff --git a/lib/netsuite/records/serialized_inventory_item.rb b/lib/netsuite/records/serialized_inventory_item.rb index 25ba32ee6..a90cfd1e3 100644 --- a/lib/netsuite/records/serialized_inventory_item.rb +++ b/lib/netsuite/records/serialized_inventory_item.rb @@ -7,7 +7,7 @@ class SerializedInventoryItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert record_refs :soft_descriptor, :stock_unit, diff --git a/lib/netsuite/records/service_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index 529b6f519..fa5c761be 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -7,7 +7,7 @@ class ServiceResaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :update_list, :delete, :upsert, :search fields :amortization_period, :available_to_partners, diff --git a/lib/netsuite/records/service_sale_item.rb b/lib/netsuite/records/service_sale_item.rb index 8b7800cf1..7631660c1 100644 --- a/lib/netsuite/records/service_sale_item.rb +++ b/lib/netsuite/records/service_sale_item.rb @@ -7,7 +7,7 @@ class ServiceSaleItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :update, :delete, :upsert, :search + actions :get, :get_deleted, :get_list, :add, :update, :update_list, :delete, :upsert, :search fields :available_to_partners, :cost_estimate, :cost_estimate_type, :cost_estimate_units, :create_job, :created_date, :display_name, :dont_show_price, :enforce_min_qty_internally, :exclude_from_sitemap, :featured_description, diff --git a/lib/netsuite/records/subtotal_item.rb b/lib/netsuite/records/subtotal_item.rb index d79aabb46..f36a7f312 100644 --- a/lib/netsuite/records/subtotal_item.rb +++ b/lib/netsuite/records/subtotal_item.rb @@ -7,7 +7,7 @@ class DescriptionItem include Support::Actions include Namespaces::ListAcct - actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :update_list, :upsert fields :available_to_partners, :created_date, :description, :include_children, :is_inactive, :item_id, :last_modified_date From 1ee55275561261acf3c15dde6782cc29fd5c7b1b Mon Sep 17 00:00:00 2001 From: dbecker-stripe <88861694+dbecker-stripe@users.noreply.github.com> Date: Mon, 13 Jun 2022 16:20:47 -0700 Subject: [PATCH 114/114] Add optional proxy for NetSuite requests through Savon (#547) This change adds an optional `proxy` attribute on the `NetSuite::Configuration` that is passed to the generated Savon client used for requests to NetSuite. --- lib/netsuite/configuration.rb | 13 +++++++++++++ spec/netsuite/configuration_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 936cbb247..c5063d528 100644 --- a/lib/netsuite/configuration.rb +++ b/lib/netsuite/configuration.rb @@ -27,6 +27,7 @@ def connection(params={}, credentials={}) logger: logger, log_level: log_level, log: !silent, # turn off logging entirely if configured + proxy: proxy, }.update(params)) cache_wsdl(client) return client @@ -394,5 +395,17 @@ def log_level(value = nil) def log_level=(value) attributes[:log_level] = value end + + def proxy=(proxy) + attributes[:proxy] = proxy + end + + def proxy(proxy = nil) + if proxy + self.proxy = proxy + else + attributes[:proxy] + end + end end end diff --git a/spec/netsuite/configuration_spec.rb b/spec/netsuite/configuration_spec.rb index 67ecffaf8..9879a1be8 100644 --- a/spec/netsuite/configuration_spec.rb +++ b/spec/netsuite/configuration_spec.rb @@ -476,4 +476,25 @@ end end + describe '#proxy' do + it 'defaults to nil' do + expect(config.proxy).to be_nil + end + + it 'can be set with proxy=' do + config.proxy = "https://my-proxy" + + expect(config.proxy).to eql("https://my-proxy") + + # ensure no exception is raised + config.connection + end + + it 'can be set with proxy(value)' do + config.proxy("https://my-proxy") + + expect(config.proxy).to eql("https://my-proxy") + end + end + end