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] 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" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..efb59187e --- /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@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + 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. + # 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@v2 + + # ℹ️ 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@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..ebc8f9f6f --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,23 @@ +name: Ruby + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + 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 }}" + steps: + - uses: actions/checkout@v3 + - 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 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 diff --git a/Gemfile b/Gemfile index ba0ce65e2..5ef6f16b1 100644 --- a/Gemfile +++ b/Gemfile @@ -2,15 +2,12 @@ source 'https://rubygems.org' gemspec gem 'simplecov', :require => false -gem 'rspec_junit_formatter' gem 'pry-nav' 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' +if ENV.fetch('BUNDLE_TZINFO', 'false') == 'true' + # optional dependency for more accurate timezone conversion + gem 'tzinfo', '>= 1.2.5' +end diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 000000000..48f4c319e --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,83 @@ +## 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) +* 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 + +### Breaking Changes +* Rename `CustomerSubscriptionsList` to `SubscriptionsList` and `CustomerSubscription` to `Subscription` to match NetSuite naming (#535) + +## 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) +* Remove monkey patched `lower_camelcase` method on String (#533) + +## 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.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) +* 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) +* 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 + +### 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 + +### 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 + +* 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) diff --git a/README.md b/README.md index 672fb4241..c3de3c7b3 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,16 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [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) - - [Custom Records & Fields](#custom-records--fields) - - [Searching](#searching) - - [Non-standard Operations](#non-standard-operations) -- [About SuiteSync](#about-suitesync) - - - -[![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) # 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. +* 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. - -Messages in the Slack ground are [archived here](https://suitechat.slackarchive.io). Search the archives to see if your question has been answered before. +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). @@ -39,9 +18,10 @@ There is some additional helpful resources for NetSuite development [listed here 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 +36,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/) +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 +* 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)) -For most use-cases, the following configuration will be sufficient: +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 email 'email@example.com' password 'password' role 10 - # use `NetSuite::Utilities.data_center_url('TSTDRV1576318')` to retrieve the 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 + # https://github.com/NetSweet/netsuite/pull/473 + endpoint "https://#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` @@ -91,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 @@ -115,6 +111,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 +124,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 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' @@ -137,9 +134,9 @@ NetSuite::Configuration.soap_header = { } ``` -### Token based Authentication +### 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 +151,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 "https://#{wsdl_domain}/services/NetSuitePort_#{api_version}" end ``` @@ -195,7 +197,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( @@ -218,6 +220,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 @@ -269,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 @@ -285,7 +314,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' } @@ -396,12 +425,15 @@ 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/' => {}, '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/' => {} @@ -415,7 +447,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" } ] @@ -573,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 @@ -593,7 +674,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. 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/circle.yml b/circle.yml deleted file mode 100644 index 664e435a9..000000000 --- a/circle.yml +++ /dev/null @@ -1,36 +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 - -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: '1.17.2' - with-cache: false - - 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 diff --git a/lib/netsuite.rb b/lib/netsuite.rb index b6bcba512..baff263f0 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' @@ -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' @@ -95,6 +96,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' @@ -123,14 +125,14 @@ 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' 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' @@ -189,14 +191,22 @@ 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' 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' + 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' @@ -220,6 +230,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' @@ -265,6 +276,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' @@ -280,6 +293,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' @@ -297,6 +312,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/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/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/actions/delete.rb b/lib/netsuite/actions/delete.rb index d79aafb05..8a11cb3fb 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 # @@ -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/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 e5f8420dd..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 ) @@ -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) @@ -235,6 +246,8 @@ def success? module Support def self.included(base) base.extend(ClassMethods) + + attr_accessor :search_joins end module ClassMethods diff --git a/lib/netsuite/configuration.rb b/lib/netsuite/configuration.rb index 89ebb4d66..c5063d528 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, @@ -26,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 @@ -94,6 +96,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 @@ -381,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/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/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 5dd04b346..b3546974a 100644 --- a/lib/netsuite/records/accounting_period.rb +++ b/lib/netsuite/records/accounting_period.rb @@ -8,7 +8,7 @@ class AccountingPeriod actions :get, :get_list, :add, :delete, :upsert, :search - fields :allow_non_gl_changes, :end_date, :is_adjust, :is_quarter, :is_year, :period_name, :start_date + fields :allow_non_gl_changes, :end_date, :is_adjust, :is_quarter, :is_year, :period_name, :start_date, :closed record_refs :parent 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..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_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, @@ -47,10 +47,10 @@ 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 - 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 1b0aa045a..10ed66df0 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 @@ -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) @@ -36,5 +35,3 @@ def initialize(attributes = {}) end end end - - 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_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/lib/netsuite/records/cash_sale.rb b/lib/netsuite/records/cash_sale.rb index 97fe2d042..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, @@ -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 2934453f0..5dc01b3f4 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, @@ -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/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/lib/netsuite/records/credit_memo.rb b/lib/netsuite/records/credit_memo.rb index b9999c869..887bcac1c 100644 --- a/lib/netsuite/records/credit_memo.rb +++ b/lib/netsuite/records/credit_memo.rb @@ -17,12 +17,13 @@ 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 field :apply_list, CreditMemoApplyList field :ship_group_list, SalesOrderShipGroupList + field :null_field_list, NullFieldList # field :bill_address_list, field :transaction_bill_address, BillAddress @@ -38,7 +39,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 39f940ff0..85163e93d 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 @@ -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_field_list.rb b/lib/netsuite/records/custom_field_list.rb index 81a7cc555..193bb4b84 100644 --- a/lib/netsuite/records/custom_field_list.rb +++ b/lib/netsuite/records/custom_field_list.rb @@ -110,10 +110,16 @@ 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' - attrs[:value] = custom_field_data[:value].map do |entry| + 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] + else + [custom_field_data[:value]] + end.map do |entry| CustomRecordRef.new(entry) end end diff --git a/lib/netsuite/records/custom_record.rb b/lib/netsuite/records/custom_record.rb index 60fd4f1de..18e66ee91 100644 --- a/lib/netsuite/records/custom_record.rb +++ b/lib/netsuite/records/custom_record.rb @@ -17,12 +17,12 @@ 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 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..6af3a8065 100644 --- a/lib/netsuite/records/customer.rb +++ b/lib/netsuite/records/customer.rb @@ -7,44 +7,245 @@ 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 - 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 + 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 :credit_cards_list, CustomerCreditCardsList - field :custom_field_list, CustomFieldList + 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 - 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 0503300c9..3489cd9b8 100644 --- a/lib/netsuite/records/customer_deposit.rb +++ b/lib/netsuite/records/customer_deposit.rb @@ -21,15 +21,14 @@ 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 - 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 e6a4bb141..a8e96f8d8 100644 --- a/lib/netsuite/records/customer_payment.rb +++ b/lib/netsuite/records/customer_payment.rb @@ -17,15 +17,17 @@ class CustomerPayment field :custom_field_list, CustomFieldList field :apply_list, CustomerPaymentApplyList + field :credit_list, CustomerPaymentCreditList 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 - 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_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/lib/netsuite/records/customer_refund.rb b/lib/netsuite/records/customer_refund.rb index 4f6398e40..8c768d3ab 100644 --- a/lib/netsuite/records/customer_refund.rb +++ b/lib/netsuite/records/customer_refund.rb @@ -20,11 +20,10 @@ 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 - attr_accessor :search_joins def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_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/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/description_item.rb b/lib/netsuite/records/description_item.rb index 7a4d3a442..5c7c5c31f 100644 --- a/lib/netsuite/records/description_item.rb +++ b/lib/netsuite/records/description_item.rb @@ -7,15 +7,15 @@ 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, :update_list, :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 - # TODO field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/discount_item.rb b/lib/netsuite/records/discount_item.rb index db1cc7827..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_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/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, diff --git a/lib/netsuite/records/estimate.rb b/lib/netsuite/records/estimate.rb index cc1602f59..426714b80 100644 --- a/lib/netsuite/records/estimate.rb +++ b/lib/netsuite/records/estimate.rb @@ -9,28 +9,108 @@ 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, - :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 - attr_accessor :search_joins def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) 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/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/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 af8165e5e..e8473c963 100644 --- a/lib/netsuite/records/inventory_item.rb +++ b/lib/netsuite/records/inventory_item.rb @@ -20,52 +20,312 @@ 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, :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 - 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 + # 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, :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, + :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, + :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 + field :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 67cef2e1a..0e0a84377 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 @@ -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/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 diff --git a/lib/netsuite/records/invoice.rb b/lib/netsuite/records/invoice.rb index 60f25aba5..eb2aeec43 100644 --- a/lib/netsuite/records/invoice.rb +++ b/lib/netsuite/records/invoice.rb @@ -9,10 +9,10 @@ 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, :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 @@ -38,17 +38,110 @@ 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, :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 + 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, :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 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_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_availability.rb b/lib/netsuite/records/item_availability.rb new file mode 100644 index 000000000..ea9cb542f --- /dev/null +++ b/lib/netsuite/records/item_availability.rb @@ -0,0 +1,46 @@ +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 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 + end + end +end diff --git a/lib/netsuite/records/item_fulfillment.rb b/lib/netsuite/records/item_fulfillment.rb index aa37b4546..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 @@ -26,11 +26,13 @@ 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 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_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_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/lib/netsuite/records/item_group.rb b/lib/netsuite/records/item_group.rb index 3cda03efb..64f9755e8 100644 --- a/lib/netsuite/records/item_group.rb +++ b/lib/netsuite/records/item_group.rb @@ -7,18 +7,18 @@ 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, :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 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 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/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/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/item_receipt_item.rb b/lib/netsuite/records/item_receipt_item.rb index c9b927a16..0bc4b60a3 100644 --- a/lib/netsuite/records/item_receipt_item.rb +++ b/lib/netsuite/records/item_receipt_item.rb @@ -7,15 +7,16 @@ 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 - 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 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/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/kit_item.rb b/lib/netsuite/records/kit_item.rb index 34dd2c7c2..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_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, @@ -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/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_assembly_item.rb b/lib/netsuite/records/lot_numbered_assembly_item.rb index 67c7d07f3..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_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/lot_numbered_inventory_item.rb b/lib/netsuite/records/lot_numbered_inventory_item.rb index 027f27a91..02d2ddc49 100644 --- a/lib/netsuite/records/lot_numbered_inventory_item.rb +++ b/lib/netsuite/records/lot_numbered_inventory_item.rb @@ -9,97 +9,241 @@ 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 + 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 + actions :get, :get_deleted, :get_list, :add, :delete, :search, :update, :upsert, :update_list - 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 + attr_accessor :external_id def initialize(attributes = {}) @internal_id = attributes.delete(:internal_id) || attributes.delete(:@internal_id) 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/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 diff --git a/lib/netsuite/records/non_inventory_purchase_item.rb b/lib/netsuite/records/non_inventory_purchase_item.rb index f321910aa..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_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, @@ -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..f40833824 100644 --- a/lib/netsuite/records/non_inventory_resale_item.rb +++ b/lib/netsuite/records/non_inventory_resale_item.rb @@ -7,34 +7,170 @@ 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, :update_list - 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, :pricing_matrix, :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 + 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 7699b4637..8d2a44577 100644 --- a/lib/netsuite/records/non_inventory_sale_item.rb +++ b/lib/netsuite/records/non_inventory_sale_item.rb @@ -7,37 +7,149 @@ 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, :update_list, :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, :pricing_matrix, :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 + field :translations_list, TranslationList 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/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/records/opportunity.rb b/lib/netsuite/records/opportunity.rb index d1cced560..3162b81bc 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 @@ -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) @@ -43,4 +42,4 @@ def initialize(attributes = {}) end end -end \ No newline at end of file +end diff --git a/lib/netsuite/records/other_charge_sale_item.rb b/lib/netsuite/records/other_charge_sale_item.rb index 874643327..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_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 @@ -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/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/lib/netsuite/records/payment_item.rb b/lib/netsuite/records/payment_item.rb index d58a0268d..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_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 @@ -15,9 +15,9 @@ class PaymentItem field :custom_field_list, CustomFieldList 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/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/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/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/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/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/lib/netsuite/records/sales_order.rb b/lib/netsuite/records/sales_order.rb index 8b6059e47..b586af0e5 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, @@ -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/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/lib/netsuite/records/serialized_assembly_item.rb b/lib/netsuite/records/serialized_assembly_item.rb index 3448dbddc..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_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, @@ -61,7 +61,6 @@ class SerializedAssemblyItem :hazmat_packing_group, :hazmat_shipping_name, :include_children, - :income_account, :interco_cogs_account, :interco_income_account, :invt_classification, @@ -181,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, @@ -209,6 +207,8 @@ class SerializedAssemblyItem :wip_acct, :wip_variance_acct + record_refs :income_account + # accountingBookDetailList ItemAccountingBookDetailList # binNumberList InventoryItemBinNumberList # itemOptionsList ItemOptionsList @@ -220,6 +220,7 @@ class SerializedAssemblyItem # siteCategoryList SiteCategoryList # translationsList TranslationList + field :subsidiary_list, RecordRefList field :custom_field_list, CustomFieldList attr_reader :internal_id diff --git a/lib/netsuite/records/serialized_inventory_item.rb b/lib/netsuite/records/serialized_inventory_item.rb index 6ce9a46a8..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_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, @@ -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/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_resale_item.rb b/lib/netsuite/records/service_resale_item.rb index d5ee833b5..fa5c761be 100644 --- a/lib/netsuite/records/service_resale_item.rb +++ b/lib/netsuite/records/service_resale_item.rb @@ -7,30 +7,134 @@ class ServiceResaleItem include Support::Actions include Namespaces::ListAcct - 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, - :pricing_matrix, :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 + actions :get, :get_deleted, :get_list, :add, :update, :update_list, :delete, :upsert, :search + + fields :amortization_period, + :available_to_partners, + :contingent_revenue_handling, + :cost, + :cost_estimate, + :cost_estimate_type, + :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, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :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, + :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, + :sitemap_priority, + :soft_descriptor, + :specials_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 + + 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 :item_options_list, ItemOptionsList + # TODO: field :item_task_templates_list, ServiceItemTaskTemplatesList + # TODO: field :hierarchy_versions_list, ServiceResaleItemHierarchyVersionsList + # TODO: field :presentation_item_list, PresentationItemList + # TODO: field :site_category_list, SiteCategoryList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id diff --git a/lib/netsuite/records/service_sale_item.rb b/lib/netsuite/records/service_sale_item.rb index 85bcb30fb..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_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, @@ -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 @@ -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/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/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/subtotal_item.rb b/lib/netsuite/records/subtotal_item.rb index 85cb546a2..f36a7f312 100644 --- a/lib/netsuite/records/subtotal_item.rb +++ b/lib/netsuite/records/subtotal_item.rb @@ -7,15 +7,15 @@ 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, :update_list, :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 - # TODO field :translations_list, TranslationList + field :translations_list, TranslationList attr_reader :internal_id attr_accessor :external_id @@ -32,4 +32,3 @@ def self.search_class_name end end end - \ No newline at end of file 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/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/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/lib/netsuite/records/vendor.rb b/lib/netsuite/records/vendor.rb index e1491c6b1..93277fc6b 100644 --- a/lib/netsuite/records/vendor.rb +++ b/lib/netsuite/records/vendor.rb @@ -9,19 +9,20 @@ 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, - :currency_list, :date_created, :default_address, :eligible_for_commission, + 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 + field :currency_list, VendorCurrencyList # TODO should change name to VendorAddressBookList field :addressbook_list, CustomerAddressbookList @@ -34,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/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 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) 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 14e3d7fc1..af478e541 100644 --- a/lib/netsuite/support/fields.rb +++ b/lib/netsuite/support/fields.rb @@ -21,6 +21,9 @@ 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 @@ -60,6 +63,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..43065247f 100644 --- a/lib/netsuite/support/records.rb +++ b/lib/netsuite/support/records.rb @@ -5,9 +5,9 @@ module Records include Namespaces::PlatformCore def to_record - attributes.reject { |k,v| self.class.read_only_fields.include?(k) }.inject({}) do |hash, (k,v)| - kname = "#{record_namespace}:" - kname += k == :klass ? 'class' : k.to_s.lower_camelcase + 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' : NetSuite::Utilities::Strings.lower_camelcase(k.to_s) to_attributes!(hash, kname, v) @@ -38,18 +38,26 @@ 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 def record_type - "#{record_namespace}:#{self.class.to_s.split('::').last}" + "#{record_namespace}:#{record_type_without_namespace}" + end + + def netsuite_type + Records.netsuite_type(self) + end + + def record_type_without_namespace + Records.record_type_without_namespace(self) end def refresh(credentials = {}) @@ -67,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/search_result.rb b/lib/netsuite/support/search_result.rb index 901c46edf..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 # @@ -89,6 +104,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/lib/netsuite/support/sublist.rb b/lib/netsuite/support/sublist.rb index 4266f09d1..b8d6a1fa1 100644 --- a/lib/netsuite/support/sublist.rb +++ b/lib/netsuite/support/sublist.rb @@ -31,11 +31,11 @@ def sublist(key, klass) end def initialize(attributes = {}) - initialize_from_attributes_hash(attributes) + initialize_from_attributes_hash(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.rb b/lib/netsuite/utilities.rb index c0b0f2d91..b0cc1c982 100644 --- a/lib/netsuite/utilities.rb +++ b/lib/netsuite/utilities.rb @@ -103,6 +103,10 @@ 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 << 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) @@ -170,9 +174,12 @@ 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::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) ns_item ||= NetSuite::Utilities.get_record(NetSuite::Records::LotNumberedInventoryItem, ns_item_internal_id, opts) 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 diff --git a/lib/netsuite/version.rb b/lib/netsuite/version.rb index 438623e3c..ecf1526e5 100644 --- a/lib/netsuite/version.rb +++ b/lib/netsuite/version.rb @@ -1,3 +1,3 @@ module NetSuite - VERSION = '0.8.6' + VERSION = '0.8.12' end diff --git a/netsuite.gemspec b/netsuite.gemspec index fb4ca5452..9102e627f 100644 --- a/netsuite.gemspec +++ b/netsuite.gemspec @@ -15,8 +15,10 @@ 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', '<= 2.11.1' + gem.add_dependency 'savon', '>= 2.3.0' - gem.add_development_dependency 'rspec', '~> 3.8.0' + gem.add_development_dependency 'rspec', '~> 3.11.0' + gem.add_development_dependency 'rake', '~> 12.3.3' end 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/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/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/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/netsuite/actions/search_spec.rb b/spec/netsuite/actions/search_spec.rb index a3cbfea04..2cb51f5d5 100644 --- a/spec/netsuite/actions/search_spec.rb +++ b/spec/netsuite/actions/search_spec.rb @@ -168,9 +168,31 @@ 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.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 + + 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 @@ -179,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/netsuite/configuration_spec.rb b/spec/netsuite/configuration_spec.rb index 7b48a0c6f..9879a1be8 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 @@ -369,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" @@ -444,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 diff --git a/spec/netsuite/records/basic_record_spec.rb b/spec/netsuite/records/basic_record_spec.rb index 8a437fbda..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, @@ -61,6 +63,7 @@ NetSuite::Records::BinTransfer, NetSuite::Records::SerializedAssemblyItem, NetSuite::Records::CustomerStatus, + NetSuite::Records::CustomerPayment, NetSuite::Records::TransactionBodyCustomField, NetSuite::Records::TransactionColumnCustomField, NetSuite::Records::EntityCustomField @@ -108,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/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 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 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/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/netsuite/records/customer_payment_credit_list_spec.rb b/spec/netsuite/records/customer_payment_credit_list_spec.rb new file mode 100644 index 000000000..bdc3c5aa6 --- /dev/null +++ b/spec/netsuite/records/customer_payment_credit_list_spec.rb @@ -0,0 +1,26 @@ +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 << 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) } + end + + describe '#to_record' do + it 'can represent itself as a SOAP record' do + record = { + 'tranCust:credit' => [{},{}] + } + + list.credits.concat([apply, apply]) + expect(list.to_record).to eql(record) + end + end + +end diff --git a/spec/netsuite/records/customer_payment_spec.rb b/spec/netsuite/records/customer_payment_spec.rb index 561e7477f..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 @@ -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' diff --git a/spec/netsuite/records/customer_spec.rb b/spec/netsuite/records/customer_spec.rb index 37c1add94..4ebab27c8 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 @@ -202,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) } 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/netsuite/records/inventory_item_spec.rb b/spec/netsuite/records/inventory_item_spec.rb index 32c643f67..b92852d0b 100644 --- a/spec/netsuite/records/inventory_item_spec.rb +++ b/spec/netsuite/records/inventory_item_spec.rb @@ -5,35 +5,316 @@ 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 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, + :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, :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 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 @@ -215,6 +496,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..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, @@ -41,6 +55,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, :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, @@ -299,6 +406,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' }) } @@ -329,6 +465,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/netsuite/records/item_availability_spec.rb b/spec/netsuite/records/item_availability_spec.rb new file mode 100644 index 000000000..d91beecec --- /dev/null +++ b/spec/netsuite/records/item_availability_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe NetSuite::Records::ItemAvailability do + before(:all) { savon.mock! } + after(:all) { savon.unmock! } + + 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, 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/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 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 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 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..cc27f5eec --- /dev/null +++ b/spec/netsuite/records/lot_numbered_inventory_item_spec.rb @@ -0,0 +1,247 @@ +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, + translations_list: NetSuite::Records::TranslationList, + }.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 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 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 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 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/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 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 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 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/records/service_resale_item_spec.rb b/spec/netsuite/records/service_resale_item_spec.rb index b59f99176..0913501b0 100644 --- a/spec/netsuite/records/service_resale_item_spec.rb +++ b/spec/netsuite/records/service_resale_item_spec.rb @@ -5,31 +5,136 @@ 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_type, + :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, + :matrix_type, + :max_donation_amount, + :maximum_quantity, + :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, + :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, + :sitemap_priority, + :soft_descriptor, + :specials_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, ].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 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) 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 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, diff --git a/spec/netsuite/support/fields_spec.rb b/spec/netsuite/support/fields_spec.rb index ddcc1379f..f888f4737 100644 --- a/spec/netsuite/support/fields_spec.rb +++ b/spec/netsuite/support/fields_spec.rb @@ -1,7 +1,11 @@ require 'spec_helper' describe NetSuite::Support::Fields do - let(:klass) { Class.new.send(:include, NetSuite::Support::Fields) } + let(:klass) do + Class.new do + include NetSuite::Support::Fields + end + end let(:instance) { klass.new } describe '.fields' do @@ -29,6 +33,23 @@ instance.one = 1 expect(instance.one).to eql(1) 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 @@ -57,4 +78,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 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 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/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 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 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 + + + + + + + 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. + + + + + + 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 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. + + + + + + + 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 + + + + + + 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 + + + + + + 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 + + + + + + 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/fixtures/search/saved_search_joined_custom_customer.xml b/spec/support/fixtures/search/saved_search_joined_custom_customer.xml index 490270e97..22d47550d 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 @@ -37,6 +43,14 @@ 444-444-4444 + + + sample string value + + + + + @@ -84,4 +98,4 @@ - \ No newline at end of file + 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 + + + + + + + + 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