README.md in netsuite-0.8.11 vs README.md in netsuite-0.8.12

- old
+ new

@@ -2,17 +2,17 @@ [![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) # 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). # Testing @@ -34,41 +34,41 @@ 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 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 + # 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' # the endpoint indicated in the > 2018_2 wsdl is invalid # you must set the endpoint directly @@ -85,21 +85,21 @@ NetSuite.configure do reset! 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 # you can specify a file or file descriptor to send the log output to (defaults to STDOUT) # If using within a Rails app, consider setting to `Rails.logger` to leverage existing @@ -109,11 +109,11 @@ # Defaults to :debug level logging for Savon API calls. Decrease the verbosity # by setting log_level to `:info`, for example # 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' role 1111 @@ -122,23 +122,23 @@ 'platformMsgs:ignoreReadOnlyFields' => true, } 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 = { 'platformMsgs:ApplicationInfo' => { 'platformMsgs:applicationId' => 'your-netsuite-app-id' } } ``` -### 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 reset! @@ -150,11 +150,11 @@ token_secret ENV['NETSUITE_TOKEN_SECRET'] # 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}" end ``` @@ -282,10 +282,24 @@ '@xsi:type' => 'customRecord' } ) ``` +## 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 # basic search search = NetSuite::Records::Customer.search({ @@ -298,11 +312,11 @@ ] }) `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' } # searching for custom records NetSuite::Records::CustomRecord.search( @@ -409,17 +423,17 @@ ] } ] }, - # 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/' => {}, '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/' => {} ], 'tranSales:accountJoin' => [ 'platformCommon:internalId/' => {} @@ -589,9 +603,56 @@ deposit = CustomerDeposit.new deposit.sales_order = RecordRef.new(internal_id: 7279) 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