Browse Source

Merge pull request #415 from Shopify/inventory_api

add inventory api
Jon G 7 years ago
parent
commit
3a9c0def95

+ 6 - 0
lib/shopify_api/resources/inventory_item.rb

@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module ShopifyAPI
+  class InventoryItem < Base
+  end
+end

+ 55 - 0
lib/shopify_api/resources/inventory_level.rb

@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module ShopifyAPI
+  class InventoryLevel < Base
+
+    # The default path structure in ActiveResource for delete would result in:
+    # /admin/inventory_levels/#{ inventory_level.id }.json?#{ params }, but since
+    # InventroyLevels are a second class resource made up of a Where and a What
+    # (Location and InventoryItem), it does not have a resource ID. Here we
+    # redefine element_path to remove the id so HTTP DELETE requests go to
+    # /admin/inventory_levels.json?#{ params } instead.
+    #
+    def self.element_path(prefix_options = {}, query_options = nil)
+      prefix_options, query_options = split_options(prefix_options) if query_options.nil?
+      "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
+    end
+
+    def destroy
+      load_attributes_from_response(
+        self.class.delete('/', location_id: location_id, inventory_item_id: inventory_item_id)
+      )
+    end
+
+    def connect(relocate_if_necessary: nil)
+      body = { location_id: location_id, inventory_item_id: inventory_item_id }
+      body[:relocate_if_necessary] = relocate_if_necessary unless relocate_if_necessary.nil?
+      load_attributes_from_response(
+        self.class.post(:connect, {}, body.to_json)
+      )
+    end
+
+    def set(new_available, disconnect_if_necessary: nil)
+      body = {
+        location_id: location_id,
+        inventory_item_id: inventory_item_id,
+        available: new_available
+      }
+      body[:disconnect_if_necessary] = disconnect_if_necessary unless disconnect_if_necessary.nil?
+      load_attributes_from_response(
+        self.class.post(:set, {}, body.to_json)
+      )
+    end
+
+    def adjust(available_adjustment)
+      body = {
+        location_id: location_id,
+        inventory_item_id: inventory_item_id,
+        available_adjustment: available_adjustment
+      }
+      load_attributes_from_response(
+        self.class.post(:adjust, {}, body.to_json)
+      )
+    end
+  end
+end

+ 4 - 0
lib/shopify_api/resources/location.rb

@@ -1,4 +1,8 @@
 module ShopifyAPI
   class Location < Base
+
+    def inventory_levels
+      ShopifyAPI::InventoryLevel.find(:all, from: "/admin/locations/#{id}/inventory_levels.json")
+    end
   end
 end

+ 7 - 0
test/fixtures/inventory_level.json

@@ -0,0 +1,7 @@
+{
+  "inventory_level" : {
+      "inventory_item_id": 808950810,
+      "location_id": 905684977,
+      "available": 1
+  }
+}

+ 24 - 0
test/fixtures/inventory_levels.json

@@ -0,0 +1,24 @@
+{
+  "inventory_levels": [
+    {
+      "inventory_item_id": 39072856,
+      "location_id": 487838322,
+      "available": 27
+    },
+    {
+      "inventory_item_id": 808950810,
+      "location_id": 905684977,
+      "available": 1
+    },
+    {
+      "inventory_item_id": 808950810,
+      "location_id": 487838322,
+      "available": 9
+    },
+    {
+      "inventory_item_id": 39072856,
+      "location_id": 905684977,
+      "available": 3
+    }
+  ]
+}

+ 59 - 0
test/inventory_level_test.rb

@@ -0,0 +1,59 @@
+require 'test_helper'
+
+class InventoryLevelTest < Test::Unit::TestCase
+  def setup
+    super
+    @inventory_level_response = ActiveSupport::JSON.decode load_fixture('inventory_level')
+    @inventory_level = ShopifyAPI::InventoryLevel.new(@inventory_level_response['inventory_level'])
+  end
+
+  test ".find with inventory_item_ids and location_ids returns expected inventory levels" do
+    params = { inventory_item_ids: [808950810, 39072856], location_ids: [905684977, 487838322] }
+    fake "inventory_levels.json?#{params.to_param}", extension: false, method: :get,
+          status: 200, body: load_fixture('inventory_levels')
+    inventory_levels = ShopifyAPI::InventoryLevel.find(:all, params: params)
+
+    assert inventory_levels.all? { |item|
+      params[:location_ids].include?(item.location_id) &&
+      params[:inventory_item_ids].include?(item.inventory_item_id)
+    }, message: 'Response contained inventory_items or locations not requested.'
+  end
+
+  test '#adjust with adjustment value returns inventory_level with available increased by adjustment value' do
+    adjustment = 5
+    updated_available = @inventory_level.available + adjustment
+    @inventory_level_response[:available] = updated_available
+
+    fake 'inventory_levels/adjust', method: :post, body: ActiveSupport::JSON.encode(@inventory_level_response)
+    @inventory_level.adjust(adjustment)
+    assert_equal updated_available, @inventory_level.available
+  end
+
+  test '#connect saves an inventory_level associated with inventory_item and location_id' do
+    params = { inventory_item_id: 808950810, location_id: 99999999 }
+    response = params.clone
+    response[:available] = 0
+
+    fake 'inventory_levels/connect', method: :post, body: ActiveSupport::JSON.encode(response)
+    inventory_level = ShopifyAPI::InventoryLevel.new(params)
+    inventory_level.connect
+    assert_equal 0, inventory_level.available, message: 'expected newly connected location to have 0 inventory'
+  end
+
+  test '#destroy removes inventory_level and returns nil' do
+    params = { inventory_item_id: @inventory_level.inventory_item_id, location_id: @inventory_level.location_id }
+    fake "inventory_levels.json?#{params.to_param}", extension: false, method: :delete, status: 204, body: nil
+    assert_nil @inventory_level.destroy
+  end
+
+  test '#set with available value returns inventory_level with available as the available value' do
+    available = 13
+    response = @inventory_level_response.clone
+    response['inventory_level']['available'] = available
+
+    fake 'inventory_levels/set', method: :post, body: ActiveSupport::JSON.encode(response)
+    @inventory_level.set(available)
+
+    assert_equal available, @inventory_level.available
+  end
+end

+ 14 - 0
test/location_test.rb

@@ -0,0 +1,14 @@
+require 'test_helper'
+
+class LocationTest < Test::Unit::TestCase
+  test '#inventory_levels returns all inventory_levels associated with this location' do
+    location = ShopifyAPI::Location.new(id: 487838322)
+    expected_body = JSON.parse(load_fixture('inventory_levels'))
+    expected_body['inventory_levels'].delete_if {|level| level['location_id'] != location.id }
+    fake "locations/#{location.id}/inventory_levels", method: :get, status: 200, body: JSON(expected_body).to_s
+    inventory_levels = location.inventory_levels
+
+    assert inventory_levels.all? { |item| item.location_id == location.id },
+           message: 'Response contained locations other than the current location.'
+  end
+end