From cf6ae36f7676568818c279d484e070c5508efbd4 Mon Sep 17 00:00:00 2001
From: mage2-team <mage2-team@magento.com>
Date: Fri, 4 Jul 2014 09:44:52 -0700
Subject: [PATCH] 2.0.0.0-dev85 * Service layer updates:   * Implemented API
 for the CatalogInventory module   * Refactored the external usages of the
 CatalogInventory module to service * Fixed bugs:   * Fixed an issue where a
 coupon usage option was not comprehensible enough   * Fixed an issue where
 products selection for adding to a bundle option was lost when switching
 between pages with product grids   * Fixed an issue where  Google Content was
 not sending the correct 'description' attribute   * Fixed an issue where
 custom attributes were not displayed in layered navigation after a product
 import   * Fixed an issue where the Category URL keys did not work correctly
 after saving   * Fixed an issue where an admin could not create a Target rule
 with a certain Products to Display condition   * Fixed a jQuery error on a
 product page in the Admin panel, which appeared when switching between
 product tabs * Framework Improvements:   * Created ProductsCustomOptions
 Service API for Catalog module   * Created DownloadableLink Service API for
 Catalog module * GitHub requests:   * [#257] JSON loading should follow OWASP
 recommendation

---
 CHANGELOG.md                                  |  19 +
 .../Controller/Adminhtml/Notification.php     |   2 +-
 .../Controller/Adminhtml/Survey.php           |   2 +-
 .../Controller/Adminhtml/System/Message.php   |   5 +-
 .../Authorizenet/Directpost/Payment.php       |  11 +-
 .../Adminhtml/Authorizenet/Payment.php        |   4 +-
 .../Controller/Authorizenet/Payment.php       |   4 +-
 .../Controller/Directpost/Payment.php         |   6 +-
 .../Model/Directpost/Observer.php             |   2 +-
 .../Magento/Backend/App/AbstractAction.php    |   2 +-
 .../Backend/Controller/Adminhtml/Ajax.php     |   2 +-
 .../Backend/Controller/Adminhtml/Auth.php     |   2 +-
 .../Backend/Controller/Adminhtml/Index.php    |   5 +-
 .../System/Config/System/Storage.php          |   2 +-
 .../Controller/Adminhtml/System/Variable.php  |   4 +-
 .../Controller/Adminhtml/Urlrewrite.php       |   2 +-
 .../templates/page/js/components.phtml        |   3 +
 .../Backup/Controller/Adminhtml/Index.php     |  10 +-
 .../Adminhtml/Sales/Order/Items/Renderer.php  |  52 +-
 .../Sales/Order/View/Items/Renderer.php       |  44 +-
 .../Magento/Bundle/Model/Product/Type.php     |   5 +
 .../view/adminhtml/web/js/bundle-product.js   |   2 +
 .../Captcha/Controller/Adminhtml/Refresh.php  |   2 +-
 .../Magento/Captcha/Controller/Refresh.php    |   2 +-
 app/code/Magento/Captcha/Model/Observer.php   |   4 +-
 .../Adminhtml/Product/Edit/Tab/Inventory.php  |  73 ++-
 .../Catalog/Block/Product/AbstractProduct.php |   2 +-
 .../Magento/Catalog/Block/Product/Context.php |   8 +-
 .../Catalog/Controller/Adminhtml/Category.php |  11 +-
 .../Controller/Adminhtml/Category/Widget.php  |   2 +-
 .../Catalog/Controller/Adminhtml/Product.php  |  10 +-
 .../Adminhtml/Product/Action/Attribute.php    |  41 +-
 .../Adminhtml/Product/Attribute.php           |   2 +-
 .../Controller/Adminhtml/Product/Gallery.php  |   4 +-
 .../Controller/Adminhtml/Product/Set.php      |   4 +-
 .../Catalog/Helper/Product/Inventory.php      | 114 +++++
 .../Magento/Catalog/Model/Indexer/Url.php     |   2 +-
 app/code/Magento/Catalog/Model/Product.php    |   4 +-
 .../Model/Product/Attribute/Backend/Stock.php |  17 +-
 .../Magento/Catalog/Model/Product/Option.php  |  23 +-
 .../Option/Validator/DefaultValidator.php     | 163 ++++++
 .../Model/Product/Option/Validator/File.php   |  42 ++
 .../Model/Product/Option/Validator/Pool.php   |  52 ++
 .../Model/Product/Option/Validator/Select.php |  75 +++
 .../Model/Product/Option/Validator/Text.php   |  42 ++
 .../Collection/AbstractCollection.php         |   4 +-
 .../Resource/Product/Indexer/Eav/Source.php   |  16 +-
 app/code/Magento/Catalog/Model/Url.php        |  43 +-
 .../Catalog/Service/V1/Data/Converter.php     |   1 -
 .../V1/Product/CustomOptions/Data/Option.php  |  96 ++++
 .../CustomOptions/Data/Option/Converter.php   |  62 +++
 .../CustomOptions/Data/Option/Metadata.php    |  69 +++
 .../Option/Metadata/Converter/Composite.php   |  53 ++
 .../Metadata/Converter/DefaultConverter.php   |  53 ++
 .../Data/Option/Metadata/Converter/Select.php |  53 ++
 .../Option/Metadata/ConverterInterface.php    |  36 ++
 .../Data/Option/Metadata/Reader.php           |  56 +++
 .../Option/Metadata/Reader/DefaultReader.php  |  72 +++
 .../Data/Option/Metadata/Reader/File.php      |  42 ++
 .../Data/Option/Metadata/Reader/Select.php    |  66 +++
 .../Data/Option/Metadata/Reader/Text.php      |  38 ++
 .../Data/Option/Metadata/ReaderInterface.php  |  36 ++
 .../Data/Option/MetadataBuilder.php           |  98 ++++
 .../CustomOptions/Data/OptionBuilder.php      |  94 ++++
 .../Product/CustomOptions/Data/OptionType.php |  62 +++
 .../CustomOptions/Data/OptionTypeBuilder.php  |  61 +++
 .../V1/Product/CustomOptions/ReadService.php  | 146 ++++++
 .../CustomOptions/ReadServiceInterface.php    |  54 ++
 .../V1/Product/CustomOptions/WriteService.php | 211 ++++++++
 .../CustomOptions/WriteServiceInterface.php   |  62 +++
 app/code/Magento/Catalog/etc/di.xml           |  43 ++
 app/code/Magento/Catalog/etc/webapi.xml       |  36 ++
 .../catalog/product/tab/inventory.phtml       |   5 +-
 .../templates/product/edit/tabs.phtml         |   9 +-
 .../Model/Export/Product.php                  | 162 +++---
 .../Model/Import/Product.php                  | 145 +++---
 .../CatalogImportExport/etc/module.xml        |   2 +
 .../CatalogInventory/Block/Qtyincrements.php  |   6 +-
 .../Block/Stockqty/AbstractStockqty.php       |   6 +-
 .../Magento/CatalogInventory/Helper/Data.php  |   3 +-
 .../CatalogInventory/Helper/Minsaleqty.php    |  52 +-
 .../CatalogInventory/Model/Observer.php       | 156 +++---
 .../CopyConstructor/CatalogInventory.php      |  37 +-
 .../Model/Quote/Item/QuantityValidator.php    |  18 +-
 .../QuantityValidator/Initializer/Option.php  |  58 ++-
 .../CatalogInventory/Model/Resource/Stock.php |   6 +-
 .../Model/Resource/Stock/Item.php             |   2 +-
 .../Model/Resource/Stock/Status.php           |  62 +--
 .../Resource/Stock/Status/Collection.php      |  81 +++
 .../Magento/CatalogInventory/Model/Stock.php  |  55 ++-
 .../CatalogInventory/Model/Stock/Item.php     |  54 +-
 .../Model/Stock/ItemRegistry.php              |  12 +-
 .../CatalogInventory/Model/Stock/Status.php   |   6 -
 .../Service/V1/Data/LowStockCriteria.php      |  68 +++
 .../V1/Data/LowStockCriteriaBuilder.php       |  63 +++
 .../Service/V1/Data/LowStockResult.php        |  70 +++
 .../Service/V1/Data/LowStockResultBuilder.php |  63 +++
 .../Service/V1/Data/StockItemDetails.php      | 176 +++++++
 .../V1/Data/StockItemDetailsBuilder.php       | 158 ++++++
 .../Service/V1/Data/StockStatus.php           |  57 +++
 .../Service/V1/Data/StockStatusBuilder.php    |  33 ++
 .../{StockItem.php => StockItemService.php}   | 140 ++----
 ...face.php => StockItemServiceInterface.php} |  67 +--
 .../Service/V1/StockStatusService.php         | 131 ++++-
 .../V1/StockStatusServiceInterface.php        |  19 +-
 app/code/Magento/CatalogInventory/etc/di.xml  |   1 +
 .../Magento/CatalogInventory/etc/events.xml   |   3 -
 .../Magento/CatalogInventory/etc/webapi.xml   |  53 ++
 .../Controller/Adminhtml/Promo/Widget.php     |   2 +-
 .../Magento/CatalogSearch/Controller/Ajax.php |   2 +-
 .../Controller/Adminhtml/Centinel/Index.php   |   4 +-
 .../Magento/Checkout/Controller/Onepage.php   |  28 +-
 app/code/Magento/Checkout/Model/Cart.php      |   6 +-
 .../Controller/Adminhtml/Wysiwyg/Images.php   |  26 +-
 .../Product/Edit/Tab/Super/Config/Matrix.php  |  17 +
 .../SuggestConfigurableAttributes.php         |   2 +-
 .../Option/Plugin/ConfigurableProduct.php     |  15 +-
 .../catalog/product/edit/super/matrix.phtml   |   2 +-
 .../Customer/Controller/Adminhtml/Index.php   |   2 +-
 .../Adminhtml/System/Config/Validatevat.php   |   2 +-
 .../Adminhtml/System/Design/Editor.php        |  13 +-
 .../Adminhtml/System/Design/Editor/Files.php  |  10 +-
 .../Adminhtml/System/Design/Editor/Tools.php  |  44 +-
 app/code/Magento/Dhl/Model/Carrier.php        | 292 +++++------
 app/code/Magento/Dhl/etc/module.xml           |   1 +
 .../Directory/Controller/Adminhtml/Json.php   |   4 +-
 .../Adminhtml/Downloadable/File.php           |   4 +-
 .../Downloadable/Model/Product/Type.php       |   2 +
 .../Service/V1/Data/FileContent.php           |  52 ++
 .../Service/V1/Data/FileContentBuilder.php    |  51 ++
 .../Service/V1/Data/FileContentUploader.php   | 167 +++++++
 .../V1/Data/FileContentUploaderInterface.php  |  37 ++
 .../Service/V1/Data/FileContentValidator.php  |  65 +++
 .../Data/DownloadableLinkContent.php          | 153 ++++++
 .../Data/DownloadableLinkContentBuilder.php   | 153 ++++++
 .../Data/DownloadableLinkContentValidator.php | 120 +++++
 .../Data/DownloadableLinkInfo.php             | 130 +++++
 .../Data/DownloadableLinkInfoBuilder.php      | 111 +++++
 .../Data/DownloadableResourceInfo.php         |  66 +++
 .../Data/DownloadableResourceInfoBuilder.php  |  70 +++
 .../Data/DownloadableSampleInfo.php           |  78 +++
 .../Data/DownloadableSampleInfoBuilder.php    |  69 +++
 .../V1/DownloadableLink/ReadService.php       | 177 +++++++
 .../DownloadableLink/ReadServiceInterface.php |  44 ++
 .../V1/DownloadableLink/WriteService.php      | 200 ++++++++
 .../WriteServiceInterface.php                 |  60 +++
 .../Data/DownloadableSampleContent.php        |  86 ++++
 .../Data/DownloadableSampleContentBuilder.php |  87 ++++
 .../DownloadableSampleContentValidator.php    |  94 ++++
 .../V1/DownloadableSample/WriteService.php    | 188 +++++++
 .../WriteServiceInterface.php                 |  65 +++
 app/code/Magento/Downloadable/etc/di.xml      |   4 +
 app/code/Magento/Downloadable/etc/webapi.xml  |  76 +++
 .../Entity/Collection/AbstractCollection.php  |   4 +-
 .../Controller/Adminhtml/Email/Template.php   |   2 +-
 app/code/Magento/Fedex/Model/Carrier.php      |   3 +
 app/code/Magento/Fedex/etc/module.xml         |   1 +
 .../Adminhtml/Googleshopping/Items.php        |   8 +-
 .../Model/Attribute/Content.php               |   2 +-
 .../Model/Product/Type/Grouped.php            |  11 +
 .../Controller/Adminhtml/Integration.php      |   6 +-
 app/code/Magento/Paypal/Model/Observer.php    |   2 +-
 .../Block/Adminhtml/Payment/View/Items.php    |   3 +-
 .../Resource/Product/Lowstock/Collection.php  |   6 +-
 .../Review/Controller/Adminhtml/Product.php   |   2 +-
 .../Model/Condition/AbstractCondition.php     |   2 +-
 .../Condition/Product/AbstractProduct.php     |   9 +
 .../Block/Adminhtml/Items/AbstractItems.php   |  75 ++-
 .../Items/Renderer/DefaultRenderer.php        |   2 -
 .../Adminhtml/Order/Create/Items/Grid.php     |  85 ++--
 .../Order/Creditmemo/Create/Items.php         |  40 +-
 .../Adminhtml/Order/Creditmemo/View/Items.php |   2 -
 .../Adminhtml/Order/Invoice/Create/Items.php  |  14 +-
 .../Adminhtml/Order/Invoice/View/Items.php    |   2 -
 .../Block/Adminhtml/Order/View/Items.php      |   2 -
 .../View/Items/Renderer/DefaultRenderer.php   |  25 +-
 .../Magento/Sales/Block/Reorder/Sidebar.php   |  56 ++-
 .../Sales/Controller/Adminhtml/Order.php      |   2 +-
 .../Controller/Adminhtml/Order/Creditmemo.php |  22 +-
 .../Controller/Adminhtml/Order/Invoice.php    |  20 +-
 .../Magento/Sales/Model/AdminOrder/Create.php |  19 +-
 .../AdminOrder/Product/Quote/Initializer.php  |  19 +-
 .../Magento/Sales/Model/Convert/Quote.php     |  63 +--
 .../Magento/Sales/Model/Order/Creditmemo.php  |   2 +-
 app/code/Magento/Sales/Model/Quote.php        |  48 +-
 app/code/Magento/Sales/Model/Quote/Item.php   |  61 +--
 .../Adminhtml/Promo/Quote/Edit/Tab/Main.php   |   5 +-
 .../Controller/Adminhtml/Promo/Quote.php      |   4 +-
 .../Shipping/Block/Adminhtml/Create/Items.php |   8 +-
 .../Shipping/Block/Adminhtml/View/Items.php   |   5 +-
 .../Controller/Adminhtml/Order/Shipment.php   |  28 +-
 .../Model/Carrier/AbstractCarrierOnline.php   |  26 +-
 app/code/Magento/Shipping/Model/Shipping.php  |  42 +-
 .../Shipping/Model/Shipping/Labels.php        |   5 +-
 app/code/Magento/Shipping/etc/module.xml      |   1 +
 .../Magento/Tax/Controller/Adminhtml/Rate.php |   4 +-
 .../Magento/Tax/Controller/Adminhtml/Tax.php  |   4 +-
 .../Adminhtml/System/Design/Theme.php         |   8 +-
 .../Adminhtml/System/Design/Wysiwyg/Files.php |  26 +-
 .../Theme/view/frontend/layout/print.xml      |   7 +-
 .../Magento/Translation/Controller/Ajax.php   |   3 +-
 app/code/Magento/Ups/Model/Carrier.php        |   3 +
 app/code/Magento/Ups/etc/module.xml           |   1 +
 .../User/Controller/Adminhtml/User.php        |   2 +-
 app/code/Magento/Usps/Model/Carrier.php       |   3 +
 app/code/Magento/Usps/etc/module.xml          |   1 +
 .../Webapi/Controller/ErrorProcessor.php      |   2 +-
 .../Magento/Webapi/Model/PathProcessor.php    |   1 +
 app/code/Magento/Webapi/Model/Rest/Config.php |  26 +-
 .../Widget/Controller/Adminhtml/Widget.php    |   4 +-
 .../Controller/Adminhtml/Widget/Instance.php  |   4 +-
 .../Block/Adminhtml/Product/ProductForm.php   |   2 +-
 .../Test/Block/Backend/ProductForm.php        |   2 +-
 .../Catalog/Helper/Product/CompareTest.php    |  41 +-
 .../Model/Product/Type/AbstractTest.php       |   3 +
 .../Magento/Catalog/_files/categories.php     | 464 ++++++------------
 .../Catalog/_files/multiple_products.php      | 182 +++----
 .../Magento/Catalog/_files/product_simple.php |   4 -
 .../Catalog/_files/product_special_price.php  |  44 +-
 .../Catalog/_files/product_virtual.php        |  32 +-
 .../Catalog/_files/product_with_options.php   | 151 +++++-
 .../_files/product_with_options_rollback.php  |  39 ++
 .../_files/product_without_options.php        |  51 ++
 .../product_without_options_rollback.php      |  39 ++
 .../Model/Import/ProductTest.php              |  48 +-
 .../_files/products_multiple_stores.csv       |   6 +
 .../quote_with_downloadable_product.php       |   2 +-
 .../Model/Product/Type/ConfigurableTest.php   |  13 +-
 .../_files/configurable_attribute.php         |  66 +++
 .../_files/product_configurable.php           |  39 +-
 .../Magento/Customer/_files/customer.php      |  40 +-
 .../Downloadable/Controller/ProductTest.php   |   2 +-
 .../Downloadable/Model/Product/TypeTest.php   |   2 +-
 .../{product.php => product_downloadable.php} |   0
 .../_files/product_downloadable_rollback.php  |  24 +
 ...hp => product_downloadable_with_files.php} |   0
 ...oduct_downloadable_with_files_rollback.php |  24 +
 .../Sales/Model/AdminOrder/CreateTest.php     |   6 +-
 .../Magento/Sales/_files/order_info.php       |  31 +-
 .../Model/Sales/Total/Quote/SubtotalTest.php  |   1 +
 .../Test/Legacy/_files/obsolete_methods.php   |  30 ++
 .../Legacy/_files/obsolete_properties.php     |   1 +
 .../Model/Directpost/ObserverTest.php         |   2 +-
 .../Adminhtml/Category/WidgetTest.php         |   2 +-
 .../Product/Attribute/Backend/StockTest.php   |  68 ++-
 .../Option/Validator/DefaultValidatorTest.php | 112 +++++
 .../Product/Option/Validator/FileTest.php     | 115 +++++
 .../Product/Option/Validator/PoolTest.php     |  66 +++
 .../Product/Option/Validator/SelectTest.php   | 178 +++++++
 .../Product/Option/Validator/TextTest.php     |  98 ++++
 .../Product/Indexer/Eav/SourceTest.php        | 132 -----
 .../Magento/Catalog/Model/UrlTest.php         | 264 +++++++++-
 .../Data/Option/ConverterTest.php             |  79 +++
 .../Metadata/Converter/CompositeTest.php      | 106 ++++
 .../Converter/DefaultConverterTest.php        | 108 ++++
 .../Option/Metadata/Converter/SelectTest.php  |  99 ++++
 .../Metadata/Reader/DefaultReaderTest.php     |  74 +++
 .../Option/Metadata/Reader/SelectTest.php     |  89 ++++
 .../Data/Option/Metadata/ReaderTest.php       |  80 +++
 .../Product/CustomOptions/ReadServiceTest.php | 181 +++++++
 .../CustomOptions/WriteServiceTest.php        | 402 +++++++++++++++
 .../Block/QtyincrementsTest.php               |  10 +-
 .../Block/Stockqty/DefaultStockqtyTest.php    |  10 +-
 .../CatalogInventory/Helper/DataTest.php      | 112 +++++
 .../Helper/MinsaleqtyTest.php                 | 164 +++++++
 .../CatalogInventory/Model/ObserverTest.php   | 197 ++++++++
 .../CopyConstructor/CatalogInventoryTest.php  |  97 ++--
 .../Initializer/OptionTest.php                |  83 +++-
 .../Resource/Stock/Status/CollectionTest.php  | 103 ++++
 .../CatalogInventory/Model/Stock/ItemTest.php |  34 +-
 .../CatalogInventory/Model/StockTest.php      | 205 ++++++++
 ...kItemTest.php => StockItemServiceTest.php} | 395 ++++++++++-----
 .../Service/V1/StockStatusServiceTest.php     | 323 +++++++++++-
 .../Magento/Checkout/Model/CartTest.php       |  10 +-
 .../SuggestConfigurableAttributesTest.php     |   2 +-
 .../Option/Plugin/ConfigurableProductTest.php |  23 +-
 .../V1/Data/FileContentValidatorTest.php      | 117 +++++
 .../DownloadableLinkContentValidatorTest.php  | 261 ++++++++++
 .../V1/DownloadableLink/ReadServiceTest.php   | 302 ++++++++++++
 .../V1/DownloadableLink/WriteServiceTest.php  | 347 +++++++++++++
 ...DownloadableSampleContentValidatorTest.php | 155 ++++++
 .../DownloadableSample/WriteServiceTest.php   | 313 ++++++++++++
 .../Framework/App/Response/HttpTest.php       |  11 +
 .../Model/Attribute/ContentTest.php           | 135 +++++
 .../Controller/Adminhtml/IntegrationTest.php  |   2 +-
 .../Rule/Model/Condition/CombineTest.php      |  68 +++
 .../Adminhtml/Items/AbstractItemsTest.php     | 259 ++++++++--
 .../Adminhtml/Order/Create/Items/GridTest.php | 151 +++---
 .../Order/Creditmemo/Create/ItemsTest.php     | 160 ++++++
 .../Sales/Block/Reorder/SidebarTest.php       |  97 +++-
 .../Product/Quote/InitializerTest.php         | 223 +++++++++
 .../Quote/Address/Total/SubtotalTest.php      |  31 +-
 .../Magento/Sales/Model/Quote/ItemTest.php    |  43 +-
 .../Carrier/AbstractCarrierOnlineTest.php     | 117 +++++
 .../Magento/Shipping/Model/ShippingTest.php   | 119 +++++
 lib/internal/Magento/Framework/App/Http.php   |   7 +-
 .../Magento/Framework/App/Response/Http.php   |  12 +
 .../Magento/Framework/AppInterface.php        |   2 +-
 298 files changed, 14124 insertions(+), 2535 deletions(-)
 create mode 100644 app/code/Magento/Catalog/Helper/Product/Inventory.php
 create mode 100644 app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
 create mode 100644 app/code/Magento/Catalog/Model/Product/Option/Validator/File.php
 create mode 100644 app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
 create mode 100644 app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
 create mode 100644 app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Converter.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Composite.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverter.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Select.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ConverterInterface.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReader.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/File.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Select.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Text.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderInterface.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/MetadataBuilder.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionBuilder.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionType.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionTypeBuilder.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadService.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceInterface.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteService.php
 create mode 100644 app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceInterface.php
 create mode 100644 app/code/Magento/CatalogInventory/Model/Resource/Stock/Status/Collection.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteria.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteriaBuilder.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResult.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResultBuilder.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetails.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetailsBuilder.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/StockStatus.php
 create mode 100644 app/code/Magento/CatalogInventory/Service/V1/Data/StockStatusBuilder.php
 rename app/code/Magento/CatalogInventory/Service/V1/{StockItem.php => StockItemService.php} (75%)
 rename app/code/Magento/CatalogInventory/Service/V1/{StockItemInterface.php => StockItemServiceInterface.php} (73%)
 create mode 100644 app/code/Magento/CatalogInventory/etc/webapi.xml
 create mode 100644 app/code/Magento/Downloadable/Service/V1/Data/FileContent.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/Data/FileContentBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/Data/FileContentUploader.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/Data/FileContentUploaderInterface.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/Data/FileContentValidator.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContent.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidator.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfo.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfoBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfo.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfoBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfo.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfoBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadService.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceInterface.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteService.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceInterface.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContent.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentBuilder.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidator.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteService.php
 create mode 100644 app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceInterface.php
 create mode 100644 app/code/Magento/Downloadable/etc/webapi.xml
 create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options_rollback.php
 create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php
 create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options_rollback.php
 create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_multiple_stores.csv
 create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php
 rename dev/tests/integration/testsuite/Magento/Downloadable/_files/{product.php => product_downloadable.php} (100%)
 create mode 100644 dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_rollback.php
 rename dev/tests/integration/testsuite/Magento/Downloadable/_files/{product_with_files.php => product_downloadable_with_files.php} (100%)
 create mode 100644 dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files_rollback.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/DefaultValidatorTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/FileTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/PoolTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/SelectTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/TextTest.php
 delete mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Model/Resource/Product/Indexer/Eav/SourceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/ConverterTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/CompositeTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverterTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/SelectTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReaderTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/SelectTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/DataTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/MinsaleqtyTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/CatalogInventory/Model/ObserverTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Resource/Stock/Status/CollectionTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/CatalogInventory/Model/StockTest.php
 rename dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/{StockItemTest.php => StockItemServiceTest.php} (51%)
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/Data/FileContentValidatorTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidatorTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidatorTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/GoogleShopping/Model/Attribute/ContentTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Rule/Model/Condition/CombineTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/ItemsTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Sales/Model/AdminOrder/Product/Quote/InitializerTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Shipping/Model/Carrier/AbstractCarrierOnlineTest.php
 create mode 100644 dev/tests/unit/testsuite/Magento/Shipping/Model/ShippingTest.php

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd296367839..1ec149d4a95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+2.0.0.0-dev85
+=============
+* Service layer updates:
+  * Implemented API for the CatalogInventory module
+  * Refactored the external usages of the CatalogInventory module to service
+* Fixed bugs:
+  * Fixed an issue where a coupon usage option was not comprehensible enough
+  * Fixed an issue where products selection for adding to a bundle option was lost when switching between pages with product grids
+  * Fixed an issue where  Google Content was not sending the correct 'description' attribute
+  * Fixed an issue where custom attributes were not displayed in layered navigation after a product import
+  * Fixed an issue where the Category URL keys did not work correctly after saving
+  * Fixed an issue where an admin could not create a Target rule with a certain Products to Display condition
+  * Fixed a jQuery error on a product page in the Admin panel, which appeared when switching between product tabs
+* Framework Improvements:
+  * Created ProductsCustomOptions Service API for Catalog module
+  * Created DownloadableLink Service API for Catalog module
+* GitHub requests:
+  * [#257] JSON loading should follow OWASP recommendation
+
 2.0.0.0-dev84
 =============
 * Fixed bugs:
diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php
index 51a736542cc..1ea1f1c1741 100644
--- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php
+++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php
@@ -95,7 +95,7 @@ class Notification extends \Magento\Backend\App\AbstractAction
         } catch (\Exception $e) {
             $responseData['success'] = false;
         }
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->create('Magento\Core\Helper\Data')->jsonEncode($responseData)
         );
     }
diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php
index 29e66dce686..e41fb155f05 100644
--- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php
+++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php
@@ -40,7 +40,7 @@ class Survey extends \Magento\Backend\App\Action
         if ($this->getRequest()->getParam('isAjax', false)) {
             $this->_objectManager->get('Magento\AdminNotification\Model\Survey')->saveSurveyViewed(true);
         }
-        $this->getResponse()->setBody(\Zend_Json::encode(array('survey_decision_saved' => 1)));
+        $this->getResponse()->representJson(\Zend_Json::encode(array('survey_decision_saved' => 1)));
     }
 
     /**
diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message.php
index ae2f578fcef..d32a72c1061 100644
--- a/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message.php
+++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message.php
@@ -41,10 +41,7 @@ class Message extends \Magento\Backend\App\AbstractAction
         foreach ($messageCollection->getItems() as $item) {
             $result[] = array('severity' => $item->getSeverity(), 'text' => $item->getText());
         }
-        $this->getResponse()->setHeader(
-            'Content-Type',
-            'application/json'
-        )->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
         );
     }
diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment.php
index 6aafb88564b..c8d74de1e48 100644
--- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment.php
+++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment.php
@@ -170,11 +170,14 @@ class Payment extends \Magento\Sales\Controller\Adminhtml\Order\Create
                     'sales/order_create/'
                 );
             }
-
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         } else {
             $result = array('error_messages' => __('Please choose a payment method.'));
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -238,7 +241,7 @@ class Payment extends \Magento\Sales\Controller\Adminhtml\Order\Create
     public function returnQuoteAction()
     {
         $this->_returnQuote();
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array('success' => 1))
         );
     }
diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Payment.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Payment.php
index 8af1616b5a5..2ce624c8dfc 100644
--- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Payment.php
+++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Payment.php
@@ -84,6 +84,8 @@ class Payment extends \Magento\Backend\App\Action
         }
 
         $this->_sessionQuote->getQuote()->getPayment()->save();
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 }
diff --git a/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php b/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php
index e601ca8b7f0..708d048c5bd 100644
--- a/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php
+++ b/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php
@@ -76,6 +76,8 @@ class Payment extends \Magento\Framework\App\Action\Action
         }
 
         $this->_session->getQuote()->getPayment()->save();
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 }
diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php
index 8aa9a9938ad..0f1916b3c51 100644
--- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php
+++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php
@@ -207,7 +207,9 @@ class Payment extends \Magento\Framework\App\Action\Action
             );
         } else {
             $result = array('error_messages' => __('Please choose a payment method.'), 'goto_section' => 'payment');
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -219,7 +221,7 @@ class Payment extends \Magento\Framework\App\Action\Action
     public function returnQuoteAction()
     {
         $this->_returnCustomerQuote();
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array('success' => 1))
         );
     }
diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Observer.php b/app/code/Magento/Authorizenet/Model/Directpost/Observer.php
index 3b1efcc2ce3..06820ffd10b 100644
--- a/app/code/Magento/Authorizenet/Model/Directpost/Observer.php
+++ b/app/code/Magento/Authorizenet/Model/Directpost/Observer.php
@@ -137,7 +137,7 @@ class Observer
                     $result['directpost'] = array('fields' => $requestToAuthorizenet->getData());
 
                     $response->clearHeader('Location');
-                    $response->setBody($this->_coreData->jsonEncode($result));
+                    $response->representJson($this->_coreData->jsonEncode($result));
                 }
             }
         }
diff --git a/app/code/Magento/Backend/App/AbstractAction.php b/app/code/Magento/Backend/App/AbstractAction.php
index 80e53fe5608..9d533f7018a 100644
--- a/app/code/Magento/Backend/App/AbstractAction.php
+++ b/app/code/Magento/Backend/App/AbstractAction.php
@@ -280,7 +280,7 @@ abstract class AbstractAction extends \Magento\Framework\App\Action\Action
             $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true);
             $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
             if ($this->getRequest()->getQuery('isAjax', false) || $this->getRequest()->getQuery('ajax', false)) {
-                $this->getResponse()->setBody(
+                $this->getResponse()->representJson(
                     $this->_objectManager->get(
                         'Magento\Core\Helper\Data'
                     )->jsonEncode(
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php b/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php
index e89fa65b80b..d11fec390d7 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php
@@ -58,7 +58,7 @@ class Ajax extends Action
         } catch (\Exception $e) {
             $response = "{error:true,message:'" . $e->getMessage() . "'}";
         }
-        $this->getResponse()->setBody($response);
+        $this->getResponse()->representJson($response);
 
         $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
     }
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Auth.php b/app/code/Magento/Backend/Controller/Adminhtml/Auth.php
index a9a5c542608..a7ac7f33901 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Auth.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth.php
@@ -67,7 +67,7 @@ class Auth extends AbstractAction
      */
     public function deniedJsonAction()
     {
-        $this->getResponse()->setBody($this->_getDeniedJson());
+        $this->getResponse()->representJson($this->_getDeniedJson());
     }
 
     /**
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Index.php
index dac4abff50c..dd154d0dc1a 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Index.php
@@ -99,8 +99,9 @@ class Index extends AbstractAction
                 }
             }
         }
-
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($items));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($items)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Config/System/Storage.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Config/System/Storage.php
index a4110fbe5c0..ec91e6b4501 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Config/System/Storage.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Config/System/Storage.php
@@ -180,6 +180,6 @@ class Storage extends \Magento\Backend\App\Action
         }
         $result['state'] = $state;
         $result = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result);
-        $this->_response->setBody($result);
+        $this->_response->representJson($result);
     }
 }
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Variable.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Variable.php
index edcdb47925a..3c8a8e7e9d0 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Variable.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Variable.php
@@ -149,7 +149,7 @@ class Variable extends Action
             $response->setError(true);
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
@@ -223,7 +223,7 @@ class Variable extends Action
             true
         );
         $variables = array($storeContactVariabls, $customVariables);
-        $this->getResponse()->setBody(\Zend_Json::encode($variables));
+        $this->getResponse()->representJson(\Zend_Json::encode($variables));
     }
 
     /**
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php b/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php
index c330de76277..0020666a60f 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php
@@ -183,7 +183,7 @@ class Urlrewrite extends Action
     public function categoriesJsonAction()
     {
         $categoryId = $this->getRequest()->getParam('id', null);
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get(
                 'Magento\Backend\Block\Urlrewrite\Catalog\Category\Tree'
             )->getTreeArray(
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/page/js/components.phtml b/app/code/Magento/Backend/view/adminhtml/templates/page/js/components.phtml
index b1edc724bca..f53f3ca7514 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/page/js/components.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/page/js/components.phtml
@@ -99,6 +99,9 @@
             '<?php echo $this->getViewFileUrl('jquery/jstree/jquery.hotkeys.js') ?>',
             '<?php echo $this->getViewFileUrl('jquery/jstree/jquery.jstree.js') ?>',
             '<?php echo $this->getViewFileUrl('Magento_Catalog::js/category-tree.js') ?>'
+        ],
+        collapsible: [
+            '<?php echo $this->getViewFileUrl('mage/collapsible.js') ?>'
         ]
     })
     /**
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index.php
index 0bee25a1894..30e2108db14 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index.php
@@ -173,7 +173,7 @@ class Index extends \Magento\Backend\App\Action
                         . 'putting your store into maintenance mode."
                         )
                     );
-                    return $this->getResponse()->setBody($response->toJson());
+                    return $this->getResponse()->representJson($response->toJson());
                 }
             }
 
@@ -211,7 +211,7 @@ class Index extends \Magento\Backend\App\Action
             $this->maintenanceMode->turnOff();
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
@@ -308,7 +308,7 @@ class Index extends \Magento\Backend\App\Action
             if (!$passwordValid) {
                 $response->setError(__('Please correct the password.'));
                 $backupManager->setErrorMessage(__('Please correct the password.'));
-                return $this->getResponse()->setBody($response->toJson());
+                $this->getResponse()->representJson($response->toJson());
             }
 
             if ($this->getRequest()->getParam('maintenance_mode')) {
@@ -327,7 +327,7 @@ class Index extends \Magento\Backend\App\Action
                         . 'putting your store into maintenance mode."
                         )
                     );
-                    return $this->getResponse()->setBody($response->toJson());
+                    return $this->getResponse()->representJson($response->toJson());
                 }
             }
 
@@ -380,7 +380,7 @@ class Index extends \Magento\Backend\App\Action
             $this->maintenanceMode->turnOff();
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
index 804d3ecce63..9ff68dfb5cb 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
@@ -23,6 +23,8 @@
  */
 namespace Magento\Bundle\Block\Adminhtml\Sales\Order\Items;
 
+use Magento\Catalog\Model\Product\Type\AbstractType;
+
 /**
  * Adminhtml sales order item renderer
  */
@@ -56,11 +58,12 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
     {
         $itemsArray = array();
 
+        $items = false;
         if ($item instanceof \Magento\Sales\Model\Order\Invoice\Item) {
             $items = $item->getInvoice()->getAllItems();
-        } else if ($item instanceof \Magento\Sales\Model\Order\Shipment\Item) {
+        } elseif ($item instanceof \Magento\Sales\Model\Order\Shipment\Item) {
             $items = $item->getShipment()->getAllItems();
-        } else if ($item instanceof \Magento\Sales\Model\Order\Creditmemo\Item) {
+        } elseif ($item instanceof \Magento\Sales\Model\Order\Creditmemo\Item) {
             $items = $item->getCreditmemo()->getAllItems();
         }
 
@@ -96,11 +99,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
             if ($parentItem) {
                 $options = $parentItem->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['shipment_type']
-                    ) &&
-                        $options['shipment_type'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+                    if (isset($options['shipment_type'])
+                        && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
                     ) {
                         return true;
                     } else {
@@ -110,11 +110,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
             } else {
                 $options = $item->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['shipment_type']
-                    ) &&
-                        $options['shipment_type'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+                    if (isset($options['shipment_type'])
+                        && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
                     ) {
                         return false;
                     } else {
@@ -126,9 +123,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
 
         $options = $this->getOrderItem()->getProductOptions();
         if ($options) {
-            if (isset(
-                $options['shipment_type']
-            ) && $options['shipment_type'] == \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+            if (isset($options['shipment_type'])
+                && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
             ) {
                 return true;
             }
@@ -150,11 +146,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
             if ($parentItem) {
                 $options = $parentItem->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['product_calculations']
-                    ) &&
-                        $options['product_calculations'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+                    if (isset($options['product_calculations'])
+                        && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
                     ) {
                         return true;
                     } else {
@@ -164,11 +157,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
             } else {
                 $options = $item->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['product_calculations']
-                    ) &&
-                        $options['product_calculations'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+                    if (isset($options['product_calculations'])
+                        && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
                     ) {
                         return false;
                     } else {
@@ -180,9 +170,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
 
         $options = $this->getOrderItem()->getProductOptions();
         if ($options) {
-            if (isset(
-                $options['product_calculations']
-            ) && $options['product_calculations'] == \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+            if (isset($options['product_calculations'])
+                && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
             ) {
                 return true;
             }
@@ -208,10 +197,9 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
     }
 
     /**
-     * @param mixed $item
      * @return array
      */
-    public function getOrderOptions($item = null)
+    public function getOrderOptions()
     {
         $result = array();
         $options = $this->getOrderItem()->getProductOptions();
@@ -269,8 +257,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
      */
     public function canShowPriceInfo($item)
     {
-        if ($item->getOrderItem()->getParentItem() && $this->isChildCalculated() ||
-            !$item->getOrderItem()->getParentItem() && !$this->isChildCalculated()
+        if ($item->getOrderItem()->getParentItem() && $this->isChildCalculated()
+            || !$item->getOrderItem()->getParentItem() && !$this->isChildCalculated()
         ) {
             return true;
         }
diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
index e075233f623..070b02878a5 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
@@ -23,6 +23,8 @@
  */
 namespace Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items;
 
+use Magento\Catalog\Model\Product\Type\AbstractType;
+
 /**
  * Adminhtml sales order item renderer
  */
@@ -57,11 +59,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
             if ($parentItem) {
                 $options = $parentItem->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['shipment_type']
-                    ) &&
-                        $options['shipment_type'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+                    if (isset($options['shipment_type'])
+                        && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
                     ) {
                         return true;
                     } else {
@@ -71,11 +70,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
             } else {
                 $options = $item->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['shipment_type']
-                    ) &&
-                        $options['shipment_type'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+                    if (isset($options['shipment_type'])
+                        && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
                     ) {
                         return false;
                     } else {
@@ -87,9 +83,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
 
         $options = $this->getOrderItem()->getProductOptions();
         if ($options) {
-            if (isset(
-                $options['shipment_type']
-            ) && $options['shipment_type'] == \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
+            if (isset($options['shipment_type'])
+                && $options['shipment_type'] == AbstractType::SHIPMENT_SEPARATELY
             ) {
                 return true;
             }
@@ -108,11 +103,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
             if ($parentItem) {
                 $options = $parentItem->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['product_calculations']
-                    ) &&
-                        $options['product_calculations'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+                    if (isset($options['product_calculations'])
+                        && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
                     ) {
                         return true;
                     } else {
@@ -122,11 +114,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
             } else {
                 $options = $item->getProductOptions();
                 if ($options) {
-                    if (isset(
-                        $options['product_calculations']
-                    ) &&
-                        $options['product_calculations'] ==
-                        \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+                    if (isset($options['product_calculations'])
+                        && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
                     ) {
                         return false;
                     } else {
@@ -138,9 +127,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
 
         $options = $this->getItem()->getProductOptions();
         if ($options) {
-            if (isset(
-                $options['product_calculations']
-            ) && $options['product_calculations'] == \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
+            if (isset($options['product_calculations'])
+                && $options['product_calculations'] == AbstractType::CALCULATE_CHILD
             ) {
                 return true;
             }
@@ -214,8 +202,8 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
      */
     public function canShowPriceInfo($item)
     {
-        if ($item->getParentItem() && $this->isChildCalculated() ||
-            !$item->getParentItem() && !$this->isChildCalculated()
+        if ($item->getParentItem() && $this->isChildCalculated()
+            || !$item->getParentItem() && !$this->isChildCalculated()
         ) {
             return true;
         }
diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php
index 59202b3d80a..a7a700fd32c 100644
--- a/app/code/Magento/Bundle/Model/Product/Type.php
+++ b/app/code/Magento/Bundle/Model/Product/Type.php
@@ -356,6 +356,11 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
             );
             $product->unsetData('msrp');
             $product->unsetData('msrp_display_actual_price_type');
+
+            /** unset product custom options for dynamic price */
+            if ($product->hasData('product_options')) {
+                $product->unsetData('product_options');
+            }
         }
 
         $product->canAffectOptions(false);
diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js
index 78b2b5f9ee7..586738ab20a 100644
--- a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js
+++ b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js
@@ -91,6 +91,8 @@
                 bSelection.gridSelection.set(optionIndex, $H({}));
                 bSelection.gridRemoval = $H({});
                 bSelection.gridSelectedProductSkus = productSkus;
+
+                $selectionGrid.on('contentUpdated', bSelection.gridUpdateCallback);
                 $selectionGrid.on('change', '.col-id input', function () {//_on can't be used because of grid reloading
                     var tr = $(this).closest('tr');
                     if ($(this).is(':checked')) {
diff --git a/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php b/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php
index 744d4682092..9c7622334ae 100644
--- a/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php
+++ b/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php
@@ -47,7 +47,7 @@ class Refresh extends \Magento\Backend\App\Action
         )->setIsAjax(
             true
         )->toHtml();
-        $this->getResponse()->setBody(json_encode(array('imgSrc' => $captchaModel->getImgSrc())));
+        $this->getResponse()->representJson(json_encode(array('imgSrc' => $captchaModel->getImgSrc())));
         $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
     }
 }
diff --git a/app/code/Magento/Captcha/Controller/Refresh.php b/app/code/Magento/Captcha/Controller/Refresh.php
index 31955e40fe8..f505d6cd974 100644
--- a/app/code/Magento/Captcha/Controller/Refresh.php
+++ b/app/code/Magento/Captcha/Controller/Refresh.php
@@ -47,7 +47,7 @@ class Refresh extends \Magento\Framework\App\Action\Action
         )->setIsAjax(
             true
         )->toHtml();
-        $this->getResponse()->setBody(json_encode(array('imgSrc' => $captchaModel->getImgSrc())));
+        $this->getResponse()->representJson(json_encode(array('imgSrc' => $captchaModel->getImgSrc())));
         $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
     }
 }
diff --git a/app/code/Magento/Captcha/Model/Observer.php b/app/code/Magento/Captcha/Model/Observer.php
index 020d9334ff8..9704e53eebc 100644
--- a/app/code/Magento/Captcha/Model/Observer.php
+++ b/app/code/Magento/Captcha/Model/Observer.php
@@ -246,7 +246,7 @@ class Observer
                 if (!$captchaModel->isCorrect($this->_getCaptchaString($controller->getRequest(), $formId))) {
                     $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
                     $result = array('error' => 1, 'message' => __('Incorrect CAPTCHA'));
-                    $controller->getResponse()->setBody($this->_coreData->jsonEncode($result));
+                    $controller->getResponse()->representJson($this->_coreData->jsonEncode($result));
                 }
             }
         }
@@ -270,7 +270,7 @@ class Observer
                 if (!$captchaModel->isCorrect($this->_getCaptchaString($controller->getRequest(), $formId))) {
                     $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
                     $result = array('error' => 1, 'message' => __('Incorrect CAPTCHA'));
-                    $controller->getResponse()->setBody($this->_coreData->jsonEncode($result));
+                    $controller->getResponse()->representJson($this->_coreData->jsonEncode($result));
                 }
             }
         }
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
index 49e90dcd850..7db4980deaa 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
@@ -38,24 +38,34 @@ class Inventory extends \Magento\Backend\Block\Widget
      *
      * @var \Magento\Catalog\Helper\Data
      */
-    protected $_catalogData;
+    protected $catalogData;
 
     /**
      * Core registry
      *
      * @var \Magento\Framework\Registry
      */
-    protected $_coreRegistry;
+    protected $coreRegistry;
 
     /**
      * @var \Magento\CatalogInventory\Model\Source\Stock
      */
-    protected $_stock;
+    protected $stock;
 
     /**
      * @var \Magento\CatalogInventory\Model\Source\Backorders
      */
-    protected $_backorders;
+    protected $backorders;
+
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \Magento\Catalog\Helper\Product\Inventory
+     */
+    protected $inventoryHelper;
 
     /**
      * @param \Magento\Backend\Block\Template\Context $context
@@ -63,6 +73,8 @@ class Inventory extends \Magento\Backend\Block\Widget
      * @param \Magento\CatalogInventory\Model\Source\Stock $stock
      * @param \Magento\Catalog\Helper\Data $catalogData
      * @param \Magento\Framework\Registry $coreRegistry
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     * @param \Magento\Catalog\Helper\Product\Inventory $inventoryHelper
      * @param array $data
      */
     public function __construct(
@@ -71,12 +83,16 @@ class Inventory extends \Magento\Backend\Block\Widget
         \Magento\CatalogInventory\Model\Source\Stock $stock,
         \Magento\Catalog\Helper\Data $catalogData,
         \Magento\Framework\Registry $coreRegistry,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
+        \Magento\Catalog\Helper\Product\Inventory $inventoryHelper,
         array $data = array()
     ) {
-        $this->_stock = $stock;
-        $this->_backorders = $backorders;
-        $this->_catalogData = $catalogData;
-        $this->_coreRegistry = $coreRegistry;
+        $this->stock = $stock;
+        $this->backorders = $backorders;
+        $this->catalogData = $catalogData;
+        $this->coreRegistry = $coreRegistry;
+        $this->stockItemService = $stockItemService;
+        $this->inventoryHelper = $inventoryHelper;
         parent::__construct($context, $data);
     }
 
@@ -85,8 +101,8 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getBackordersOption()
     {
-        if ($this->_catalogData->isModuleEnabled('Magento_CatalogInventory')) {
-            return $this->_backorders->toOptionArray();
+        if ($this->catalogData->isModuleEnabled('Magento_CatalogInventory')) {
+            return $this->backorders->toOptionArray();
         }
 
         return array();
@@ -99,8 +115,8 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getStockOption()
     {
-        if ($this->_catalogData->isModuleEnabled('Magento_CatalogInventory')) {
-            return $this->_stock->toOptionArray();
+        if ($this->catalogData->isModuleEnabled('Magento_CatalogInventory')) {
+            return $this->stock->toOptionArray();
         }
 
         return array();
@@ -113,17 +129,17 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getProduct()
     {
-        return $this->_coreRegistry->registry('product');
+        return $this->coreRegistry->registry('product');
     }
 
     /**
      * Retrieve Catalog Inventory  Stock Item Model
      *
-     * @return \Magento\CatalogInventory\Model\Stock\Item
+     * @return \Magento\CatalogInventory\Service\V1\Data\StockItem
      */
-    public function getStockItem()
+    public function getStockItemDo()
     {
-        return $this->getProduct()->getStockItem();
+        return $this->stockItemService->getStockItem($this->getProduct()->getId());
     }
 
     /**
@@ -132,14 +148,7 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getFieldValue($field)
     {
-        if ($this->getStockItem()) {
-            return $this->getStockItem()->getDataUsingMethod($field);
-        }
-
-        return $this->_scopeConfig->getValue(
-            \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_ITEM . $field,
-            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-        );
+        return $this->inventoryHelper->getFieldValue($field, $this->getStockItemDo());
     }
 
     /**
@@ -148,16 +157,7 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getConfigFieldValue($field)
     {
-        if ($this->getStockItem()) {
-            if ($this->getStockItem()->getData('use_config_' . $field) == 0) {
-                return $this->getStockItem()->getData($field);
-            }
-        }
-
-        return $this->_scopeConfig->getValue(
-            \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_ITEM . $field,
-            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-        );
+        return $this->inventoryHelper->getConfigFieldValue($field, $this->getStockItemDo());
     }
 
     /**
@@ -166,10 +166,7 @@ class Inventory extends \Magento\Backend\Block\Widget
      */
     public function getDefaultConfigValue($field)
     {
-        return $this->_scopeConfig->getValue(
-            \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_ITEM . $field,
-            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-        );
+        return $this->inventoryHelper->getDefaultConfigValue($field);
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php
index 1ec50c29083..0e5cc16085e 100644
--- a/app/code/Magento/Catalog/Block/Product/AbstractProduct.php
+++ b/app/code/Magento/Catalog/Block/Product/AbstractProduct.php
@@ -137,7 +137,7 @@ abstract class AbstractProduct extends \Magento\Framework\View\Element\Template
     protected $reviewRenderer;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
diff --git a/app/code/Magento/Catalog/Block/Product/Context.php b/app/code/Magento/Catalog/Block/Product/Context.php
index 8f23e8f9b54..df1b21deceb 100644
--- a/app/code/Magento/Catalog/Block/Product/Context.php
+++ b/app/code/Magento/Catalog/Block/Product/Context.php
@@ -84,7 +84,7 @@ class Context extends \Magento\Framework\View\Element\Template\Context
     protected $reviewRenderer;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
@@ -123,7 +123,7 @@ class Context extends \Magento\Framework\View\Element\Template\Context
      * @param \Magento\Theme\Helper\Layout $layoutHelper
      * @param \Magento\Catalog\Helper\Image $imageHelper
      * @param ReviewRendererInterface $reviewRenderer
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
@@ -162,7 +162,7 @@ class Context extends \Magento\Framework\View\Element\Template\Context
         \Magento\Theme\Helper\Layout $layoutHelper,
         \Magento\Catalog\Helper\Image $imageHelper,
         ReviewRendererInterface $reviewRenderer,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
     ) {
         $this->imageHelper = $imageHelper;
         $this->layoutHelper = $layoutHelper;
@@ -204,7 +204,7 @@ class Context extends \Magento\Framework\View\Element\Template\Context
     }
 
     /**
-     * @return \Magento\CatalogInventory\Service\V1\StockItem
+     * @return \Magento\CatalogInventory\Service\V1\StockItemService
      */
     public function getStockItemService()
     {
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
index 82c523c7e25..e2b3ed29153 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
@@ -174,8 +174,7 @@ class Category extends \Magento\Backend\App\Action
                 'category_prepare_ajax_response',
                 array('response' => $eventResponse, 'controller' => $this)
             );
-            $this->getResponse()->setHeader('Content-type', 'application/json', true);
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($eventResponse->getData())
             );
             return;
@@ -246,7 +245,7 @@ class Category extends \Magento\Backend\App\Action
             if (!($category = $this->_initCategory())) {
                 return;
             }
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_view->getLayout()->createBlock(
                     'Magento\Catalog\Block\Adminhtml\Category\Tree'
                 )->getTreeJson(
@@ -512,7 +511,7 @@ class Category extends \Magento\Backend\App\Action
 
         $block = $this->_view->getLayout()->createBlock('Magento\Catalog\Block\Adminhtml\Category\Tree');
         $root = $block->getRoot();
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get(
                 'Magento\Core\Helper\Data'
             )->jsonEncode(
@@ -543,7 +542,7 @@ class Category extends \Magento\Backend\App\Action
         $categoryId = (int)$this->getRequest()->getParam('id');
         if ($categoryId) {
             $category = $this->_objectManager->create('Magento\Catalog\Model\Category')->load($categoryId);
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_objectManager->get(
                     'Magento\Core\Helper\Data'
                 )->jsonEncode(
@@ -560,7 +559,7 @@ class Category extends \Magento\Backend\App\Action
      */
     public function suggestCategoriesAction()
     {
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_view->getLayout()->createBlock(
                 'Magento\Catalog\Block\Adminhtml\Category\Tree'
             )->getSuggestedCategoriesJson(
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Widget.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Widget.php
index 584baa55b3b..72b8c542ec1 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Widget.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Widget.php
@@ -75,7 +75,7 @@ class Widget extends \Magento\Backend\App\Action
                 $this->_coreRegistry->register('current_category', $category);
             }
             $categoryTreeBlock = $this->_getCategoryTreeBlock()->setSelectedCategories(explode(',', $selected));
-            $this->getResponse()->setBody($categoryTreeBlock->getTreeJson($category));
+            $this->getResponse()->representJson($categoryTreeBlock->getTreeJson($category));
         }
     }
 
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product.php
index 590abfe6464..400d9c773e2 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product.php
@@ -521,7 +521,7 @@ class Product extends \Magento\Backend\App\Action
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
@@ -786,7 +786,7 @@ class Product extends \Magento\Backend\App\Action
     public function suggestProductTemplatesAction()
     {
         $this->productBuilder->build($this->getRequest());
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(
                 $this->_view->getLayout()->createBlock('Magento\Catalog\Block\Product\TemplateSelector')
                     ->getSuggestedTemplates($this->getRequest()->getParam('label_part'))
@@ -801,7 +801,7 @@ class Product extends \Magento\Backend\App\Action
      */
     public function suggestAttributesAction()
     {
-        $this->getResponse()->setBody(
+        $this->getResponse()->srepresentJson(
             $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(
                 $this->_view->getLayout()->createBlock(
                     'Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes\Search'
@@ -846,12 +846,12 @@ class Product extends \Magento\Backend\App\Action
                 ->setSortOrder('0')
                 ->save();
 
-            $this->getResponse()->setBody($attribute->toJson());
+            $this->getResponse()->representJson($attribute->toJson());
         } catch (\Exception $e) {
             $response = new \Magento\Framework\Object();
             $response->setError(false);
             $response->setMessage($e->getMessage());
-            $this->getResponse()->setBody($response->toJson());
+            $this->getResponse()->representJson($response->toJson());
         }
     }
 }
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute.php
index 102e33268f7..3b5b5442ccb 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute.php
@@ -47,25 +47,33 @@ class Attribute extends Action
      */
     protected $_catalogProduct;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder
+     */
+    protected $stockItemBuilder;
+
     /**
      * @param Action\Context $context
      * @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $helper
      * @param \Magento\Catalog\Model\Indexer\Product\Flat\Processor $productFlatIndexerProcessor
      * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $productPriceIndexerProcessor
      * @param \Magento\Catalog\Helper\Product $catalogProduct
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder $stockItemBuilder
      */
     public function __construct(
         Action\Context $context,
         \Magento\Catalog\Helper\Product\Edit\Action\Attribute $helper,
         \Magento\Catalog\Model\Indexer\Product\Flat\Processor $productFlatIndexerProcessor,
         \Magento\Catalog\Model\Indexer\Product\Price\Processor $productPriceIndexerProcessor,
-        \Magento\Catalog\Helper\Product $catalogProduct
+        \Magento\Catalog\Helper\Product $catalogProduct,
+        \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder $stockItemBuilder
     ) {
         parent::__construct($context);
         $this->_helper = $helper;
         $this->_productFlatIndexerProcessor = $productFlatIndexerProcessor;
         $this->_productPriceIndexerProcessor = $productPriceIndexerProcessor;
         $this->_catalogProduct = $catalogProduct;
+        $this->stockItemBuilder = $stockItemBuilder;
     }
 
     /**
@@ -148,31 +156,18 @@ class Attribute extends Action
                     ->updateAttributes($this->_helper->getProductIds(), $attributesData, $storeId);
             }
             if ($inventoryData) {
-                $stockItem = $this->_objectManager->create('Magento\CatalogInventory\Model\Stock\Item');
-                $stockItem->setProcessIndexEvents(false);
-                $stockItemSaved = false;
+                /** @var \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService */
+                $stockItemService = $this->_objectManager
+                    ->create('Magento\CatalogInventory\Service\V1\StockItemService');
 
                 foreach ($this->_helper->getProductIds() as $productId) {
-                    $stockItem->setData(array());
-                    $stockItem->loadByProduct($productId)->setProductId($productId);
-
-                    $stockDataChanged = false;
-                    foreach ($inventoryData as $k => $v) {
-                        $stockItem->setDataUsingMethod($k, $v);
-                        if ($stockItem->dataHasChangedFor($k)) {
-                            $stockDataChanged = true;
-                        }
-                    }
-                    if ($stockDataChanged) {
-                        $stockItem->save();
-                        $stockItemSaved = true;
+                    $stockItemDo = $stockItemService->getStockItem($productId);
+                    if (!$stockItemDo->getProductId()) {
+                        $inventoryData[] = $productId;
                     }
-                }
 
-                if ($stockItemSaved) {
-                    $this->_objectManager->get('Magento\Index\Model\Indexer')->indexEvents(
-                        \Magento\CatalogInventory\Model\Stock\Item::ENTITY,
-                        \Magento\Index\Model\Event::TYPE_SAVE
+                    $stockItemService->saveStockItem(
+                        $this->stockItemBuilder->mergeDataObjectWithArray($stockItemDo, $inventoryData)
                     );
                 }
             }
@@ -297,6 +292,6 @@ class Attribute extends Action
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 }
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php
index fa5614a851b..e4806b7a9fb 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php
@@ -229,7 +229,7 @@ class Attribute extends \Magento\Backend\App\Action
                 $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
             }
         }
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery.php
index 466320d9361..a8a3f1f448b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery.php
@@ -70,7 +70,9 @@ class Gallery extends \Magento\Backend\App\Action
             $result = array('error' => $e->getMessage(), 'errorcode' => $e->getCode());
         }
 
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set.php
index c7c3b595b8c..36ba0bd9f6a 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set.php
@@ -182,7 +182,7 @@ class Set extends \Magento\Backend\App\Action
                 )->jsonEncode(
                     array('messages' => $block->getGroupedHtml(), 'error' => $hasError, 'id' => $model->getId())
                 );
-                $this->getResponse()->setBody($body);
+                $this->getResponse()->representJson($body);
             } else {
                 if ($hasError) {
                     $this->_redirect('catalog/*/add');
@@ -200,7 +200,7 @@ class Set extends \Magento\Backend\App\Action
                 $response['error'] = 0;
                 $response['url'] = $this->getUrl('catalog/*/');
             }
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
             );
         }
diff --git a/app/code/Magento/Catalog/Helper/Product/Inventory.php b/app/code/Magento/Catalog/Helper/Product/Inventory.php
new file mode 100644
index 00000000000..71b013914d4
--- /dev/null
+++ b/app/code/Magento/Catalog/Helper/Product/Inventory.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Helper\Product;
+
+use \Magento\CatalogInventory\Service\V1\Data\StockItem;
+use Magento\Framework\App\Helper\Context;
+use \Magento\Framework\App\Config\ScopeConfigInterface;
+
+/**
+ * Catalog Product Inventory Helper
+ */
+class Inventory extends \Magento\Framework\App\Helper\AbstractHelper
+{
+    /**
+     * @var ScopeConfigInterface
+     */
+    protected $scopeConfig;
+
+    /**
+     * @param Context $context
+     * @param ScopeConfigInterface $scopeConfig
+     */
+    public function __construct(
+        Context $context,
+        ScopeConfigInterface $scopeConfig
+    ) {
+        $this->scopeConfig = $scopeConfig;
+        parent::__construct($context);
+    }
+
+    /**
+     * @param string $field
+     * @param StockItem $dataObject
+     * @return mixed
+     */
+    public function getFieldValue($field, StockItem $dataObject)
+    {
+        if ($dataObject->getStockId()) {
+            return $this->getDoFieldData($field, $dataObject);
+        }
+
+        return $this->getDefaultConfigValue($field);
+    }
+
+    /**
+     * @param string $field
+     * @param StockItem $dataObject
+     * @return mixed|null|string
+     */
+    public function getConfigFieldValue($field, StockItem $dataObject)
+    {
+        if ($dataObject->getStockId()) {
+            if ($this->getDoFieldData('use_config_' . $field, $dataObject) == 0) {
+                return $this->getDoFieldData($field, $dataObject);
+            }
+        }
+
+        return $this->getDefaultConfigValue($field);
+    }
+
+    /**
+     * @param string $field
+     * @return string|null
+     */
+    public function getDefaultConfigValue($field)
+    {
+        return $this->scopeConfig->getValue(
+            \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_ITEM . $field,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+    }
+
+    /**
+     * @param string $field
+     * @param StockItem $dataObject
+     * @return mixed
+     * @throws \BadMethodCallException
+     */
+    public function getDoFieldData($field, StockItem $dataObject)
+    {
+        $possibleMethods = array(
+            'get' . \Magento\Framework\Service\DataObjectConverter::snakeCaseToCamelCase($field),
+            'is' . \Magento\Framework\Service\DataObjectConverter::snakeCaseToCamelCase($field)
+        );
+
+        foreach ($possibleMethods as $method) {
+            if (method_exists($dataObject, $method)) {
+                return $dataObject->{$method}();
+            }
+        }
+        throw new \BadMethodCallException(__('Field "%1" was not found in DO "%2".', $field, get_class($dataObject)));
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Url.php b/app/code/Magento/Catalog/Model/Indexer/Url.php
index aa720e963b1..0a1dd8dc3a2 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Url.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Url.php
@@ -277,7 +277,7 @@ class Url extends \Magento\Index\Model\Indexer\AbstractIndexer
             $this->_catalogUrl->clearStoreInvalidRewrites();
             // Maybe some categories were moved
             foreach ($data['rewrite_category_ids'] as $categoryId) {
-                $this->_catalogUrl->refreshCategoryRewrite($categoryId);
+                $this->_catalogUrl->refreshCategoryRewrite($categoryId, null, true, true);
             }
         }
     }
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index 99317d82065..23aed6b0054 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -1440,9 +1440,7 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements IdentityIn
      */
     public function getAttributeText($attributeCode)
     {
-        return $this->getResource()->getAttribute(
-            $attributeCode
-        )->getSource()->getOptionText(
+        return $this->getResource()->getAttribute($attributeCode)->getSource()->getOptionText(
             $this->getData($attributeCode)
         );
     }
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
index f82734a2e95..f83fd3ae758 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
@@ -32,23 +32,23 @@ use Magento\Catalog\Model\Product;
 class Stock extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
 {
     /**
-     * Stock item factory
+     * Stock item service
      *
-     * @var \Magento\CatalogInventory\Model\Stock\ItemFactory
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
-    protected $_stockItemFactory;
+    protected $stockItemService;
 
     /**
      * Construct
      *
      * @param \Magento\Framework\Logger $logger
-     * @param \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      */
     public function __construct(
         \Magento\Framework\Logger $logger,
-        \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
     ) {
-        $this->_stockItemFactory = $stockItemFactory;
+        $this->stockItemService = $stockItemService;
         parent::__construct($logger);
     }
 
@@ -60,11 +60,10 @@ class Stock extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
      */
     public function afterLoad($object)
     {
-        $item = $this->_stockItemFactory->create();
-        $item->loadByProduct($object);
+        $stockItemDo = $this->stockItemService->getStockItem($object->getId());
         $object->setData(
             $this->getAttribute()->getAttributeCode(),
-            array('is_in_stock' => $item->getIsInStock(), 'qty' => $item->getQty())
+            array('is_in_stock' => $stockItemDo->getIsInStock(), 'qty' => $stockItemDo->getQty())
         );
         return parent::afterLoad($object);
     }
diff --git a/app/code/Magento/Catalog/Model/Product/Option.php b/app/code/Magento/Catalog/Model/Product/Option.php
index d6e9f7754e1..dc3b95fb27c 100644
--- a/app/code/Magento/Catalog/Model/Product/Option.php
+++ b/app/code/Magento/Catalog/Model/Product/Option.php
@@ -37,6 +37,8 @@ use Magento\Framework\Model\AbstractModel;
  * @method \Magento\Catalog\Model\Product\Option setProductId(int $value)
  * @method string getType()
  * @method \Magento\Catalog\Model\Product\Option setType(string $value)
+ * @method string getTitle()
+ * @method \Magento\Catalog\Model\Product\Option seTitle(string $value)
  * @method int getIsRequire()
  * @method \Magento\Catalog\Model\Product\Option setIsRequire(int $value)
  * @method string getSku()
@@ -118,12 +120,18 @@ class Option extends AbstractModel
      */
     protected $string;
 
+    /**
+     * @var Option\Validator\Pool
+     */
+    protected $validatorPool;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param Option\Value $productOptionValue
-     * @param \Magento\Catalog\Model\Product\Option\Type\Factory $optionFactory
+     * @param Option\Type\Factory $optionFactory
      * @param \Magento\Framework\Stdlib\String $string
+     * @param Option\Validator\Pool $validatorPool
      * @param \Magento\Framework\Model\Resource\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\Db $resourceCollection
      * @param array $data
@@ -134,12 +142,14 @@ class Option extends AbstractModel
         Option\Value $productOptionValue,
         \Magento\Catalog\Model\Product\Option\Type\Factory $optionFactory,
         \Magento\Framework\Stdlib\String $string,
+        Option\Validator\Pool $validatorPool,
         \Magento\Framework\Model\Resource\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\Db $resourceCollection = null,
         array $data = array()
     ) {
         $this->_productOptionValue = $productOptionValue;
         $this->_optionFactory = $optionFactory;
+        $this->validatorPool = $validatorPool;
         $this->string = $string;
         parent::__construct($context, $registry, $resource, $resourceCollection, $data);
     }
@@ -328,6 +338,7 @@ class Option extends AbstractModel
     public function saveOptions()
     {
         foreach ($this->getOptions() as $option) {
+            $this->_validatorBeforeSave = null;
             $this->setData(
                 $option
             )->setData(
@@ -337,6 +348,8 @@ class Option extends AbstractModel
                 'store_id',
                 $this->getProduct()->getStoreId()
             );
+            /** Reset is delete flag from the previous iteration */
+            $this->isDeleted(false);
 
             if ($this->getData('option_id') == '0') {
                 $this->unsetData('option_id');
@@ -567,4 +580,12 @@ class Option extends AbstractModel
         }
         return $this;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _getValidationRulesBeforeSave()
+    {
+        return $this->validatorPool->get($this->getType());
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
new file mode 100644
index 00000000000..6433e327fcb
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+use Zend_Validate_Exception;
+use Magento\Catalog\Model\Product\Option;
+
+class DefaultValidator extends \Magento\Framework\Validator\AbstractValidator
+{
+    /**
+     * Product option types
+     *
+     * @var string[]
+     */
+    protected $productOptionTypes;
+
+    /**
+     * Price types
+     *
+     * @var string[]
+     */
+    protected $priceTypes;
+
+    /**
+     * @param \Magento\Catalog\Model\ProductOptions\ConfigInterface $productOptionConfig
+     * @param \Magento\Catalog\Model\Config\Source\Product\Options\Price $priceConfig
+     */
+    public function __construct(
+        \Magento\Catalog\Model\ProductOptions\ConfigInterface $productOptionConfig,
+        \Magento\Catalog\Model\Config\Source\Product\Options\Price $priceConfig
+    ) {
+        foreach ($productOptionConfig->getAll() as $option) {
+            foreach ($option['types'] as $type) {
+                $this->productOptionTypes[] = $type['name'];
+            }
+        }
+
+        foreach ($priceConfig->toOptionArray() as $item) {
+            $this->priceTypes[] = $item['value'];
+        }
+    }
+
+    /**
+     * Returns true if and only if $value meets the validation requirements
+     *
+     * If $value fails validation, then this method returns false, and
+     * getMessages() will return an array of messages that explain why the
+     * validation failed.
+     *
+     * @param  \Magento\Catalog\Model\Product\Option $value
+     * @return boolean
+     * @throws Zend_Validate_Exception If validation of $value is impossible
+     */
+    public function isValid($value)
+    {
+        $messages = array();
+
+        if (!$this->validateOptionRequiredFields($value)) {
+            $messages['option required fields'] = 'Missed values for option required fields';
+        }
+
+        if (!$this->validateOptionType($value)) {
+            $messages['option type'] = 'Invalid option type';
+        }
+
+        if (!$this->validateOptionValue($value)) {
+            $messages['option values'] = 'Invalid option value';
+        }
+
+        $this->_addMessages($messages);
+
+        return empty($messages);
+    }
+
+    /**
+     * Validate option required fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionRequiredFields(Option $option)
+    {
+        return !$this->isEmpty($option->getTitle()) && !$this->isEmpty($option->getType());
+    }
+
+    /**
+     * Validate option type fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionType(Option $option)
+    {
+        return $this->isInRange($option->getType(), $this->productOptionTypes);
+    }
+
+    /**
+     * Validate option type fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionValue(Option $option)
+    {
+        return $this->isInRange($option->getPriceType(), $this->priceTypes) && !$this->isNegative($option->getPrice());
+    }
+
+    /**
+     * Check whether value is empty
+     *
+     * @param mixed $value
+     * @return bool
+     */
+    protected function isEmpty($value)
+    {
+        return empty($value);
+    }
+
+    /**
+     * Check whether value is in range
+     *
+     * @param string $value
+     * @param array $range
+     * @return bool
+     */
+    protected function isInRange($value, array $range)
+    {
+        return in_array($value, $range);
+    }
+
+    /**
+     * Check whether value is not negative
+     *
+     * @param string $value
+     * @return bool
+     */
+    protected function isNegative($value)
+    {
+        return intval($value) < 0;
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/File.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/File.php
new file mode 100644
index 00000000000..02cdbd28712
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/File.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+use Magento\Catalog\Model\Product\Option;
+
+class File extends DefaultValidator
+{
+    /**
+     * Validate option type fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionValue(Option $option)
+    {
+        $result = parent::validateOptionValue($option);
+        return $result && !$this->isNegative($option->getImageSizeX())&& !$this->isNegative($option->getImageSizeY());
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
new file mode 100644
index 00000000000..6d36f834d63
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class Pool
+{
+    /**
+     * @var \Zend_Validate_Interface
+     */
+    protected $validators;
+
+    /**
+     * @param \Zend_Validate_Interface[] $validators
+     */
+    public function __construct(array $validators)
+    {
+        $this->validators = $validators;
+    }
+
+    /**
+     * Get validator
+     *
+     * @param string $type
+     * @return \Zend_Validate_Interface
+     */
+    public function get($type)
+    {
+        return isset($this->validators[$type]) ? $this->validators[$type] : $this->validators['default'];
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
new file mode 100644
index 00000000000..37a8dfc9ad0
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+use Magento\Catalog\Model\Product\Option;
+
+class Select extends DefaultValidator
+{
+    /**
+     * Check if all values are marked for removal
+     *
+     * @param array $values
+     * @return bool
+     */
+    protected function checkAllValuesRemoved($values)
+    {
+        foreach ($values as $value) {
+            if (!array_key_exists('is_delete', $value) || $value['is_delete'] != 1) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Validate option type fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionValue(Option $option)
+    {
+        $values = $option->getData('values');
+        if (!is_array($values) || $this->isEmpty($values)) {
+            return false;
+        }
+
+        //forbid removal of last value for option
+        if ($this->checkAllValuesRemoved($values)) {
+            return false;
+        }
+
+        foreach ($option->getData('values') as $value) {
+            $type = isset($value['price_type']) ? $value['price_type'] : '';
+            $price = isset($value['price']) ? $value['price'] : 0;
+            $title = isset($value['title']) ? $value['title'] : '';
+            if (!$this->isInRange($type, $this->priceTypes) || $this->isNegative($price) || $this->isEmpty($title)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php
new file mode 100644
index 00000000000..949de1775a0
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+use Magento\Catalog\Model\Product\Option;
+
+class Text extends DefaultValidator
+{
+    /**
+     * Validate option type fields
+     *
+     * @param Option $option
+     * @return bool
+     */
+    protected function validateOptionValue(Option $option)
+    {
+        $result = parent::validateOptionValue($option);
+        return $result && !$this->isNegative($option->getMaxCharacters());
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Resource/Collection/AbstractCollection.php b/app/code/Magento/Catalog/Model/Resource/Collection/AbstractCollection.php
index f333654da3c..70eb37b606d 100644
--- a/app/code/Magento/Catalog/Model/Resource/Collection/AbstractCollection.php
+++ b/app/code/Magento/Catalog/Model/Resource/Collection/AbstractCollection.php
@@ -57,7 +57,7 @@ class AbstractCollection extends \Magento\Eav\Model\Entity\Collection\AbstractCo
      * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Zend_Db_Adapter_Abstract $connection
-     * 
+     *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -179,7 +179,7 @@ class AbstractCollection extends \Magento\Eav\Model\Entity\Collection\AbstractCo
                 $attributeIds
             )->where(
                 't_d.store_id = ?',
-                0
+                $adapter->getIfNullSql('t_s.store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID)
             );
         } else {
             $select = parent::_getLoadAttributesSelect($table)->where('store_id = ?', $this->getDefaultStoreId());
diff --git a/app/code/Magento/Catalog/Model/Resource/Product/Indexer/Eav/Source.php b/app/code/Magento/Catalog/Model/Resource/Product/Indexer/Eav/Source.php
index fea812a8954..e2af327803e 100644
--- a/app/code/Magento/Catalog/Model/Resource/Product/Indexer/Eav/Source.php
+++ b/app/code/Magento/Catalog/Model/Resource/Product/Indexer/Eav/Source.php
@@ -138,19 +138,25 @@ class Source extends AbstractEav
             array('store_id', 'website_id')
         )->joinLeft(
             array('d' => $this->getTable('catalog_product_entity_int')),
-            '1 = 1 AND d.store_id = 0',
+            '1 = 1 AND (d.store_id = 0 OR d.store_id = s.store_id)',
             array('entity_id', 'attribute_id', 'value')
-        )->joinInner(
+        )->joinLeft(
             array('d2' => $this->getTable('catalog_product_entity_int')),
             sprintf(
-                'd.entity_id = d2.entity_id AND d2.attribute_id = %s AND d2.value = %s AND d.store_id = 0',
+                'd.entity_id = d2.entity_id AND d2.attribute_id = %s AND d2.value = %s AND d.store_id = d2.store_id',
                 $this->_eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'status')->getId(),
                 ProductStatus::STATUS_ENABLED
             ),
             array()
         )->where(
             's.store_id != 0'
-        );
+        )->where(
+            'd.value IS NOT NULL'
+        )->where(
+            'd2.value IS NOT NULL'
+        )->group(array(
+            's.store_id', 's.website_id', 'd.entity_id', 'd.attribute_id', 'd.value'
+        ));
 
         if (!is_null($entityIds)) {
             $subSelect->where('d.entity_id IN(?)', $entityIds);
@@ -248,7 +254,7 @@ class Source extends AbstractEav
             array('value' => $productValueExpression)
         )->where(
             'pvd.store_id=?',
-            \Magento\Store\Model\Store::DEFAULT_STORE_ID
+            $adapter->getIfNullSql('pvs.store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID)
         )->where(
             'cs.store_id!=?',
             \Magento\Store\Model\Store::DEFAULT_STORE_ID
diff --git a/app/code/Magento/Catalog/Model/Url.php b/app/code/Magento/Catalog/Model/Url.php
index 2e45f495e76..fbd489bce82 100644
--- a/app/code/Magento/Catalog/Model/Url.php
+++ b/app/code/Magento/Catalog/Model/Url.php
@@ -302,7 +302,7 @@ class Url
         }
 
         $this->clearStoreInvalidRewrites($storeId);
-        $this->refreshCategoryRewrite($this->getStores($storeId)->getRootCategoryId(), $storeId, false);
+        $this->refreshCategoryRewrite($this->getStores($storeId)->getRootCategoryId(), $storeId, false, false);
         $this->refreshProductRewrites($storeId);
         $this->getResource()->clearCategoryProduct($storeId);
 
@@ -315,10 +315,15 @@ class Url
      * @param \Magento\Framework\Object $category
      * @param string $parentPath
      * @param bool $refreshProducts
+     * @param bool $changeRequestPath
      * @return $this
      */
-    protected function _refreshCategoryRewrites(\Magento\Framework\Object $category, $parentPath = null, $refreshProducts = true)
-    {
+    protected function _refreshCategoryRewrites(
+        \Magento\Framework\Object $category,
+        $parentPath = null,
+        $refreshProducts = true,
+        $changeRequestPath = false
+    ) {
         if ($category->getId() != $this->getStores($category->getStoreId())->getRootCategoryId()) {
             if ($category->getUrlKey() == '') {
                 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
@@ -328,7 +333,7 @@ class Url
 
             $idPath = $this->generatePath('id', null, $category);
             $targetPath = $this->generatePath('target', null, $category);
-            $requestPath = $this->getCategoryRequestPath($category, $parentPath);
+            $requestPath = $this->getCategoryRequestPath($category, $parentPath, $changeRequestPath);
 
             $rewriteData = array(
                 'store_id' => $category->getStoreId(),
@@ -366,7 +371,12 @@ class Url
         }
 
         foreach ($category->getChilds() as $child) {
-            $this->_refreshCategoryRewrites($child, $category->getUrlPath() . '/', $refreshProducts);
+            $this->_refreshCategoryRewrites(
+                $child,
+                $category->getUrlPath() . '/',
+                $refreshProducts,
+                $changeRequestPath
+            );
         }
 
         return $this;
@@ -483,13 +493,18 @@ class Url
      * @param int $categoryId
      * @param int|null $storeId
      * @param bool $refreshProducts
+     * @param bool $changeRequestPath
      * @return $this
      */
-    public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshProducts = true)
-    {
+    public function refreshCategoryRewrite(
+        $categoryId,
+        $storeId = null,
+        $refreshProducts = true,
+        $changeRequestPath = false
+    ) {
         if (is_null($storeId)) {
             foreach ($this->getStores() as $store) {
-                $this->refreshCategoryRewrite($categoryId, $store->getId(), $refreshProducts);
+                $this->refreshCategoryRewrite($categoryId, $store->getId(), $refreshProducts, $changeRequestPath);
             }
             return $this;
         }
@@ -506,7 +521,7 @@ class Url
             $categoryIds = array_merge($categoryIds, array_keys($category->getAllChilds()));
         }
         $this->_rewrites = $this->getResource()->prepareRewrites($storeId, $categoryIds);
-        $this->_refreshCategoryRewrites($category, null, $refreshProducts);
+        $this->_refreshCategoryRewrites($category, null, $refreshProducts, $changeRequestPath);
 
         unset($category);
         $this->_rewrites = array();
@@ -743,14 +758,15 @@ class Url
      *
      * @param \Magento\Framework\Object $category
      * @param string $parentPath
+     * @param bool $changeRequestPath
      * @return string
      */
-    public function getCategoryRequestPath($category, $parentPath)
+    public function getCategoryRequestPath($category, $parentPath, $changeRequestPath = false)
     {
         $storeId = $category->getStoreId();
         $idPath = $this->generatePath('id', null, $category);
         $categoryUrlSuffix = $this->getCategoryUrlSuffix($storeId);
-
+        $pathSuffix = '(\-[0-9]+)?';
         if (isset($this->_rewrites[$idPath])) {
             $this->_rewrite = $this->_rewrites[$idPath];
             $existingRequestPath = $this->_rewrites[$idPath]->getRequestPath();
@@ -770,7 +786,10 @@ class Url
         $parentPath = $this->_catalogCategory->getCategoryUrlPath($parentPath, true, $storeId);
 
         $requestPath = $parentPath . $urlKey;
-        $regexp = '/^' . preg_quote($requestPath, '/') . '(\-[0-9]+)?' . preg_quote($categoryUrlSuffix, '/') . '$/i';
+        if ($changeRequestPath) {
+            $pathSuffix = '';
+        }
+        $regexp = '/^' . preg_quote($requestPath, '/') . $pathSuffix . preg_quote($categoryUrlSuffix, '/') . '$/i';
         if (isset($existingRequestPath) && preg_match($regexp, $existingRequestPath)) {
             return $existingRequestPath;
         }
diff --git a/app/code/Magento/Catalog/Service/V1/Data/Converter.php b/app/code/Magento/Catalog/Service/V1/Data/Converter.php
index 57dc8d19b55..e7c82fd5a08 100644
--- a/app/code/Magento/Catalog/Service/V1/Data/Converter.php
+++ b/app/code/Magento/Catalog/Service/V1/Data/Converter.php
@@ -23,7 +23,6 @@
  */
 namespace Magento\Catalog\Service\V1\Data;
 
-use Magento\Catalog\Service\V1\Data\ProductBuilder;
 use Magento\Catalog\Service\V1\Data\Product as ProductDataObject;
 
 /**
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option.php
new file mode 100644
index 00000000000..bac5ba32df2
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data;
+
+class Option extends \Magento\Framework\Service\Data\AbstractObject
+{
+    const OPTION_ID = 'option_id';
+    const TITLE = 'title';
+    const TYPE = 'type';
+    const SORT_ORDER = 'sort_order';
+    const IS_REQUIRE = 'is_require';
+    const METADATA = 'metadata';
+
+    /**
+     * Get option id
+     *
+     * @return int|null
+     */
+    public function getOptionId()
+    {
+        return $this->_get(self::OPTION_ID);
+    }
+
+    /**
+     * Get option title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->_get(self::TITLE);
+    }
+
+    /**
+     * Get option type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->_get(self::TYPE);
+    }
+
+    /**
+     * Get sort order
+     *
+     * @return int
+     */
+    public function getSortOrder()
+    {
+        return $this->_get(self::SORT_ORDER);
+    }
+
+    /**
+     * Get is require
+     *
+     * @return bool
+     * @SuppressWarnings(PHPMD.BooleanGetMethodName)
+     */
+    public function getIsRequire()
+    {
+        return $this->_get(self::IS_REQUIRE);
+    }
+
+    /**
+     * Get option metadata
+     *
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata[]
+     */
+    public function getMetadata()
+    {
+        return $this->_get(self::METADATA);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Converter.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Converter.php
new file mode 100644
index 00000000000..5ee17d07c22
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Converter.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface as MetadataConverter;
+
+class Converter
+{
+    /**
+     * @var MetadataConverter
+     */
+    protected $metadataConverter;
+
+    /**
+     * @param MetadataConverter $valueConverter
+     */
+    public function __construct(MetadataConverter $valueConverter)
+    {
+        $this->metadataConverter = $valueConverter;
+    }
+
+    /**
+     * Convert data object to array
+     *
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+     * @return array
+     */
+    public function convert(\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option)
+    {
+        $output = [
+            'option_id' => $option->getOptionId(),
+            'title' => $option->getTitle(),
+            'type' => $option->getType(),
+            'sort_order' => $option->getSortOrder(),
+            'is_require' => $option->getIsRequire()
+        ];
+        $output = array_merge($output, $this->metadataConverter->convert($option));
+        return $output;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata.php
new file mode 100644
index 00000000000..9c9a653ea78
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option;
+
+class Metadata extends \Magento\Framework\Service\Data\Eav\AbstractObject
+{
+    const PRICE = 'price';
+    const PRICE_TYPE = 'price_type';
+    const SKU = 'sku';
+    const SORT_ORDER = 'sort_order';
+    const FILE_EXTENSION = 'file_extension';
+    const IMAGE_SIZE_X = 'image_size_x';
+    const IMAGE_SIZE_Y = 'image_size_y';
+    const MAX_CHARACTERS = 'max_characters';
+    const TITLE = 'title';
+    const OPTION_TYPE_ID = 'option_type_id';
+
+    /**
+     * Get price
+     *
+     * @return float
+     */
+    public function getPrice()
+    {
+        return $this->_get(self::PRICE);
+    }
+
+    /**
+     * Get price type
+     *
+     * @return string
+     */
+    public function getPriceType()
+    {
+        return $this->_get(self::PRICE_TYPE);
+    }
+
+    /**
+     * Get Sku
+     *
+     * @return string
+     */
+    public function getSku()
+    {
+        return $this->_get(self::SKU);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Composite.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Composite.php
new file mode 100644
index 00000000000..229898e5ead
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Composite.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface;
+
+class Composite implements ConverterInterface
+{
+    /**
+     * @var ConverterInterface[]
+     */
+    protected $converters;
+
+    /**
+     * @param ConverterInterface[] $converters
+     */
+    public function __construct(array $converters)
+    {
+        $this->converters = $converters;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function convert(\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option)
+    {
+        $type = $option->getType();
+        $converter = isset($this->converters[$type]) ? $this->converters[$type] : $this->converters['default'];
+        return $converter->convert($option);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverter.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverter.php
new file mode 100644
index 00000000000..1341080351f
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverter.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface;
+
+class DefaultConverter implements ConverterInterface
+{
+    /**
+     * Convert option data object value to array representation
+     *
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+     * @return array
+     */
+    public function convert(\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option)
+    {
+        /** @var Metadata $value */
+        $value = current($option->getMetadata());
+        $output = [
+            Metadata::PRICE => $value->getPrice(),
+            Metadata::PRICE_TYPE => $value->getPriceType(),
+            Metadata::SKU => $value->getSku(),
+        ];
+
+        foreach ($value->getCustomAttributes() as $attribute) {
+            $output[$attribute->getAttributeCode()] = $attribute->getValue();
+        }
+        return $output;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Select.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Select.php
new file mode 100644
index 00000000000..b0e7cb2f23e
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Select.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option;
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface;
+
+class Select implements ConverterInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function convert(Option $option)
+    {
+        $output = [];
+        foreach ($option->getMetadata() as $value) {
+            $attributes = $value->getCustomAttributes();
+            $valueItem = [
+                Metadata::PRICE => $value->getPrice(),
+                Metadata::PRICE_TYPE => $value->getPriceType(),
+                Metadata::SKU => $value->getSku()
+            ];
+            foreach ($attributes as $attribute) {
+                $valueItem[$attribute->getAttributeCode()] = $attribute->getValue();
+            }
+            $output[] = $valueItem;
+        }
+        return ['values' => $output];
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ConverterInterface.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ConverterInterface.php
new file mode 100644
index 00000000000..b1e92b754a2
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ConverterInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+interface ConverterInterface
+{
+    /**
+     * Convert option data object value to array representation
+     *
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+     * @return array
+     */
+    public function convert(\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader.php
new file mode 100644
index 00000000000..b479efe75c1
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class Reader implements ReaderInterface
+{
+    /**
+     * @var ReaderInterface[]
+     */
+    protected $valueReaders;
+
+    /**
+     * @param ReaderInterface[] $valueReaders
+     */
+    public function __construct($valueReaders)
+    {
+        $this->valueReaders = $valueReaders;
+    }
+
+    /**
+     * Load option value
+     *
+     * @param \Magento\Catalog\Model\Product\Option $option
+     * @return Metadata[]
+     */
+    public function read(\Magento\Catalog\Model\Product\Option $option)
+    {
+        $type = $option->getType();
+        $reader = isset($this->valueReaders[$type]) ? $this->valueReaders[$type] : $this->valueReaders['default'];
+        return $reader->read($option);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReader.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReader.php
new file mode 100644
index 00000000000..8c4ffa0fdc6
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReader.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\MetadataBuilder;
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface;
+
+class DefaultReader implements ReaderInterface
+{
+    /**
+     * @var MetadataBuilder
+     */
+    protected $valueBuilder;
+
+    /**
+     * @param MetadataBuilder $valueBuilder
+     */
+    public function __construct(MetadataBuilder $valueBuilder)
+    {
+        $this->valueBuilder = $valueBuilder;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function read(\Magento\Catalog\Model\Product\Option $option)
+    {
+        $fields = [
+            Metadata::PRICE => $option->getPrice(),
+            Metadata::PRICE_TYPE => $option->getPriceType(),
+            Metadata::SKU => $option->getSku()
+        ];
+        $fields = array_merge($fields, $this->getCustomAttributes($option));
+        $value = $this->valueBuilder->populateWithArray($fields)->create();
+        return [$value];
+    }
+
+    /**
+     * Get custom attributes
+     *
+     * @param \Magento\Catalog\Model\Product\Option $option
+     * @return array
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function getCustomAttributes(\Magento\Catalog\Model\Product\Option $option)
+    {
+        return [];
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/File.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/File.php
new file mode 100644
index 00000000000..e7f36b3b92f
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/File.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class File extends DefaultReader
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function getCustomAttributes(\Magento\Catalog\Model\Product\Option $option)
+    {
+        return [
+            Metadata::FILE_EXTENSION => $option->getFileExtension(),
+            Metadata::IMAGE_SIZE_X => $option->getImageSizeX(),
+            Metadata::IMAGE_SIZE_Y => $option->getImageSizeY(),
+        ];
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Select.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Select.php
new file mode 100644
index 00000000000..093b6837234
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Select.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\MetadataBuilder;
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface;
+
+class Select implements ReaderInterface
+{
+    /**
+     * @var MetadataBuilder
+     */
+    protected $metadataBuilder;
+
+    /**
+     * @param MetadataBuilder $metadataBuilder
+     */
+    public function __construct(MetadataBuilder $metadataBuilder)
+    {
+        $this->metadataBuilder = $metadataBuilder;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function read(\Magento\Catalog\Model\Product\Option $option)
+    {
+        $output = [];
+        foreach ($option->getValues() as $value) {
+            $output[] = $this->metadataBuilder->populateWithArray(
+                [
+                    Metadata::PRICE => $value->getPrice(),
+                    Metadata::PRICE_TYPE => $value->getPriceType(),
+                    Metadata::SKU => $value->getSku(),
+                    Metadata::TITLE => $value->getTitle(),
+                    Metadata::SORT_ORDER => $value->getSortOrder(),
+                    Metadata::OPTION_TYPE_ID => $value->getId()
+                ]
+            )->create();
+        }
+        return $output;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Text.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Text.php
new file mode 100644
index 00000000000..00264921875
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Text.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class Text extends DefaultReader
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function getCustomAttributes(\Magento\Catalog\Model\Product\Option $option)
+    {
+        return [Metadata::MAX_CHARACTERS => $option->getMaxCharacters()];
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderInterface.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderInterface.php
new file mode 100644
index 00000000000..c384bc1a619
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+interface ReaderInterface
+{
+    /**
+     * Read product option custom attributes value
+     *
+     * @param \Magento\Catalog\Model\Product\Option $option
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata[]
+     */
+    public function read(\Magento\Catalog\Model\Product\Option $option);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/MetadataBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/MetadataBuilder.php
new file mode 100644
index 00000000000..620857ccc39
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/MetadataBuilder.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option;
+
+use Magento\Framework\Service\Data\Eav\AttributeValueBuilder;
+
+class MetadataBuilder extends \Magento\Framework\Service\Data\Eav\AbstractObjectBuilder
+{
+    /**
+     * @var string[]
+     */
+    protected $customAttributeCodes = [
+        Metadata::SORT_ORDER,
+        Metadata::TITLE,
+        Metadata::FILE_EXTENSION,
+        Metadata::IMAGE_SIZE_X,
+        Metadata::IMAGE_SIZE_Y,
+        Metadata::MAX_CHARACTERS,
+        Metadata::OPTION_TYPE_ID
+    ];
+
+    /**
+     * @param \Magento\Framework\Service\Data\ObjectFactory $objectFactory
+     * @param AttributeValueBuilder $valueBuilder
+     * @param array $customAttributeCodes
+     */
+    public function __construct(
+        \Magento\Framework\Service\Data\ObjectFactory $objectFactory,
+        AttributeValueBuilder $valueBuilder,
+        array $customAttributeCodes = array()
+    ) {
+        parent::__construct($objectFactory, $valueBuilder);
+        $this->customAttributeCodes = array_merge($this->customAttributeCodes, $customAttributeCodes);
+    }
+
+    /**
+     * Set price
+     *
+     * @param float $value
+     * @return $this
+     */
+    public function setPrice($value)
+    {
+        return $this->_set(Metadata::PRICE, $value);
+    }
+
+    /**
+     * Set price type
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setPriceType($value)
+    {
+        return $this->_set(Metadata::PRICE_TYPE, $value);
+    }
+
+    /**
+     * Set Sku
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setSku($value)
+    {
+        return $this->_set(Metadata::SKU, $value);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCustomAttributesCodes()
+    {
+        return array_merge($this->customAttributeCodes, parent::getCustomAttributesCodes());
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionBuilder.php
new file mode 100644
index 00000000000..c56dddae572
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionBuilder.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data;
+
+class OptionBuilder extends \Magento\Framework\Service\Data\AbstractObjectBuilder
+{
+    /**
+     * Set option id
+     *
+     * @param int|null $value
+     * @return $this
+     */
+    public function setOptionId($value)
+    {
+        return $this->_set(Option::OPTION_ID, $value);
+    }
+
+    /**
+     * Set option title
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setTitle($value)
+    {
+        return $this->_set(Option::TITLE, $value);
+    }
+
+    /**
+     * Set option type
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setType($value)
+    {
+        return $this->_set(Option::TYPE, $value);
+    }
+
+    /**
+     * Set sort order
+     *
+     * @param int $value
+     * @return $this
+     */
+    public function setSortOrder($value)
+    {
+        return $this->_set(Option::SORT_ORDER, $value);
+    }
+
+    /**
+     * Set is require
+     *
+     * @param bool $value
+     * @return $this
+     */
+    public function setIsRequire($value)
+    {
+        return $this->_set(Option::IS_REQUIRE, $value);
+    }
+
+    /**
+     * Set option metadata
+     *
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata[] $value
+     * @return $this
+     */
+    public function setMetadata($value)
+    {
+        return $this->_set(Option::METADATA, $value);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionType.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionType.php
new file mode 100644
index 00000000000..e55da5970ac
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionType.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data;
+
+class OptionType extends \Magento\Framework\Service\Data\AbstractObject
+{
+    const LABEL = 'label';
+    const CODE = 'code';
+    const GROUP = 'group';
+
+    /**
+     * Get option type label
+     *
+     * @return string
+     */
+    public function getLabel()
+    {
+        return $this->_get(self::LABEL);
+    }
+
+    /**
+     * Get option type code
+     *
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->_get(self::CODE);
+    }
+
+    /**
+     * Get option type group
+     *
+     * @return string
+     */
+    public function getGroup()
+    {
+        return $this->_get(self::GROUP);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionTypeBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionTypeBuilder.php
new file mode 100644
index 00000000000..ea08d6857c9
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionTypeBuilder.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data;
+
+class OptionTypeBuilder extends \Magento\Framework\Service\Data\AbstractObjectBuilder
+{
+    /**
+     * Set option type label
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setLabel($value)
+    {
+        return $this->_set(OptionType::LABEL, $value);
+    }
+
+    /**
+     * Set option type code
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setCode($value)
+    {
+        return $this->_set(OptionType::CODE, $value);
+    }
+
+    /**
+     * Set option type group
+     *
+     * @param string $value
+     * @return $this
+     */
+    public function setGroup($value)
+    {
+        return $this->_set(OptionType::GROUP, $value);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadService.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadService.php
new file mode 100644
index 00000000000..1c1ac4bbc2b
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadService.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+
+class ReadService implements \Magento\Catalog\Service\V1\Product\CustomOptions\ReadServiceInterface
+{
+    /**
+     * Product Option Config
+     *
+     * @var \Magento\Catalog\Model\ProductOptions\ConfigInterface
+     */
+    protected $productOptionConfig;
+
+    /**
+     * @var Data\OptionTypeBuilder
+     */
+    protected $optionTypeBuilder;
+
+    /**
+     * @var Data\OptionBuilder
+     */
+    protected $optionBuilder;
+
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var Data\Option\Metadata\ReaderInterface
+     */
+    protected $optionMetadataReader;
+
+    /**
+     * @param \Magento\Catalog\Model\ProductOptions\ConfigInterface $productOptionConfig
+     * @param Data\OptionTypeBuilder $optionTypeBuilder
+     * @param Data\OptionBuilder $optionBuilder
+     * @param \Magento\Catalog\Model\ProductRepository $productRepository
+     * @param Data\Option\Metadata\ReaderInterface $optionMetadataReader
+     */
+    public function __construct(
+        \Magento\Catalog\Model\ProductOptions\ConfigInterface $productOptionConfig,
+        Data\OptionTypeBuilder $optionTypeBuilder,
+        Data\OptionBuilder $optionBuilder,
+        \Magento\Catalog\Model\ProductRepository $productRepository,
+        Data\Option\Metadata\ReaderInterface $optionMetadataReader
+    ) {
+        $this->productOptionConfig = $productOptionConfig;
+        $this->optionTypeBuilder = $optionTypeBuilder;
+        $this->optionBuilder = $optionBuilder;
+        $this->productRepository = $productRepository;
+        $this->optionMetadataReader = $optionMetadataReader;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTypes()
+    {
+        $output = [];
+        foreach ($this->productOptionConfig->getAll() as $option) {
+            foreach ($option['types'] as $type) {
+                if ($type['disabled']) {
+                    continue;
+                }
+                $itemData = [
+                    Data\OptionType::LABEL => __($type['label']),
+                    Data\OptionType::CODE => $type['name'],
+                    Data\OptionType::GROUP => __($option['label'])
+                ];
+                $output[] = $this->optionTypeBuilder->populateWithArray($itemData)->create();
+            }
+        }
+        return $output;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getList($productSku)
+    {
+        $product = $this->productRepository->get($productSku);
+        $output = [];
+        /** @var $option \Magento\Catalog\Model\Product\Option */
+        foreach ($product->getOptions() as $option) {
+            $output[] = $this->_createOptionDataObject($option);
+        }
+        return $output;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get($productSku, $optionId)
+    {
+        $product = $this->productRepository->get($productSku);
+        $option = $product->getOptionById($optionId);
+        if ($option === null) {
+            throw new NoSuchEntityException();
+        }
+        return $this->_createOptionDataObject($option);
+    }
+
+    /**
+     * Create option data object
+     *
+     * @param \Magento\Catalog\Model\Product\Option $option
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option array
+     */
+    protected function _createOptionDataObject(\Magento\Catalog\Model\Product\Option $option)
+    {
+        $data = array(
+            Data\Option::OPTION_ID => $option->getId(),
+            Data\Option::TITLE => $option->getTitle(),
+            Data\Option::TYPE => $option->getType(),
+            Data\Option::IS_REQUIRE => $option->getIsRequire(),
+            Data\Option::SORT_ORDER => $option->getSortOrder(),
+            Data\Option::METADATA => $this->optionMetadataReader->read($option)
+        );
+        return $this->optionBuilder->populateWithArray($data)->create();
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceInterface.php
new file mode 100644
index 00000000000..f5381e836ae
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceInterface.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+ 
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+interface ReadServiceInterface
+{
+    /**
+     * Get custom option types
+     *
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionType[]
+     */
+    public function getTypes();
+
+    /**
+     * Get the list of custom options for a specific product
+     *
+     * @param string $productSku
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option[]
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function getList($productSku);
+
+    /**
+     * Get custom option for a specific product
+     *
+     * @param string $productSku
+     * @param string $optionId
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function get($productSku, $optionId);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteService.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteService.php
new file mode 100644
index 00000000000..55d29959618
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteService.php
@@ -0,0 +1,211 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\CouldNotSaveException;
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionBuilder;
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class WriteService implements WriteServiceInterface
+{
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var Data\Option\Converter
+     */
+    protected $optionConverter;
+
+    /**
+     * @var Data\Option\Metadata\ReaderInterface
+     */
+    protected $optionMetadataReader;
+
+    /**
+     * @var OptionBuilder
+     */
+    protected $optionBuilder;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\OptionFactory
+     */
+    protected $optionFactory;
+
+    /**
+     * @param OptionBuilder $optionBuilder
+     * @param Data\Option\Converter $optionConverter
+     * @param \Magento\Catalog\Model\ProductRepository $productRepository
+     * @param Data\Option\Metadata\ReaderInterface $optionMetadataReader
+     * @param \Magento\Catalog\Model\Product\OptionFactory $optionFactory
+     */
+    public function __construct(
+        OptionBuilder $optionBuilder,
+        Data\Option\Converter $optionConverter,
+        \Magento\Catalog\Model\ProductRepository $productRepository,
+        Data\Option\Metadata\ReaderInterface $optionMetadataReader,
+        \Magento\Catalog\Model\Product\OptionFactory $optionFactory
+    ) {
+        $this->optionBuilder = $optionBuilder;
+        $this->optionConverter = $optionConverter;
+        $this->productRepository = $productRepository;
+        $this->optionMetadataReader = $optionMetadataReader;
+        $this->optionFactory = $optionFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function add($productSku, \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option)
+    {
+        $product = $this->productRepository->get($productSku);
+        $optionData = $this->optionConverter->convert($option);
+
+        $product->setCanSaveCustomOptions(true);
+        $product->setProductOptions([$optionData]);
+
+        $existingOptions = $product->getOptions();
+
+        try {
+            $product->save();
+        } catch (\Exception $e) {
+            throw new CouldNotSaveException('Could not save product option');
+        }
+
+        $productId = $product->getId();
+        $product->reset();
+        $product->load($productId);
+        $currentOptions = $product->getOptions();
+
+        $newID = array_diff(array_keys($currentOptions), array_keys($existingOptions));
+        if (empty($newID)) {
+            throw new CouldNotSaveException('Could not save product option');
+        }
+        $newID = current($newID);
+        /** @var \Magento\Catalog\Model\Product\Option $newOption */
+        $newOption = $currentOptions[$newID];
+        $data= array(
+            Data\Option::OPTION_ID => $newOption->getId(),
+            Data\Option::TITLE => $newOption->getTitle(),
+            Data\Option::TYPE => $newOption->getType(),
+            Data\Option::IS_REQUIRE => $newOption->getIsRequire(),
+            Data\Option::SORT_ORDER => $newOption->getSortOrder(),
+            Data\Option::METADATA => $this->optionMetadataReader->read($newOption)
+        );
+        $optionDataObject = $this->optionBuilder->populateWithArray($data)->create();
+        return $optionDataObject;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function remove($productSku, $optionId)
+    {
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->productRepository->get($productSku);
+        $options = $product->getOptions();
+        $option = $this->optionFactory->create();
+        $option->load($optionId);
+        if (!$option->getId() || !isset($options[$option->getId()])) {
+            throw NoSuchEntityException::singleField('optionId', $optionId);
+        }
+
+        unset($options[$optionId]);
+        try {
+            $option->delete();
+            if (empty($options)) {
+                $product->setHasOptions(false);
+                $product->save();
+            }
+        } catch (\Exception $e) {
+            throw new CouldNotSaveException('Could not remove custom option');
+        }
+        return true;
+    }
+
+    /**
+     * Mark original values for removal if they are absent among new values
+     *
+     * @param $newValues array
+     * @param $originalValues \Magento\Catalog\Model\Product\Option\Value[]
+     * @return array
+     */
+    protected function markRemovedValues($newValues, $originalValues)
+    {
+        $idsToLeave = [];
+
+        foreach ($newValues as $newValue) {
+            if (array_key_exists(Metadata::OPTION_TYPE_ID, $newValue)) {
+                $idsToLeave[] = $newValue[Metadata::OPTION_TYPE_ID];
+            }
+        }
+
+        /** @var $originalValue \Magento\Catalog\Model\Product\Option\Value */
+        foreach ($originalValues as $originalValue) {
+            if (!in_array($originalValue->getData(Metadata::OPTION_TYPE_ID), $idsToLeave)) {
+                $originalValue->setData('is_delete', 1);
+                $newValues[] = $originalValue->getData();
+            }
+        }
+
+        return $newValues;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update(
+        $productSku,
+        $optionId,
+        \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+    ) {
+        $product = $this->productRepository->get($productSku);
+        $optionData = $this->optionConverter->convert($option);
+        if (!$product->getOptionById($optionId)) {
+            throw new NoSuchEntityException();
+        }
+        $optionData['option_id'] = $optionId;
+        $originalValues = $product->getOptionById($optionId)->getValues();
+        if (array_key_exists('values', $optionData)) {
+            $optionData['values'] = $this->markRemovedValues($optionData['values'], $originalValues);
+        }
+
+        $product->setCanSaveCustomOptions(true);
+        $product->setProductOptions([$optionData]);
+
+        try {
+            $product->save();
+        } catch (\Exception $e) {
+            throw new CouldNotSaveException('Could not save custom option');
+        }
+
+        return true;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceInterface.php
new file mode 100644
index 00000000000..72ab9d5ee24
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceInterface.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+ 
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+interface WriteServiceInterface
+{
+    /**
+     * Remove custom option from product
+     *
+     * @param string $productSku
+     * @param int $optionId
+     * @throws \Magento\Framework\Exception\NoSuchEntityException|\Magento\Framework\Exception\CouldNotSaveException
+     * @return bool
+     */
+    public function remove($productSku, $optionId);
+
+    /**
+     * Add custom option to the product
+     *
+     * @param string $productSku
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+     * @return \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option
+     */
+    public function add($productSku, \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option);
+
+    /**
+     * Add custom option to the product
+     *
+     * @param string $productSku
+     * @param string $optionId
+     * @param \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+     * @return bool
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function update(
+        $productSku,
+        $optionId,
+        \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option $option
+    );
+}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index a7f281199ba..6d0094742ee 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -51,6 +51,10 @@
     <preference for="Magento\Catalog\Service\V1\Product\Link\Data\ProductLink\DataMapperInterface" type="Magento\Catalog\Service\V1\Product\Link\Data\ProductLink\DataMapper\Composite" />
     <preference for="Magento\Catalog\Service\V1\Product\GroupPriceServiceInterface" type="Magento\Catalog\Service\V1\Product\GroupPriceService" />
     <preference for="Magento\Catalog\Service\V1\Product\TierPriceServiceInterface" type="Magento\Catalog\Service\V1\Product\TierPriceService" />
+    <preference for="Magento\Catalog\Service\V1\Product\CustomOptions\ReadServiceInterface" type="Magento\Catalog\Service\V1\Product\CustomOptions\ReadService" />
+    <preference for="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface" type="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader" />
+    <preference for="Magento\Catalog\Service\V1\Product\CustomOptions\WriteServiceInterface" type="Magento\Catalog\Service\V1\Product\CustomOptions\WriteService" />
+    <preference for="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface" type="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Composite" />
     <type name="Magento\Log\Model\Resource\Log">
         <plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
     </type>
@@ -401,4 +405,43 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader">
+        <arguments>
+            <argument name="valueReaders" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\DefaultReader</item>
+                <item name="field" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Text</item>
+                <item name="area" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Text</item>
+                <item name="file" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\File</item>
+                <item name="drop_down" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select</item>
+                <item name="radio" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select</item>
+                <item name="checkbox" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select</item>
+                <item name="multiple" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select</item>
+            </argument>
+        </arguments>
+    </type>
+    <type name="Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Composite">
+        <arguments>
+            <argument name="converters" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\DefaultConverter</item>
+                <item name="drop_down" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select</item>
+                <item name="radio" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select</item>
+                <item name="checkbox" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select</item>
+                <item name="multiple" xsi:type="object">Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select</item>
+            </argument>
+        </arguments>
+    </type>
+    <type name="Magento\Catalog\Model\Product\Option\Validator\Pool">
+        <arguments>
+            <argument name="validators" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\DefaultValidator</item>
+                <item name="drop_down" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Select</item>
+                <item name="radio" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Select</item>
+                <item name="checkbox" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Select</item>
+                <item name="multiple" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Select</item>
+                <item name="text" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Text</item>
+                <item name="area" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\Text</item>
+                <item name="file" xsi:type="object">Magento\Catalog\Model\Product\Option\Validator\File</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml
index 68c16392095..f4048537474 100644
--- a/app/code/Magento/Catalog/etc/webapi.xml
+++ b/app/code/Magento/Catalog/etc/webapi.xml
@@ -289,4 +289,40 @@
             <resource ref="Magento_Catalog::catalog"/>
         </resources>
     </route>
+    <route url="/V1/products/options/types" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\ReadServiceInterface" method="getTypes"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/options" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\ReadServiceInterface" method="getList"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/options/:optionId" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\ReadServiceInterface" method="get"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/options" method="POST">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\WriteServiceInterface" method="add"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/options/:optionId" method="PUT">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\WriteServiceInterface" method="update"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/options/:optionId" method="DELETE">
+        <service class="Magento\Catalog\Service\V1\Product\CustomOptions\WriteServiceInterface" method="remove"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
 </routes>
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/tab/inventory.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/tab/inventory.phtml
index b9a4bc194de..3144968c7b2 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/tab/inventory.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/tab/inventory.phtml
@@ -207,9 +207,10 @@
         <span><?php echo __('Enable Qty Increments') ?></span>
     </label>
     <div class="control">
+        <?php $qtyIncrementsEnabled = $this->getFieldValue('enable_qty_increments'); ?>
         <select id="inventory_enable_qty_increments" name="<?php echo $this->getFieldSuffix() ?>[stock_data][enable_qty_increments]" <?php echo $_readonly;?>>
-            <option value="1"><?php echo __('Yes') ?></option>
-            <option value="0"<?php if ($this->getConfigFieldValue('enable_qty_increments') == 0): ?> selected="selected"<?php endif; ?>><?php echo __('No') ?></option>
+            <option value="1"<?php if ($qtyIncrementsEnabled): ?> selected="selected"<?php endif; ?>><?php echo __('Yes') ?></option>
+            <option value="0"<?php if (!$qtyIncrementsEnabled): ?> selected="selected"<?php endif; ?>><?php echo __('No') ?></option>
         </select>
         <input type="hidden" id="inventory_enable_qty_increments_default" value="<?php echo $this->getDefaultConfigValue('enable_qty_increments'); ?>">
         <?php $_checked = ($this->getFieldValue('use_config_enable_qty_inc') || $this->IsNew()) ? 'checked="checked"' : '' ?>
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/tabs.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/tabs.phtml
index bb4e97755e6..7e97028f574 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/tabs.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/tabs.phtml
@@ -43,13 +43,12 @@
     <?php $isBasic = $tabGroupCode == \Magento\Catalog\Block\Adminhtml\Product\Edit\Tabs::BASIC_TAB_GROUP_CODE; ?>
     <div id="<?php echo $tabGroupId ?>"
         <?php if (!$isBasic): ?>
-        data-mage-init='{"accordion":{"active":<?php echo $this->isAdvancedTabGroupActive() ? '0' : 'false' ?>, "collapsible": true}}'
+            data-mage-init='{"collapsible":{"active": <?php echo $this->isAdvancedTabGroupActive() ? 'true' : 'false' ?>, "collapsible": true}}'
         <?php endif;?>>
-        <h3 <?php echo $this->getUiId('title') ?>>
-            <?php echo $isBasic ? __('Basic Settings')
-            : __('Advanced Settings') ?>
+        <h3 <?php echo $this->getUiId('title') ?> data-role="title" <?php if (!$isBasic): ?>class="ui-accordion-header"<?php endif;?>>
+            <span data-role="trigger"> <?php echo $isBasic ? __('Basic Settings') : __('Advanced Settings') ?></span>
         </h3>
-        <ul <?php echo $this->getUiId('tab', $tabGroupId) ?> class="tabs">
+        <ul <?php echo $this->getUiId('tab', $tabGroupId) ?> class="tabs" data-role="content">
             <?php foreach ($tabs as $_tab): ?>
             <?php if (!$this->canShowTab($_tab) || $_tab->getParentTab()
                 || ($_tab->getGroupCode() && $_tab->getGroupCode() != $tabGroupCode)
diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
index 2e4f8fc812f..8903427a9ae 100644
--- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
@@ -60,6 +60,8 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
 
     const COL_SKU = 'sku';
 
+    const COL_VISIBILITY = 'visibility';
+
     /**
      * Pairs of attribute set ID-to-name.
      *
@@ -323,7 +325,9 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         $productTypes = $this->_exportConfig->getEntityTypes($this->getEntityTypeCode());
         foreach ($productTypes as $productTypeName => $productTypeConfig) {
             if (!($model = $this->_typeFactory->create($productTypeConfig['model']))) {
-                throw new \Magento\Framework\Model\Exception("Entity type model '{$productTypeConfig['model']}' is not found");
+                throw new \Magento\Framework\Model\Exception(
+                    "Entity type model '{$productTypeConfig['model']}' is not found"
+                );
             }
             if (!$model instanceof \Magento\CatalogImportExport\Model\Export\Product\Type\AbstractType) {
                 throw new \Magento\Framework\Model\Exception(
@@ -748,6 +752,8 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         set_time_limit(0);
 
         $this->_prepareEntityCollection($this->_getEntityCollection());
+        $this->_getEntityCollection()->setOrder('has_options', 'asc');
+        $this->_getEntityCollection()->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
         $writer = $this->getWriter();
         $page = 0;
         while (true) {
@@ -821,7 +827,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                                     $this->_attributeValues[$attrCode],
                                     array_flip($attrValue)
                                 );
-                                $rowMultiselects[$itemId][$attrCode] = $attrValue;
+                                $rowMultiselects[$storeId][$itemId][$attrCode] = $attrValue;
                             } else {
                                 if (isset($this->_attributeValues[$attrCode][$attrValue])) {
                                     $attrValue = $this->_attributeValues[$attrCode][$attrValue];
@@ -842,6 +848,9 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                             // mark row as not empty
                             $rowIsEmpty = false;
                         }
+                        if (!empty($rowMultiselects[$storeId][$itemId][$attrCode])) {
+                            $rowIsEmpty = false;
+                        }
                     }
                     if ($rowIsEmpty) {
                         // remove empty rows
@@ -986,6 +995,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                         $dataRow[self::COL_SKU] = null;
                         $dataRow[self::COL_ATTR_SET] = null;
                         $dataRow[self::COL_TYPE] = null;
+                        $dataRow[self::COL_VISIBILITY] = $productData[$defaultStoreId][self::COL_VISIBILITY];
                     } else {
                         $dataRow[self::COL_STORE] = null;
                         if (isset($stockItemRows[$productId])) {
@@ -1021,90 +1031,96 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                         $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId]));
                     }
                     $dataRow = $this->rowCustomizer->addData($dataRow, $productId);
-                    if (!empty($rowMultiselects[$productId])) {
-                        foreach ($rowMultiselects[$productId] as $attrKey => $attrVal) {
-                            if (!empty($rowMultiselects[$productId][$attrKey])) {
-                                $dataRow[$attrKey] = array_shift($rowMultiselects[$productId][$attrKey]);
+                    if (!empty($rowMultiselects[$storeId][$productId])) {
+                        foreach ($rowMultiselects[$storeId][$productId] as $attrKey => $attrVal) {
+                            if (!empty($rowMultiselects[$storeId][$productId][$attrKey])) {
+                                $dataRow[$attrKey] = array_shift($rowMultiselects[$storeId][$productId][$attrKey]);
                             }
                         }
                     }
                     $exportData[] = $dataRow;
-                }
-                // calculate largest links block
-                $largestLinks = 0;
 
-                if (isset($linksRows[$productId])) {
-                    $linksRowsKeys = array_keys($linksRows[$productId]);
-                    foreach ($linksRowsKeys as $linksRowsKey) {
-                        $largestLinks = max($largestLinks, count($linksRows[$productId][$linksRowsKey]));
-                    }
-                }
-                $additionalRowsCount = max(
-                    count($rowCategories[$productId]),
-                    count($rowWebsites[$productId]),
-                    $largestLinks
-                );
-                if (!empty($rowTierPrices[$productId])) {
-                    $additionalRowsCount = max($additionalRowsCount, count($rowTierPrices[$productId]));
-                }
-                if (!empty($rowGroupPrices[$productId])) {
-                    $additionalRowsCount = max($additionalRowsCount, count($rowGroupPrices[$productId]));
-                }
-                if (!empty($mediaGalery[$productId])) {
-                    $additionalRowsCount = max($additionalRowsCount, count($mediaGalery[$productId]));
-                }
-                if (!empty($customOptionsData[$productId])) {
-                    $additionalRowsCount = max($additionalRowsCount, count($customOptionsData[$productId]));
-                }
-                $additionalRowsCount = $this->rowCustomizer->getAdditionalRowsCount($additionalRowsCount, $productId);
-                if (!empty($rowMultiselects[$productId])) {
-                    foreach ($rowMultiselects[$productId] as $attributes) {
-                        $additionalRowsCount = max($additionalRowsCount, count($attributes));
-                    }
-                }
+                    // calculate largest links block
+                    $largestLinks = 0;
 
-                if ($additionalRowsCount) {
-                    for ($i = 0; $i < $additionalRowsCount; $i++) {
-                        $dataRow = array();
-
-                        $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId);
-                        if ($rowWebsites[$productId]) {
-                            $dataRow['_product_websites'] = $this->_websiteIdToCode[array_shift(
-                                $rowWebsites[$productId]
-                            )];
-                        }
-                        if (!empty($rowTierPrices[$productId])) {
-                            $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId]));
+                    if (isset($linksRows[$productId])) {
+                        $linksRowsKeys = array_keys($linksRows[$productId]);
+                        foreach ($linksRowsKeys as $linksRowsKey) {
+                            $largestLinks = max($largestLinks, count($linksRows[$productId][$linksRowsKey]));
                         }
-                        if (!empty($rowGroupPrices[$productId])) {
-                            $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId]));
-                        }
-                        if (!empty($mediaGalery[$productId])) {
-                            $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId]));
+                    }
+                    $additionalRowsCount = max(
+                        count($rowCategories[$productId]),
+                        count($rowWebsites[$productId]),
+                        $largestLinks
+                    );
+                    if (!empty($rowTierPrices[$productId])) {
+                        $additionalRowsCount = max($additionalRowsCount, count($rowTierPrices[$productId]));
+                    }
+                    if (!empty($rowGroupPrices[$productId])) {
+                        $additionalRowsCount = max($additionalRowsCount, count($rowGroupPrices[$productId]));
+                    }
+                    if (!empty($mediaGalery[$productId])) {
+                        $additionalRowsCount = max($additionalRowsCount, count($mediaGalery[$productId]));
+                    }
+                    if (!empty($customOptionsData[$productId])) {
+                        $additionalRowsCount = max($additionalRowsCount, count($customOptionsData[$productId]));
+                    }
+                    $additionalRowsCount = $this->rowCustomizer
+                        ->getAdditionalRowsCount($additionalRowsCount, $productId);
+                    if (!empty($rowMultiselects[$storeId][$productId])) {
+                        foreach ($rowMultiselects[$storeId][$productId] as $attributes) {
+                            $additionalRowsCount = max($additionalRowsCount, count($attributes));
                         }
-                        foreach ($linkIdColPrefix as $linkId => &$colPrefix) {
-                            if (!empty($linksRows[$productId][$linkId])) {
-                                $linkData = array_shift($linksRows[$productId][$linkId]);
-                                $dataRow[$colPrefix . 'position'] = $linkData['position'];
-                                $dataRow[$colPrefix . 'sku'] = $linkData['sku'];
-
-                                if (null !== $linkData['default_qty']) {
-                                    $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty'];
+                    }
+
+                    if ($additionalRowsCount) {
+                        for ($i = 0; $i < $additionalRowsCount; $i++) {
+                            $dataRow = array();
+                            if ($defaultStoreId != $storeId) {
+                                $dataRow[self::COL_STORE] = $this->_storeIdToCode[$storeId];
+                            }
+                            $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId);
+                            if ($rowWebsites[$productId]) {
+                                $dataRow['_product_websites'] = $this->_websiteIdToCode[array_shift(
+                                    $rowWebsites[$productId]
+                                )];
+                            }
+                            if (!empty($rowTierPrices[$productId])) {
+                                $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId]));
+                            }
+                            if (!empty($rowGroupPrices[$productId])) {
+                                $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId]));
+                            }
+                            if (!empty($mediaGalery[$productId])) {
+                                $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId]));
+                            }
+                            foreach ($linkIdColPrefix as $linkId => &$colPrefix) {
+                                if (!empty($linksRows[$productId][$linkId])) {
+                                    $linkData = array_shift($linksRows[$productId][$linkId]);
+                                    $dataRow[$colPrefix . 'position'] = $linkData['position'];
+                                    $dataRow[$colPrefix . 'sku'] = $linkData['sku'];
+
+                                    if (null !== $linkData['default_qty']) {
+                                        $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty'];
+                                    }
                                 }
                             }
-                        }
-                        if (!empty($customOptionsData[$productId])) {
-                            $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId]));
-                        }
-                        $dataRow = $this->rowCustomizer->addData($dataRow, $productId);
-                        if (!empty($rowMultiselects[$productId])) {
-                            foreach ($rowMultiselects[$productId] as $attrKey => $attrVal) {
-                                if (!empty($rowMultiselects[$productId][$attrKey])) {
-                                    $dataRow[$attrKey] = array_shift($rowMultiselects[$productId][$attrKey]);
+                            if (!empty($customOptionsData[$productId])) {
+                                $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId]));
+                            }
+                            $dataRow = $this->rowCustomizer->addData($dataRow, $productId);
+                            if (!empty($rowMultiselects[$storeId][$productId])) {
+                                foreach ($rowMultiselects[$storeId][$productId] as $attrKey => $attrVal) {
+                                    if (!empty($rowMultiselects[$storeId][$productId][$attrKey])) {
+                                        $dataRow[$attrKey] = array_shift(
+                                            $rowMultiselects[$storeId][$productId][$attrKey]
+                                        );
+                                    }
                                 }
                             }
+                            $exportData[] = $dataRow;
                         }
-                        $exportData[] = $dataRow;
                     }
                 }
             }
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index a8607a1a938..5a63675b971 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -289,6 +289,34 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         '_media_is_disabled'
     );
 
+    /**
+     * @var array
+     */
+    protected $defaultStockData = [
+        'manage_stock' => 1,
+        'use_config_manage_stock' => 1,
+        'qty' => 0,
+        'min_qty' => 0,
+        'use_config_min_qty' => 1,
+        'min_sale_qty' => 1,
+        'use_config_min_sale_qty' => 1,
+        'max_sale_qty' => 10000,
+        'use_config_max_sale_qty' => 1,
+        'is_qty_decimal' => 0,
+        'backorders' => 0,
+        'use_config_backorders' => 1,
+        'notify_stock_qty' => 1,
+        'use_config_notify_stock_qty' => 1,
+        'enable_qty_increments' => 0,
+        'use_config_enable_qty_inc' => 1,
+        'qty_increments' => 0,
+        'use_config_qty_increments' => 1,
+        'is_in_stock' => 0,
+        'low_stock_date' => null,
+        'stock_status_changed_auto' => 0,
+        'is_decimal_divided' => 0
+    ];
+
     /**
      * Column names that holds images files names
      *
@@ -360,7 +388,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
     protected $_catalogData = null;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
@@ -436,11 +464,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected $_stockResItemFac;
 
-    /**
-     * @var \Magento\CatalogInventory\Model\Stock\ItemFactory
-     */
-    protected $_stockItemFactory;
-
     /**
      * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
      */
@@ -451,6 +474,16 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected $dateTime;
 
+    /**
+     * @var \Magento\Index\Model\Indexer
+     */
+    protected $indexer;
+
+    /**
+     * @var \Magento\Indexer\Model\Indexer
+     */
+    protected $newIndexer;
+
     /**
      * @var \Magento\Framework\Logger
      */
@@ -470,7 +503,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      * @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
      * @param \Magento\Framework\Stdlib\String $string
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Catalog\Helper\Data $catalogData
      * @param \Magento\ImportExport\Model\Import\Config $importConfig
      * @param \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory $resourceFactory
@@ -486,10 +519,11 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      * @param \Magento\CatalogImportExport\Model\Import\UploaderFactory $uploaderFactory
      * @param \Magento\Framework\App\Filesystem $filesystem
      * @param \Magento\CatalogInventory\Model\Resource\Stock\ItemFactory $stockResItemFac
-     * @param \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Framework\Logger $logger
+     * @param \Magento\Index\Model\Indexer $indexer
+     * @param \Magento\Indexer\Model\Indexer $newIndexer
      * @param array $data
      */
     public function __construct(
@@ -501,7 +535,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         \Magento\ImportExport\Model\Resource\Helper $resourceHelper,
         \Magento\Framework\Stdlib\String $string,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Catalog\Helper\Data $catalogData,
         \Magento\ImportExport\Model\Import\Config $importConfig,
         \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory $resourceFactory,
@@ -517,10 +551,11 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         \Magento\CatalogImportExport\Model\Import\UploaderFactory $uploaderFactory,
         \Magento\Framework\App\Filesystem $filesystem,
         \Magento\CatalogInventory\Model\Resource\Stock\ItemFactory $stockResItemFac,
-        \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory,
         \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         \Magento\Framework\Logger $logger,
+        \Magento\Index\Model\Indexer $indexer,
+        \Magento\Indexer\Model\Indexer $newIndexer,
         array $data = array()
     ) {
         $this->_eventManager = $eventManager;
@@ -539,9 +574,10 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         $this->_uploaderFactory = $uploaderFactory;
         $this->_mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem::MEDIA_DIR);
         $this->_stockResItemFac = $stockResItemFac;
-        $this->_stockItemFactory = $stockItemFactory;
         $this->_localeDate = $localeDate;
         $this->dateTime = $dateTime;
+        $this->indexer = $indexer;
+        $this->newIndexer = $newIndexer;
         $this->_logger = $logger;
         parent::__construct($coreData, $importExportData, $importData, $config, $resource, $resourceHelper, $string);
         $this->_optionEntity = isset(
@@ -624,12 +660,12 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $this->_deleteProducts();
         } else {
             $this->_saveProducts();
-            $this->_saveStockItem();
-            $this->_saveLinks();
-            $this->getOptionEntity()->importData();
-            foreach ($this->_productTypeModels as $productType => $productTypeModel) {
+            foreach ($this->_productTypeModels as $productTypeModel) {
                 $productTypeModel->saveData();
             }
+            $this->_saveLinks();
+            $this->_saveStockItem();
+            $this->getOptionEntity()->importData();
         }
         $this->_eventManager->dispatch('catalog_product_import_finish_before', array('adapter' => $this));
         return true;
@@ -1289,6 +1325,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                                 'attribute_set_id' => $this->_newSku[$rowSku]['attr_set_id'],
                                 'type_id' => $this->_newSku[$rowSku]['type_id'],
                                 'sku' => $rowSku,
+                                'has_options' => isset($rowData['has_options']) ? $rowData['has_options'] : 0,
                                 'created_at' => $this->dateTime->now(),
                                 'updated_at' => $this->dateTime->now()
                             );
@@ -1725,38 +1762,12 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected function _saveStockItem()
     {
-        $defaultStockData = array(
-            'manage_stock' => 1,
-            'use_config_manage_stock' => 1,
-            'qty' => 0,
-            'min_qty' => 0,
-            'use_config_min_qty' => 1,
-            'min_sale_qty' => 1,
-            'use_config_min_sale_qty' => 1,
-            'max_sale_qty' => 10000,
-            'use_config_max_sale_qty' => 1,
-            'is_qty_decimal' => 0,
-            'backorders' => 0,
-            'use_config_backorders' => 1,
-            'notify_stock_qty' => 1,
-            'use_config_notify_stock_qty' => 1,
-            'enable_qty_increments' => 0,
-            'use_config_enable_qty_inc' => 1,
-            'qty_increments' => 0,
-            'use_config_qty_increments' => 1,
-            'is_in_stock' => 0,
-            'low_stock_date' => null,
-            'stock_status_changed_auto' => 0,
-            'is_decimal_divided' => 0
-        );
-
         /** @var $stockResource \Magento\CatalogInventory\Model\Resource\Stock\Item */
         $stockResource = $this->_stockResItemFac->create();
         $entityTable = $stockResource->getMainTable();
-
         while ($bunch = $this->_dataSourceModel->getNextBunch()) {
             $stockData = array();
-
+            $productIdsToReindex = array();
             // Format bunch to stock data rows
             foreach ($bunch as $rowNum => $rowData) {
                 if (!$this->isRowAllowedToImport($rowData, $rowNum)) {
@@ -1769,46 +1780,48 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
 
                 $row = array();
                 $row['product_id'] = $this->_newSku[$rowData[self::COL_SKU]]['entity_id'];
-                $row['stock_id'] = 1;
+                $productIdsToReindex[] = $row['product_id'];
+                $row['stock_id'] = \Magento\CatalogInventory\Model\Stock\Item::DEFAULT_STOCK_ID;
 
-                /** @var $stockItem \Magento\CatalogInventory\Model\Stock\Item */
-                $stockItem = $this->_stockItemFactory->create();
-                $stockItem->loadByProduct($row['product_id']);
-                $existStockData = $stockItem->getData();
+                $stockItemDo = $this->stockItemService->getStockItem($row['product_id']);
+                $existStockData = $stockItemDo->__toArray();
 
                 $row = array_merge(
-                    $defaultStockData,
-                    array_intersect_key($existStockData, $defaultStockData),
-                    array_intersect_key($rowData, $defaultStockData),
+                    $this->defaultStockData,
+                    array_intersect_key($existStockData, $this->defaultStockData),
+                    array_intersect_key($rowData, $this->defaultStockData),
                     $row
                 );
 
-                $stockItem->setData($row);
-
                 if ($this->stockItemService->isQty($this->_newSku[$rowData[self::COL_SKU]]['type_id'])) {
-                    if ($stockItem->verifyNotification()) {
-                        $stockItem->setLowStockDate(
-                            $this->_localeDate->date(
-                                null,
-                                null,
-                                null,
-                                false
-                            )->toString(
-                                \Magento\Framework\Stdlib\DateTime::DATETIME_INTERNAL_FORMAT
-                            )
+                    if ($this->stockItemService->verifyNotification($row['product_id'])) {
+                        $row['low_stock_date'] = $this->_localeDate->date(
+                            null,
+                            null,
+                            null,
+                            false
+                        )->toString(
+                            \Magento\Framework\Stdlib\DateTime::DATETIME_INTERNAL_FORMAT
                         );
                     }
-                    $stockItem->setStockStatusChangedAuto((int)(!$stockItem->verifyStock()));
+                    $row['stock_status_changed_auto'] = (int) !$this->stockItemService->verifyStock($row['product_id']);
                 } else {
-                    $stockItem->setQty(0);
+                    $row['qty'] = 0;
                 }
-                $stockData[] = $stockItem->unsetOldData()->getData();
+                $stockData[] = $row;
             }
 
             // Insert rows
-            if ($stockData) {
+            if (!empty($stockData)) {
                 $this->_connection->insertOnDuplicate($entityTable, $stockData);
             }
+
+            if ($productIdsToReindex) {
+                $this->indexer->getProcessByCode('cataloginventory_stock')->getIndexer()->reindexAll();
+                $this->indexer->getProcessByCode('catalog_product_attribute')->getIndexer()->reindexAll();
+                $this->newIndexer->load('catalog_product_category')->reindexList($productIdsToReindex);
+                $this->newIndexer->load('catalog_product_price')->reindexList($productIdsToReindex);
+            }
         }
         return $this;
     }
diff --git a/app/code/Magento/CatalogImportExport/etc/module.xml b/app/code/Magento/CatalogImportExport/etc/module.xml
index c770dde9d5e..1bf9a1ca017 100644
--- a/app/code/Magento/CatalogImportExport/etc/module.xml
+++ b/app/code/Magento/CatalogImportExport/etc/module.xml
@@ -30,6 +30,8 @@
             <module name="Magento_Catalog"/>
             <module name="Magento_Eav"/>
             <module name="Magento_ImportExport"/>
+            <module name="Magento_Index"/>
+            <module name="Magento_Indexer"/>
             <module name="Magento_Store"/>
             <module name="Magento_CatalogInventory"/>
             <module name="Magento_Customer"/>
diff --git a/app/code/Magento/CatalogInventory/Block/Qtyincrements.php b/app/code/Magento/CatalogInventory/Block/Qtyincrements.php
index 947ef525c3b..d8b57d513fe 100644
--- a/app/code/Magento/CatalogInventory/Block/Qtyincrements.php
+++ b/app/code/Magento/CatalogInventory/Block/Qtyincrements.php
@@ -47,20 +47,20 @@ class Qtyincrements extends Template implements IdentityInterface
     protected $_coreRegistry;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Framework\Registry $registry
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Framework\Registry $registry,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_coreRegistry = $registry;
diff --git a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
index ac375618d61..6577cdf072b 100644
--- a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
+++ b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
@@ -44,20 +44,20 @@ abstract class AbstractStockqty extends \Magento\Framework\View\Element\Template
     protected $_coreRegistry;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Framework\Registry $registry
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Framework\Registry $registry,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_coreRegistry = $registry;
diff --git a/app/code/Magento/CatalogInventory/Helper/Data.php b/app/code/Magento/CatalogInventory/Helper/Data.php
index cf88006dc27..54849de6512 100644
--- a/app/code/Magento/CatalogInventory/Helper/Data.php
+++ b/app/code/Magento/CatalogInventory/Helper/Data.php
@@ -64,7 +64,6 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
     /**
      * @param \Magento\Framework\App\Helper\Context $context
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
-     * @param \Magento\Catalog\Model\ProductTypes\ConfigInterface $config
      */
     public function __construct(
         \Magento\Framework\App\Helper\Context $context,
@@ -108,7 +107,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
     }
 
     /**
-     * Check if creditmemo items auto return option is enabled
+     * Check if credit memo items auto return option is enabled
      *
      * @return bool
      */
diff --git a/app/code/Magento/CatalogInventory/Helper/Minsaleqty.php b/app/code/Magento/CatalogInventory/Helper/Minsaleqty.php
index e2adf1a3ad1..2f7b6bee2e4 100644
--- a/app/code/Magento/CatalogInventory/Helper/Minsaleqty.php
+++ b/app/code/Magento/CatalogInventory/Helper/Minsaleqty.php
@@ -37,7 +37,7 @@ class Minsaleqty
      *
      * @var \Magento\Framework\App\Config\ScopeConfigInterface
      */
-    protected $_scopeConfig;
+    protected $scopeConfig;
 
     /**
      * @var \Magento\Framework\Math\Random
@@ -52,7 +52,7 @@ class Minsaleqty
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Framework\Math\Random $mathRandom
     ) {
-        $this->_scopeConfig = $scopeConfig;
+        $this->scopeConfig = $scopeConfig;
         $this->mathRandom = $mathRandom;
     }
 
@@ -62,7 +62,7 @@ class Minsaleqty
      * @param int|float|string|null $qty
      * @return float|null
      */
-    protected function _fixQty($qty)
+    protected function fixQty($qty)
     {
         return !empty($qty) ? (float) $qty : null;
     }
@@ -73,16 +73,16 @@ class Minsaleqty
      * @param int|float|string|array $value
      * @return string
      */
-    protected function _serializeValue($value)
+    protected function serializeValue($value)
     {
         if (is_numeric($value)) {
-            $data = (double)$value;
-            return (string)$data;
-        } else if (is_array($value)) {
+            $data = (float) $value;
+            return (string) $data;
+        } elseif (is_array($value)) {
             $data = array();
             foreach ($value as $groupId => $qty) {
                 if (!array_key_exists($groupId, $data)) {
-                    $data[$groupId] = $this->_fixQty($qty);
+                    $data[$groupId] = $this->fixQty($qty);
                 }
             }
             if (count($data) == 1 && array_key_exists(CustomerGroupService::CUST_GROUP_ALL, $data)) {
@@ -100,10 +100,10 @@ class Minsaleqty
      * @param int|float|string $value
      * @return array
      */
-    protected function _unserializeValue($value)
+    protected function unserializeValue($value)
     {
         if (is_numeric($value)) {
-            return array(CustomerGroupService::CUST_GROUP_ALL => $this->_fixQty($value));
+            return array(CustomerGroupService::CUST_GROUP_ALL => $this->fixQty($value));
         } elseif (is_string($value) && !empty($value)) {
             return unserialize($value);
         } else {
@@ -117,7 +117,7 @@ class Minsaleqty
      * @param string|array $value
      * @return bool
      */
-    protected function _isEncodedArrayFieldValue($value)
+    protected function isEncodedArrayFieldValue($value)
     {
         if (!is_array($value)) {
             return false;
@@ -140,12 +140,12 @@ class Minsaleqty
      * @param array $value
      * @return array
      */
-    protected function _encodeArrayFieldValue(array $value)
+    protected function encodeArrayFieldValue(array $value)
     {
         $result = array();
         foreach ($value as $groupId => $qty) {
             $resultId = $this->mathRandom->getUniqueHash('_');
-            $result[$resultId] = array('customer_group_id' => $groupId, 'min_sale_qty' => $this->_fixQty($qty));
+            $result[$resultId] = array('customer_group_id' => $groupId, 'min_sale_qty' => $this->fixQty($qty));
         }
         return $result;
     }
@@ -156,7 +156,7 @@ class Minsaleqty
      * @param array $value
      * @return array
      */
-    protected function _decodeArrayFieldValue(array $value)
+    protected function decodeArrayFieldValue(array $value)
     {
         $result = array();
         unset($value['__empty']);
@@ -168,7 +168,7 @@ class Minsaleqty
                 continue;
             }
             $groupId = $row['customer_group_id'];
-            $qty = $this->_fixQty($row['min_sale_qty']);
+            $qty = $this->fixQty($row['min_sale_qty']);
             $result[$groupId] = $qty;
         }
         return $result;
@@ -183,14 +183,14 @@ class Minsaleqty
      */
     public function getConfigValue($customerGroupId, $store = null)
     {
-        $value = $this->_scopeConfig->getValue(
+        $value = $this->scopeConfig->getValue(
             \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_MIN_SALE_QTY,
             \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
             $store
         );
-        $value = $this->_unserializeValue($value);
-        if ($this->_isEncodedArrayFieldValue($value)) {
-            $value = $this->_decodeArrayFieldValue($value);
+        $value = $this->unserializeValue($value);
+        if ($this->isEncodedArrayFieldValue($value)) {
+            $value = $this->decodeArrayFieldValue($value);
         }
         $result = null;
         foreach ($value as $groupId => $qty) {
@@ -201,7 +201,7 @@ class Minsaleqty
                 $result = $qty;
             }
         }
-        return $this->_fixQty($result);
+        return $this->fixQty($result);
     }
 
     /**
@@ -212,9 +212,9 @@ class Minsaleqty
      */
     public function makeArrayFieldValue($value)
     {
-        $value = $this->_unserializeValue($value);
-        if (!$this->_isEncodedArrayFieldValue($value)) {
-            $value = $this->_encodeArrayFieldValue($value);
+        $value = $this->unserializeValue($value);
+        if (!$this->isEncodedArrayFieldValue($value)) {
+            $value = $this->encodeArrayFieldValue($value);
         }
         return $value;
     }
@@ -227,10 +227,10 @@ class Minsaleqty
      */
     public function makeStorableArrayFieldValue($value)
     {
-        if ($this->_isEncodedArrayFieldValue($value)) {
-            $value = $this->_decodeArrayFieldValue($value);
+        if ($this->isEncodedArrayFieldValue($value)) {
+            $value = $this->decodeArrayFieldValue($value);
         }
-        $value = $this->_serializeValue($value);
+        $value = $this->serializeValue($value);
         return $value;
     }
 }
diff --git a/app/code/Magento/CatalogInventory/Model/Observer.php b/app/code/Magento/CatalogInventory/Model/Observer.php
index 18a9c826bc1..62f5455a633 100644
--- a/app/code/Magento/CatalogInventory/Model/Observer.php
+++ b/app/code/Magento/CatalogInventory/Model/Observer.php
@@ -111,6 +111,55 @@ class Observer
      */
     protected $_priceIndexer;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder
+     */
+    protected $stockItemBuilder;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\ItemRegistry
+     */
+    protected $stockItemRegistry;
+
+    /**
+     * @var array
+     */
+    protected $paramListToCheck = [
+        'use_config_min_qty' => [
+            'item' => 'stock_data/min_qty',
+            'config' => 'stock_data/use_config_min_qty',
+        ],
+        'use_config_min_sale_qty' => [
+            'item' => 'stock_data/min_sale_qty',
+            'config' => 'stock_data/use_config_min_sale_qty',
+        ],
+        'use_config_max_sale_qty' => [
+            'item' => 'stock_data/max_sale_qty',
+            'config' => 'stock_data/use_config_max_sale_qty',
+        ],
+        'use_config_backorders' => [
+            'item' => 'stock_data/backorders',
+            'config' => 'stock_data/use_config_backorders',
+        ],
+        'use_config_notify_stock_qty' => [
+            'item' => 'stock_data/notify_stock_qty',
+            'config' => 'stock_data/use_config_notify_stock_qty',
+        ],
+        'use_config_enable_qty_inc' => [
+            'item' => 'stock_data/enable_qty_increments',
+            'config' => 'stock_data/use_config_enable_qty_inc',
+        ],
+        'use_config_qty_increments' => [
+            'item' => 'stock_data/qty_increments',
+            'config' => 'stock_data/use_config_qty_increments',
+        ],
+    ];
+
     /**
      * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
      * @param Resource\Indexer\Stock $resourceIndexerStock
@@ -121,7 +170,9 @@ class Observer
      * @param \Magento\CatalogInventory\Helper\Data $catalogInventoryData
      * @param Stock\ItemFactory $stockItemFactory
      * @param StockFactory $stockFactory
-     * @param Stock\StatusFactory $stockStatusFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder $stockItemBuilder
+     * @param Stock\ItemRegistry $stockItemRegistry
      */
     public function __construct(
         \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
@@ -133,7 +184,9 @@ class Observer
         \Magento\CatalogInventory\Helper\Data $catalogInventoryData,
         \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory,
         StockFactory $stockFactory,
-        \Magento\CatalogInventory\Model\Stock\StatusFactory $stockStatusFactory
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
+        \Magento\CatalogInventory\Service\V1\Data\StockItemBuilder $stockItemBuilder,
+        \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry
     ) {
         $this->_priceIndexer = $priceIndexer;
         $this->_resourceIndexerStock = $resourceIndexerStock;
@@ -144,7 +197,9 @@ class Observer
         $this->_catalogInventoryData = $catalogInventoryData;
         $this->_stockItemFactory = $stockItemFactory;
         $this->_stockFactory = $stockFactory;
-        $this->_stockStatusFactory = $stockStatusFactory;
+        $this->stockItemService = $stockItemService;
+        $this->stockItemBuilder = $stockItemBuilder;
+        $this->stockItemRegistry = $stockItemRegistry;
     }
 
     /**
@@ -157,30 +212,8 @@ class Observer
     {
         $product = $observer->getEvent()->getProduct();
         if ($product instanceof \Magento\Catalog\Model\Product) {
-            $productId = intval($product->getId());
-            if (!isset($this->_stockItemsArray[$productId])) {
-                $this->_stockItemsArray[$productId] = $this->_stockItemFactory->create();
-            }
-            $productStockItem = $this->_stockItemsArray[$productId];
-            $productStockItem->assignProduct($product);
-        }
-        return $this;
-    }
-
-    /**
-     * Remove stock information from static variable
-     *
-     * @param EventObserver $observer
-     * @return $this
-     */
-    public function removeInventoryData($observer)
-    {
-        $product = $observer->getEvent()->getProduct();
-        if ($product instanceof \Magento\Catalog\Model\Product
-            && $product->getId()
-            && isset($this->_stockItemsArray[$product->getId()])
-        ) {
-            unset($this->_stockItemsArray[$product->getId()]);
+            $stockItem = $this->stockItemRegistry->retrieve($product->getId());
+            $this->_stockStatus->assignProduct($product, $stockItem->getStockId(), $product->getStockStatus());
         }
         return $this;
     }
@@ -198,7 +231,7 @@ class Observer
         if ($productCollection->hasFlag('require_stock_items')) {
             $this->_stockFactory->create()->addItemsToProducts($productCollection);
         } else {
-            $this->_stockStatusFactory->create()->addStockStatusToProducts($productCollection);
+            $this->_stockStatus->addStockStatusToProducts($productCollection);
         }
         return $this;
     }
@@ -233,69 +266,41 @@ class Observer
             return $this;
         }
 
-        $item = $product->getStockItem();
-        if (!$item) {
-            $item = $this->_stockItemFactory->create();
-        }
-        $this->_prepareItemForSave($item, $product);
-        $item->save();
+        $this->saveStockItemData($product);
         return $this;
     }
 
     /**
      * Prepare stock item data for save
      *
-     * @param Item $item
      * @param \Magento\Catalog\Model\Product $product
      * @return $this
      */
-    protected function _prepareItemForSave($item, $product)
+    protected function saveStockItemData($product)
     {
-        $item->addData($product->getStockData())
-            ->setProduct($product)
-            ->setProductId($product->getId())
-            ->setStockId($item->getStockId());
-
-        $paramListToCheck = [
-            'use_config_min_qty' => [
-                'item' => 'stock_data/min_qty',
-                'config' => 'stock_data/use_config_min_qty',
-            ],
-            'use_config_min_sale_qty' => [
-                'item' => 'stock_data/min_sale_qty',
-                'config' => 'stock_data/use_config_min_sale_qty',
-            ],
-            'use_config_max_sale_qty' => [
-                'item' => 'stock_data/max_sale_qty',
-                'config' => 'stock_data/use_config_max_sale_qty',
-            ],
-            'use_config_backorders' => [
-                'item' => 'stock_data/backorders',
-                'config' => 'stock_data/use_config_backorders',
-            ],
-            'use_config_notify_stock_qty' => [
-                'item' => 'stock_data/notify_stock_qty',
-                'config' => 'stock_data/use_config_notify_stock_qty',
-            ],
-            'use_config_enable_qty_inc' => [
-                'item' => 'stock_data/enable_qty_increments',
-                'config' => 'stock_data/use_config_enable_qty_inc',
-            ],
-            'use_config_qty_increments' => [
-                'item' => 'stock_data/qty_increments',
-                'config' => 'stock_data/use_config_qty_increments',
-            ],
-        ];
-        foreach ($paramListToCheck as $dataKey => $configPath) {
+        $stockItemData = $product->getStockData();
+        $stockItemData['product_id'] = $product->getId();
+        /**
+         * @todo Should be refactored together with \Magento\CatalogInventory\Model\Stock\Item::getStockId
+         */
+        $stockItemData['stock_id'] = \Magento\CatalogInventory\Model\Stock\Item::DEFAULT_STOCK_ID;
+
+        foreach ($this->paramListToCheck as $dataKey => $configPath) {
             if (null !== $product->getData($configPath['item']) && null === $product->getData($configPath['config'])) {
-                $item->setData($dataKey, false);
+                $stockItemData[$dataKey] = false;
             }
         }
 
         $originalQty = $product->getData('stock_data/original_inventory_qty');
         if (strlen($originalQty) > 0) {
-            $item->setQtyCorrection($item->getQty() - $originalQty);
+            $stockItemData['qty_correction'] = $stockItemData['qty'] - $originalQty;
         }
+
+        $stockItemDo = $this->stockItemService->getStockItem($product->getId());
+        $this->stockItemService->saveStockItem(
+            $this->stockItemBuilder->mergeDataObjectWithArray($stockItemDo, $stockItemData)
+        );
+
         return $this;
     }
 
@@ -385,7 +390,8 @@ class Observer
         } else {
             $stockItem = null;
             if ($quoteItem->getProduct()) {
-                $stockItem = $quoteItem->getProduct()->getStockItem();
+                /** @var Item $stockItem */
+                $stockItem = $this->stockItemRegistry->retrieve($quoteItem->getProduct()->getId());
             }
             $items[$productId] = array('item' => $stockItem, 'qty' => $quoteItem->getTotalQty());
         }
diff --git a/app/code/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventory.php b/app/code/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventory.php
index f3c2260206e..2df401b74d6 100644
--- a/app/code/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventory.php
+++ b/app/code/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventory.php
@@ -25,6 +25,20 @@ namespace Magento\CatalogInventory\Model\Product\CopyConstructor;
 
 class CatalogInventory implements \Magento\Catalog\Model\Product\CopyConstructorInterface
 {
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
+    /**
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     */
+    public function __construct(
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+    ) {
+        $this->stockItemService = $stockItemService;
+    }
+
     /**
      * Copy product inventory data (used for product duplicate functionality)
      *
@@ -34,23 +48,22 @@ class CatalogInventory implements \Magento\Catalog\Model\Product\CopyConstructor
      */
     public function build(\Magento\Catalog\Model\Product $product, \Magento\Catalog\Model\Product $duplicate)
     {
-        $duplicate->unsStockItem();
-        $stockData = array(
+        $stockData = [
             'use_config_min_qty' => 1,
             'use_config_min_sale_qty' => 1,
             'use_config_max_sale_qty' => 1,
             'use_config_backorders' => 1,
             'use_config_notify_stock_qty' => 1
-        );
-        /** @var \Magento\CatalogInventory\Model\Stock\Item $currentStockItem */
-        $currentStockItem = $product->getStockItem();
-        if ($currentStockItem) {
-            $stockData += array(
-                'use_config_enable_qty_inc' => $currentStockItem->getData('use_config_enable_qty_inc'),
-                'enable_qty_increments' => $currentStockItem->getData('enable_qty_increments'),
-                'use_config_qty_increments' => $currentStockItem->getData('use_config_qty_increments'),
-                'qty_increments' => $currentStockItem->getData('qty_increments')
-            );
+        ];
+        /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $currentStockItemDo */
+        $currentStockItemDo = $this->stockItemService->getStockItem($product->getId());
+        if ($currentStockItemDo->getStockId()) {
+            $stockData += [
+                'use_config_enable_qty_inc' => $currentStockItemDo->isUseConfigEnableQtyInc(),
+                'enable_qty_increments' => $currentStockItemDo->isEnableQtyIncrements(),
+                'use_config_qty_increments' => $currentStockItemDo->isUseConfigQtyIncrements(),
+                'qty_increments' => $currentStockItemDo->getQtyIncrements(),
+            ];
         }
         $duplicate->setStockData($stockData);
     }
diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php
index 043a1c889b1..57076438958 100644
--- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php
+++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php
@@ -37,16 +37,24 @@ class QuantityValidator
      */
     protected $stockItemInitializer;
 
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\ItemFactory
+     */
+    protected $stockItemFactory;
+
     /**
      * @param QuantityValidator\Initializer\Option $optionInitializer
      * @param QuantityValidator\Initializer\StockItem $stockItemInitializer
+     * @param \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory
      */
     public function __construct(
         QuantityValidator\Initializer\Option $optionInitializer,
-        QuantityValidator\Initializer\StockItem $stockItemInitializer
+        QuantityValidator\Initializer\StockItem $stockItemInitializer,
+        \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory
     ) {
         $this->optionInitializer = $optionInitializer;
         $this->stockItemInitializer = $stockItemInitializer;
+        $this->stockItemFactory = $stockItemFactory;
     }
 
     /**
@@ -73,15 +81,16 @@ class QuantityValidator
         $qty = $quoteItem->getQty();
 
         /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
-        $stockItem = $quoteItem->getProduct()->getStockItem();
+        $stockItem = $this->stockItemFactory->create()->loadByProduct($quoteItem->getProduct());
 
         $parentStockItem = false;
 
         /**
-         * Check if product in stock. For composite products check base (parent) item stosk status
+         * Check if product in stock. For composite products check base (parent) item stock status
          */
         if ($quoteItem->getParentItem()) {
-            $parentStockItem = $quoteItem->getParentItem()->getProduct()->getStockItem();
+            $parentStockItem = $this->stockItemFactory->create()
+                ->loadByProduct($quoteItem->getParentItem()->getProduct());
         }
 
         if ($stockItem) {
@@ -136,6 +145,7 @@ class QuantityValidator
             }
 
             foreach ($options as $option) {
+
                 $result = $this->optionInitializer->initialize($option, $quoteItem, $qty);
                 if ($result->getHasError()) {
                     $option->setHasError(true);
diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php
index 89e4ea5d133..35b9643b850 100644
--- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php
+++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php
@@ -32,41 +32,41 @@ class Option
      */
     protected $quoteItemQtyList;
 
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\ItemRegistry
+     */
+    protected $stockItemRegistry;
+
     /**
      * @param QuoteItemQtyList $quoteItemQtyList
+     * @param \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry
      */
-    public function __construct(QuoteItemQtyList $quoteItemQtyList)
-    {
+    public function __construct(
+        QuoteItemQtyList $quoteItemQtyList,
+        \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry
+    ) {
         $this->quoteItemQtyList = $quoteItemQtyList;
+        $this->stockItemRegistry = $stockItemRegistry;
     }
 
     /**
-     * Initialize item option
+     * Init stock item
      *
      * @param \Magento\Sales\Model\Quote\Item\Option $option
      * @param \Magento\Sales\Model\Quote\Item $quoteItem
-     * @param int $qty
-     *
-     * @return \Magento\Framework\Object
      *
+     * @return \Magento\CatalogInventory\Model\Stock\Item
      * @throws \Magento\Framework\Model\Exception
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function initialize(
+    public function getStockItem(
         \Magento\Sales\Model\Quote\Item\Option $option,
-        \Magento\Sales\Model\Quote\Item $quoteItem,
-        $qty
+        \Magento\Sales\Model\Quote\Item $quoteItem
     ) {
-        $optionValue = $option->getValue();
-        $optionQty = $qty * $optionValue;
-        $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $optionValue;
-
-        /* @var $stockItem \Magento\CatalogInventory\Model\Stock\Item */
-        $stockItem = $option->getProduct()->getStockItem();
-
-        if (!$stockItem instanceof \Magento\CatalogInventory\Model\Stock\Item) {
+        $stockItem = $this->stockItemRegistry->retrieve($option->getProduct()->getId());
+        if (!$stockItem->getId()) {
             throw new \Magento\Framework\Model\Exception(__('The stock item for Product in option is not valid.'));
         }
-
         /**
          * define that stock item is child for composite product
          */
@@ -76,6 +76,27 @@ class Option
          */
         $stockItem->setSuppressCheckQtyIncrements(true);
 
+        return $stockItem;
+    }
+
+    /**
+     * Initialize item option
+     *
+     * @param \Magento\Sales\Model\Quote\Item\Option $option
+     * @param \Magento\Sales\Model\Quote\Item $quoteItem
+     * @param int $qty
+     *
+     * @return \Magento\Framework\Object
+     * @throws \Magento\Framework\Model\Exception
+     */
+    public function initialize(
+        \Magento\Sales\Model\Quote\Item\Option $option,
+        \Magento\Sales\Model\Quote\Item $quoteItem,
+        $qty
+    ) {
+        $optionValue = $option->getValue();
+        $optionQty = $qty * $optionValue;
+        $increaseOptionQty = ($quoteItem->getQtyToAdd() ? $quoteItem->getQtyToAdd() : $qty) * $optionValue;
         $qtyForCheck = $this->quoteItemQtyList->getQty(
             $option->getProduct()->getId(),
             $quoteItem->getId(),
@@ -83,6 +104,7 @@ class Option
             $increaseOptionQty
         );
 
+        $stockItem = $this->getStockItem($option, $quoteItem);
         $result = $stockItem->checkQuoteItemQty($optionQty, $qtyForCheck, $optionValue);
 
         if (!is_null($result->getItemIsQtyDecimal())) {
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
index f2eac875267..780b01605e9 100644
--- a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
+++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
@@ -79,7 +79,7 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb
     protected $_stock;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
@@ -104,14 +104,14 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb
 
     /**
      * @param \Magento\Framework\App\Resource $resource
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\CatalogInventory\Model\StockFactory $stockFactory
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      */
     public function __construct(
         \Magento\Framework\App\Resource $resource,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\CatalogInventory\Model\StockFactory $stockFactory,
         \Magento\Framework\Stdlib\DateTime $dateTime
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock/Item.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Item.php
index 49bef032311..dbc92f34dc3 100644
--- a/app/code/Magento/CatalogInventory/Model/Resource/Stock/Item.php
+++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Item.php
@@ -102,7 +102,7 @@ class Item extends \Magento\Framework\Model\Resource\Db\AbstractDb
     {
         if ($columns === null) {
             $adapter = $this->_getReadAdapter();
-            $isManageStock = (int)$this->_scopeConfig->getValue(
+            $isManageStock = (int) $this->_scopeConfig->getValue(
                 \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_MANAGE_STOCK,
                 \Magento\Store\Model\ScopeInterface::SCOPE_STORE
             );
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status.php
index 466d1020ffa..63e7109d8d1 100644
--- a/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status.php
+++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status.php
@@ -100,17 +100,13 @@ class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb
         $websites = array_keys($object->getWebsites($websiteId));
         $adapter = $this->_getWriteAdapter();
         foreach ($websites as $websiteId) {
-            $select = $adapter->select()->from(
-                $this->getMainTable()
-            )->where(
-                'product_id = :product_id'
-            )->where(
-                'website_id = :website_id'
-            )->where(
-                'stock_id = :stock_id'
-            );
+            $select = $adapter->select()->from($this->getMainTable())
+                ->where('product_id = :product_id')
+                ->where('website_id = :website_id')
+                ->where('stock_id = :stock_id');
             $bind = array(':product_id' => $productId, ':website_id' => $websiteId, ':stock_id' => $stockId);
-            if ($row = $adapter->fetchRow($select, $bind)) {
+            $row = $adapter->fetchRow($select, $bind);
+            if ($row) {
                 $bind = array('qty' => $qty, 'stock_status' => $status);
                 $where = array(
                     $adapter->quoteInto('product_id=?', (int)$row['product_id']),
@@ -148,19 +144,11 @@ class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb
             $productIds = array($productIds);
         }
 
-        $select = $this->_getReadAdapter()->select()->from(
-            $this->getMainTable(),
-            array('product_id', 'stock_status')
-        )->where(
-            'product_id IN(?)',
-            $productIds
-        )->where(
-            'stock_id=?',
-            (int)$stockId
-        )->where(
-            'website_id=?',
-            (int)$websiteId
-        );
+        $select = $this->_getReadAdapter()->select()
+            ->from($this->getMainTable(), array('product_id', 'stock_status'))
+            ->where('product_id IN(?)', $productIds)
+            ->where('stock_id=?', (int) $stockId)
+            ->where('website_id=?', (int) $websiteId);
         return $this->_getReadAdapter()->fetchPairs($select);
     }
 
@@ -212,13 +200,10 @@ class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb
         $select = $this->_getReadAdapter()->select()->from(
             array('e' => $this->getTable('catalog_product_entity')),
             array('entity_id', 'type_id')
-        )->order(
-            'entity_id ASC'
-        )->where(
-            'entity_id > :entity_id'
-        )->limit(
-            $limit
-        );
+        )
+            ->order('entity_id ASC')
+            ->where('entity_id > :entity_id')
+            ->limit($limit);
         return $this->_getReadAdapter()->fetchPairs($select, array(':entity_id' => $lastEntityId));
     }
 
@@ -311,19 +296,10 @@ class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb
         $adapter = $this->_getReadAdapter();
 
         if ($storeId === null || $storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID) {
-            $select = $adapter->select()->from(
-                $attributeTable,
-                array('entity_id', 'value')
-            )->where(
-                'entity_id IN (?)',
-                $productIds
-            )->where(
-                'attribute_id = ?',
-                $attribute->getAttributeId()
-            )->where(
-                'store_id = ?',
-                \Magento\Store\Model\Store::DEFAULT_STORE_ID
-            );
+            $select = $adapter->select()->from($attributeTable, array('entity_id', 'value'))
+                ->where('entity_id IN (?)', $productIds)
+                ->where('attribute_id = ?', $attribute->getAttributeId())
+                ->where('store_id = ?', \Magento\Store\Model\Store::DEFAULT_STORE_ID);
 
             $rows = $adapter->fetchPairs($select);
         } else {
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status/Collection.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status/Collection.php
new file mode 100644
index 00000000000..e893c58d0d2
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status/Collection.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\CatalogInventory\Model\Resource\Stock\Status;
+
+/**
+ * Stock status collection resource model
+ */
+class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+{
+    /**
+     * Initialize resource model
+     *
+     * @return void
+     */
+    protected function _construct()
+    {
+        $this->_init(
+            'Magento\CatalogInventory\Model\Stock\Status',
+            'Magento\CatalogInventory\Model\Resource\Stock\Status'
+        );
+    }
+
+    /**
+     * Filter status by website
+     *
+     * @param \Magento\Store\Model\Website $website
+     * @return $this
+     */
+    public function addWebsiteFilter(\Magento\Store\Model\Website $website)
+    {
+        $this->addFieldToFilter('website_id', $website->getWebsiteId());
+        return $this;
+    }
+
+    /**
+     * Add filter by quantity to collection
+     *
+     * @param float $qty
+     * @return $this
+     */
+    public function addQtyFilter($qty)
+    {
+        return $this->addFieldToFilter('main_table.qty', ['lteq' => $qty]);
+    }
+
+    /**
+     * Initialize select object
+     *
+     * @return $this
+     */
+    protected function _initSelect()
+    {
+        return parent::_initSelect()->getSelect()->join(
+            array('cp_table' => $this->getTable('catalog_product_entity')),
+            'main_table.product_id = cp_table.entity_id',
+            array('sku', 'type_id')
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/Stock.php b/app/code/Magento/CatalogInventory/Model/Stock.php
index a832a2952a2..dc0245c8945 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock.php
@@ -49,10 +49,15 @@ class Stock extends \Magento\Framework\Model\AbstractModel
     const DEFAULT_STOCK_ID = 1;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
+    /**
+     * @var Stock\Status
+     */
+    protected $stockStatus;
+
     /**
      * Store model manager
      *
@@ -72,13 +77,20 @@ class Stock extends \Magento\Framework\Model\AbstractModel
      */
     protected $_collectionFactory;
 
+    /**
+     * @var \Magento\Catalog\Model\ProductFactory
+     */
+    protected $productFactory;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param Resource\Stock\Item\CollectionFactory $collectionFactory
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     * @param Stock\Status $stockStatus
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param Stock\ItemFactory $stockItemFactory
+     * @param \Magento\Catalog\Model\ProductFactory $productFactory
      * @param \Magento\Framework\Model\Resource\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\Db $resourceCollection
      * @param array $data
@@ -87,9 +99,11 @@ class Stock extends \Magento\Framework\Model\AbstractModel
         \Magento\Framework\Model\Context $context,
         \Magento\Framework\Registry $registry,
         \Magento\CatalogInventory\Model\Resource\Stock\Item\CollectionFactory $collectionFactory,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
+        \Magento\CatalogInventory\Model\Stock\Status $stockStatus,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\CatalogInventory\Model\Stock\ItemFactory $stockItemFactory,
+        \Magento\Catalog\Model\ProductFactory $productFactory,
         \Magento\Framework\Model\Resource\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\Db $resourceCollection = null,
         array $data = array()
@@ -98,8 +112,10 @@ class Stock extends \Magento\Framework\Model\AbstractModel
 
         $this->_collectionFactory = $collectionFactory;
         $this->stockItemService = $stockItemService;
+        $this->stockStatus = $stockStatus;
         $this->_storeManager = $storeManager;
         $this->_stockItemFactory = $stockItemFactory;
+        $this->productFactory = $productFactory;
     }
 
     /**
@@ -128,18 +144,20 @@ class Stock extends \Magento\Framework\Model\AbstractModel
      */
     public function addItemsToProducts($productCollection)
     {
-        $items = $this->getItemCollection()->addProductsFilter(
-            $productCollection
-        )->joinStockStatus(
-            $productCollection->getStoreId()
-        )->load();
+        $items = $this->getItemCollection()->addProductsFilter($productCollection)
+            ->joinStockStatus($productCollection->getStoreId())
+            ->load();
         $stockItems = array();
         foreach ($items as $item) {
             $stockItems[$item->getProductId()] = $item;
         }
         foreach ($productCollection as $product) {
             if (isset($stockItems[$product->getId()])) {
-                $stockItems[$product->getId()]->assignProduct($product);
+                $this->stockStatus->assignProduct(
+                    $product,
+                    $stockItems[$product->getId()]->getStockId(),
+                    $product->getStockStatus()
+                );
             }
         }
         return $this;
@@ -155,6 +173,19 @@ class Stock extends \Magento\Framework\Model\AbstractModel
         return $this->_collectionFactory->create()->addStockFilter($this->getId());
     }
 
+    /**
+     * Get Product type
+     *
+     * @param int $productId
+     * @return string
+     */
+    protected function getProductType($productId)
+    {
+        $product = $this->productFactory->create();
+        $product->load($productId);
+        return $product->getTypeId();
+    }
+
     /**
      * Prepare array($productId=>$qty) based on array($productId => array('qty'=>$qty, 'item'=>$stockItem))
      *
@@ -171,7 +202,7 @@ class Stock extends \Magento\Framework\Model\AbstractModel
                 $stockItem = $item['item'];
             }
             $canSubtractQty = $stockItem->getId() && $stockItem->canSubtractQty();
-            if ($canSubtractQty && $this->stockItemService->isQty($stockItem->getTypeId())) {
+            if ($canSubtractQty && $this->stockItemService->isQty($this->getProductType($productId))) {
                 $qtys[$productId] = $item['qty'];
             }
         }
@@ -240,7 +271,7 @@ class Stock extends \Magento\Framework\Model\AbstractModel
         }
         /** @var Item $stockItem */
         $stockItem = $this->_stockItemFactory->create()->loadByProduct($productId);
-        if ($this->stockItemService->isQty($stockItem->getTypeId())) {
+        if ($this->stockItemService->isQty($this->getProductType($productId))) {
             if ($item->getStoreId()) {
                 $stockItem->setStoreId($item->getStoreId());
             }
@@ -263,7 +294,7 @@ class Stock extends \Magento\Framework\Model\AbstractModel
     {
         /** @var Item $stockItem */
         $stockItem = $this->_stockItemFactory->create()->loadByProduct($productId);
-        if ($stockItem->getId() && $this->stockItemService->isQty($stockItem->getTypeId())) {
+        if ($stockItem->getId() && $this->stockItemService->isQty($this->getProductType($productId))) {
             $stockItem->addQty($qty);
             if ($stockItem->getCanBackInStock() && $stockItem->getQty() > $stockItem->getMinQty()) {
                 $stockItem->setIsInStock(true)->setStockStatusChangedAutomaticallyFlag(true);
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/Item.php b/app/code/Magento/CatalogInventory/Model/Stock/Item.php
index 0bad5e7727a..772335e07bd 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/Item.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/Item.php
@@ -131,6 +131,11 @@ class Item extends \Magento\Framework\Model\AbstractModel
      */
     const ENTITY = 'cataloginventory_stock_item';
 
+    /**
+     * Default stock id
+     */
+    const DEFAULT_STOCK_ID = 1;
+
     /**
      * @var array
      */
@@ -179,10 +184,15 @@ class Item extends \Magento\Framework\Model\AbstractModel
     protected $_catalogInventoryMinsaleqty;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\ItemRegistry
+     */
+    protected $stockItemRegistry;
+
     /**
      * Core store config
      *
@@ -238,7 +248,8 @@ class Item extends \Magento\Framework\Model\AbstractModel
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Index\Model\Indexer $indexer
      * @param Status $stockStatus
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     * @param ItemRegistry $stockItemRegistry
      * @param \Magento\CatalogInventory\Helper\Minsaleqty $catalogInventoryMinsaleqty
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -256,7 +267,8 @@ class Item extends \Magento\Framework\Model\AbstractModel
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Index\Model\Indexer $indexer,
         Status $stockStatus,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
+        \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry,
         \Magento\CatalogInventory\Helper\Minsaleqty $catalogInventoryMinsaleqty,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
@@ -274,6 +286,7 @@ class Item extends \Magento\Framework\Model\AbstractModel
         $this->_indexer = $indexer;
         $this->_stockStatus = $stockStatus;
         $this->stockItemService = $stockItemService;
+        $this->stockItemRegistry = $stockItemRegistry;
         $this->_catalogInventoryMinsaleqty = $catalogInventoryMinsaleqty;
         $this->_scopeConfig = $scopeConfig;
         $this->_storeManager = $storeManager;
@@ -301,7 +314,7 @@ class Item extends \Magento\Framework\Model\AbstractModel
      */
     public function getStockId()
     {
-        return 1;
+        return self::DEFAULT_STOCK_ID;
     }
 
     /**
@@ -395,26 +408,6 @@ class Item extends \Magento\Framework\Model\AbstractModel
         return $storeId;
     }
 
-    /**
-     * Adding stock data to product
-     *
-     * @param Product $product
-     * @return $this
-     */
-    public function assignProduct(Product $product)
-    {
-        if (!$this->getId() || !$this->getProductId()) {
-            $this->_getResource()->loadByProductId($this, $product->getId());
-            $this->setOrigData();
-        }
-
-        $this->setProduct($product);
-        $product->setStockItem($this);
-        $product->setIsInStock($this->getIsInStock());
-        $this->_stockStatus->assignProduct($product, $this->getStockId(), $this->getStockStatus());
-        return $this;
-    }
-
     /**
      * Retrieve minimal quantity available for item status in stock
      *
@@ -902,11 +895,10 @@ class Item extends \Magento\Framework\Model\AbstractModel
     protected function _beforeSave()
     {
         parent::_beforeSave();
-        // see if quantity is defined for this item type
-        $typeId = $this->getTypeId();
-        if ($productTypeId = $this->getProductTypeId()) {
-            $typeId = $productTypeId;
-        }
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->productFactory->create();
+        $product->load($this->getProductId());
+        $typeId = $product->getTypeId() ? $product->getTypeId() : $this->getTypeId();
 
         $isQty = $this->stockItemService->isQty($typeId);
 
@@ -1039,9 +1031,7 @@ class Item extends \Magento\Framework\Model\AbstractModel
                 foreach ($productsByGroups as $productsInGroup) {
                     $qty = 0;
                     foreach ($productsInGroup as $childProduct) {
-                        if ($childProduct->hasStockItem()) {
-                            $qty += $childProduct->getStockItem()->getStockQty();
-                        }
+                        $qty += $this->stockItemRegistry->retrieve($childProduct->getId())->getStockQty();
                     }
                     if (null === $stockQty || $qty < $stockQty) {
                         $stockQty = $qty;
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php b/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php
index 7f3d7deef5a..0ec4cd4274f 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php
@@ -61,7 +61,7 @@ class ItemRegistry extends \Magento\Framework\Model\AbstractModel
      */
     public function retrieve($productId)
     {
-        if (!isset($this->stockItemRegistry[$productId])) {
+        if (empty($this->stockItemRegistry[$productId])) {
             /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
             $stockItem = $this->stockItemFactory->create();
 
@@ -71,4 +71,14 @@ class ItemRegistry extends \Magento\Framework\Model\AbstractModel
 
         return $this->stockItemRegistry[$productId];
     }
+
+    /**
+     * @param int $productId
+     * @return $this
+     */
+    public function erase($productId)
+    {
+        $this->stockItemRegistry[$productId] = null;
+        return $this;
+    }
 }
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/Status.php b/app/code/Magento/CatalogInventory/Model/Stock/Status.php
index 747c344d39a..273029ea228 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/Status.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/Status.php
@@ -502,12 +502,6 @@ class Status extends \Magento\Framework\Model\AbstractModel
             }
         }
 
-        /* back compatible stock item */
-        foreach ($productCollection as $product) {
-            $object = new \Magento\Framework\Object(array('is_in_stock' => $product->getData('is_salable')));
-            $product->setStockItem($object);
-        }
-
         return $this;
     }
 
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteria.php b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteria.php
new file mode 100644
index 00000000000..9749bd1d058
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteria.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+/**
+ * Low stock criteria data object
+ */
+class LowStockCriteria extends AbstractObject
+{
+    /**#@+
+     * Stock status object data keys
+     */
+    const QTY = 'qty';
+    const PAGE_SIZE = 'page_size';
+    const CURRENT_PAGE = 'current_page';
+    /**#@-*/
+
+    /**
+     * @return float
+     */
+    public function getQty()
+    {
+        return $this->_get(self::QTY);
+    }
+
+    /**
+     * Get page size
+     *
+     * @return int|null
+     */
+    public function getPageSize()
+    {
+        return $this->_get(self::PAGE_SIZE);
+    }
+
+    /**
+     * Get current page
+     *
+     * @return int|null
+     */
+    public function getCurrentPage()
+    {
+        return $this->_get(self::CURRENT_PAGE);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteriaBuilder.php b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteriaBuilder.php
new file mode 100644
index 00000000000..bd8e901e44b
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteriaBuilder.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+/**
+ * Low stock criteria builder
+ */
+class LowStockCriteriaBuilder extends \Magento\Framework\Service\Data\AbstractObjectBuilder
+{
+    /**
+     * Set page size
+     *
+     * @param float $qty
+     * @return $this
+     */
+    public function setQty($qty)
+    {
+        return $this->_set(LowStockCriteria::QTY, $qty);
+    }
+
+    /**
+     * Set page size
+     *
+     * @param int $pageSize
+     * @return $this
+     */
+    public function setPageSize($pageSize)
+    {
+        return $this->_set(LowStockCriteria::PAGE_SIZE, $pageSize);
+    }
+
+    /**
+     * Set current page
+     *
+     * @param int $currentPage
+     * @return $this
+     */
+    public function setCurrentPage($currentPage)
+    {
+        return $this->_set(LowStockCriteria::CURRENT_PAGE, $currentPage);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResult.php b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResult.php
new file mode 100644
index 00000000000..9da2be72982
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResult.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+/**
+ * Low stock search result data object
+ */
+class LowStockResult extends AbstractObject
+{
+    /**#@+
+     * Low stock search result object data keys
+     */
+    const PRODUCT_SKU_LIST = 'items';
+    const SEARCH_CRITERIA = 'search_criteria';
+    const TOTAL_COUNT = 'total_count';
+    /**#@-*/
+
+    /**
+     * Get items
+     *
+     * @return string[]
+     */
+    public function getItems()
+    {
+        return is_null($this->_get(self::PRODUCT_SKU_LIST)) ? array() : $this->_get(self::PRODUCT_SKU_LIST);
+    }
+
+    /**
+     * Get search criteria
+     *
+     * @return \Magento\CatalogInventory\Service\V1\Data\LowStockCriteria
+     */
+    public function getSearchCriteria()
+    {
+        return $this->_get(self::SEARCH_CRITERIA);
+    }
+
+    /**
+     * Get total count
+     *
+     * @return int
+     */
+    public function getTotalCount()
+    {
+        return $this->_get(self::TOTAL_COUNT);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResultBuilder.php b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResultBuilder.php
new file mode 100644
index 00000000000..1f4e01a9207
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResultBuilder.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+/**
+ * Low stock search result builder object
+ */
+class LowStockResultBuilder extends \Magento\Framework\Service\Data\AbstractObjectBuilder
+{
+    /**
+     * Set search criteria
+     *
+     * @param LowStockCriteria $searchCriteria
+     * @return $this
+     */
+    public function setSearchCriteria(LowStockCriteria $searchCriteria)
+    {
+        return $this->_set(LowStockResult::SEARCH_CRITERIA, $searchCriteria);
+    }
+
+    /**
+     * Set total count
+     *
+     * @param int $totalCount
+     * @return $this
+     */
+    public function setTotalCount($totalCount)
+    {
+        return $this->_set(LowStockResult::TOTAL_COUNT, $totalCount);
+    }
+
+    /**
+     * Set items
+     *
+     * @param array $items
+     * @return $this
+     */
+    public function setItems($items)
+    {
+        return $this->_set(LowStockResult::PRODUCT_SKU_LIST, $items);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetails.php b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetails.php
new file mode 100644
index 00000000000..79c275304cf
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetails.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+/**
+ * Stock item details data object
+ */
+class StockItemDetails extends AbstractObject
+{
+    /**#@+
+     * Stock item object data keys
+     */
+    const QTY = 'qty';
+
+    const MIN_QTY = 'min_qty';
+
+    const IS_QTY_DECIMAL = 'is_qty_decimal';
+
+    const BACKORDERS = 'backorders';
+
+    const MIN_SALE_QTY = 'min_sale_qty';
+
+    const MAX_SALE_QTY = 'max_sale_qty';
+
+    const IS_IN_STOCK = 'is_in_stock';
+
+    const LOW_STOCK_DATE = 'low_stock_date';
+
+    const NOTIFY_STOCK_QTY = 'notify_stock_qty';
+
+    const MANAGE_STOCK = 'manage_stock';
+
+    const STOCK_STATUS_CHANGED_AUTO = 'stock_status_changed_auto';
+
+    const QTY_INCREMENTS = 'qty_increments';
+
+    const ENABLE_QTY_INCREMENTS = 'enable_qty_increments';
+
+    const IS_DECIMAL_DIVIDED = 'is_decimal_divided';
+    /**#@-*/
+
+    /**
+     * @return float
+     */
+    public function getQty()
+    {
+        return $this->_get(self::QTY);
+    }
+
+    /**
+     * @return float
+     */
+    public function getMinQty()
+    {
+        return $this->_get(self::MIN_QTY);
+    }
+
+    /**
+     * @return bool
+     */
+    public function getIsQtyDecimal()
+    {
+        return $this->_get(self::IS_QTY_DECIMAL);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isBackorders()
+    {
+        return $this->_get(self::BACKORDERS);
+    }
+
+    /**
+     * @return float
+     */
+    public function getMinSaleQty()
+    {
+        return $this->_get(self::MIN_SALE_QTY);
+    }
+
+    /**
+     * @return float
+     */
+    public function getMaxSaleQty()
+    {
+        return $this->_get(self::MAX_SALE_QTY);
+    }
+
+    /**
+     * @return bool
+     */
+    public function getIsInStock()
+    {
+        return $this->_get(self::IS_IN_STOCK);
+    }
+
+    /**
+     * @return string
+     */
+    public function getLowStockDate()
+    {
+        return $this->_get(self::LOW_STOCK_DATE);
+    }
+
+    /**
+     * @return float
+     */
+    public function getNotifyStockQty()
+    {
+        return $this->_get(self::NOTIFY_STOCK_QTY);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isManageStock()
+    {
+        return $this->_get(self::MANAGE_STOCK);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isStockStatusChangedAuto()
+    {
+        return $this->_get(self::STOCK_STATUS_CHANGED_AUTO);
+    }
+
+    /**
+     * @return float
+     */
+    public function getQtyIncrements()
+    {
+        return $this->_get(self::QTY_INCREMENTS);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isEnableQtyIncrements()
+    {
+        return $this->_get(self::ENABLE_QTY_INCREMENTS);
+    }
+
+    /**
+     * @return bool
+     */
+    public function getIsDecimalDivided()
+    {
+        return $this->_get(self::IS_DECIMAL_DIVIDED);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetailsBuilder.php b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetailsBuilder.php
new file mode 100644
index 00000000000..7ee9ae24a29
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetailsBuilder.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+/**
+ * Stock item details data builder
+ */
+class StockItemDetailsBuilder extends AbstractObjectBuilder
+{
+    /**
+     * @param int $qty
+     * @return $this
+     */
+    public function setQty($qty)
+    {
+        return $this->_set(StockItemDetails::QTY, $qty);
+    }
+
+    /**
+     * @param int $minQty
+     * @return $this
+     */
+    public function setMinQty($minQty)
+    {
+        return $this->_set(StockItemDetails::MIN_QTY, $minQty);
+    }
+
+    /**
+     * @param bool $isQtyDecimal
+     * @return $this
+     */
+    public function setIsQtyDecimal($isQtyDecimal)
+    {
+        return $this->_set(StockItemDetails::IS_QTY_DECIMAL, $isQtyDecimal);
+    }
+
+    /**
+     * @param bool $backorders
+     * @return $this
+     */
+    public function setBackorders($backorders)
+    {
+        return $this->_set(StockItemDetails::BACKORDERS, $backorders);
+    }
+
+    /**
+     * @param float $minSaleQty
+     * @return $this
+     */
+    public function setMinSaleQty($minSaleQty)
+    {
+        return $this->_set(StockItemDetails::MIN_SALE_QTY, $minSaleQty);
+    }
+
+    /**
+     * @param float $maxSaleQty
+     * @return $this
+     */
+    public function setMaxSaleQty($maxSaleQty)
+    {
+        return $this->_set(StockItemDetails::MAX_SALE_QTY, $maxSaleQty);
+    }
+
+    /**
+     * @param bool $isInStock
+     * @return $this
+     */
+    public function setIsInStock($isInStock)
+    {
+        return $this->_set(StockItemDetails::IS_IN_STOCK, $isInStock);
+    }
+
+    /**
+     * @param string $lowStockDate
+     * @return $this
+     */
+    public function setLowStockDate($lowStockDate)
+    {
+        return $this->_set(StockItemDetails::LOW_STOCK_DATE, $lowStockDate);
+    }
+
+    /**
+     * @param float $notifyStockQty
+     * @return $this
+     */
+    public function setNotifyStockQty($notifyStockQty)
+    {
+        return $this->_set(StockItemDetails::NOTIFY_STOCK_QTY, $notifyStockQty);
+    }
+
+    /**
+     * @param bool $manageStock
+     * @return $this
+     */
+    public function setManageStock($manageStock)
+    {
+        return $this->_set(StockItemDetails::MANAGE_STOCK, $manageStock);
+    }
+
+    /**
+     * @param bool $stockStatusChangedAuto
+     * @return $this
+     */
+    public function setStockStatusChangedAuto($stockStatusChangedAuto)
+    {
+        return $this->_set(StockItemDetails::STOCK_STATUS_CHANGED_AUTO, $stockStatusChangedAuto);
+    }
+
+    /**
+     * @param float $qtyIncrements
+     * @return $this
+     */
+    public function setQtyIncrements($qtyIncrements)
+    {
+        return $this->_set(StockItemDetails::QTY_INCREMENTS, $qtyIncrements);
+    }
+
+    /**
+     * @param bool $enableQtyIncrements
+     * @return $this
+     */
+    public function setEnableQtyIncrements($enableQtyIncrements)
+    {
+        return $this->_set(StockItemDetails::ENABLE_QTY_INCREMENTS, $enableQtyIncrements);
+    }
+
+    /**
+     * @param bool $isDecimalDivided
+     * @return $this
+     */
+    public function setIsDecimalDivided($isDecimalDivided)
+    {
+        return $this->_set(StockItemDetails::IS_DECIMAL_DIVIDED, $isDecimalDivided);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatus.php b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatus.php
new file mode 100644
index 00000000000..62d942b34a6
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatus.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+/**
+ * Stock status data object
+ */
+class StockStatus extends AbstractObject
+{
+    /**#@+
+     * Stock status object data keys
+     */
+    const STOCK_STATUS = 'is_in_stock';
+
+    const STOCK_QTY = 'qty';
+
+    /**#@-*/
+
+    /**
+     * @return bool
+     */
+    public function getIsInStock()
+    {
+        return $this->_get(self::STOCK_STATUS);
+    }
+
+    /**
+     * @return int
+     */
+    public function getQty()
+    {
+        return $this->_get(self::STOCK_QTY);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatusBuilder.php b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatusBuilder.php
new file mode 100644
index 00000000000..f5c06c0054d
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatusBuilder.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Service\V1\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+/**
+ * Stock status data builder
+ */
+class StockStatusBuilder extends AbstractObjectBuilder
+{
+}
diff --git a/app/code/Magento/CatalogInventory/Service/V1/StockItem.php b/app/code/Magento/CatalogInventory/Service/V1/StockItemService.php
similarity index 75%
rename from app/code/Magento/CatalogInventory/Service/V1/StockItem.php
rename to app/code/Magento/CatalogInventory/Service/V1/StockItemService.php
index c1d1b9cc4c6..10aad371011 100644
--- a/app/code/Magento/CatalogInventory/Service/V1/StockItem.php
+++ b/app/code/Magento/CatalogInventory/Service/V1/StockItemService.php
@@ -23,10 +23,13 @@
  */
 namespace Magento\CatalogInventory\Service\V1;
 
+use Magento\Catalog\Service\V1\Product\ProductLoader;
+use Magento\Framework\Exception\NoSuchEntityException;
+
 /**
  * Stock item service
  */
-class StockItem implements StockItemInterface
+class StockItemService implements StockItemServiceInterface
 {
     /**
      * @var \Magento\CatalogInventory\Model\Stock\ItemRegistry
@@ -50,19 +53,27 @@ class StockItem implements StockItemInterface
      */
     protected $stockItemBuilder;
 
+    /**
+     * @var ProductLoader
+     */
+    protected $productLoader;
+
     /**
      * @param \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry
      * @param \Magento\Catalog\Model\ProductTypes\ConfigInterface $config
      * @param Data\StockItemBuilder $stockItemBuilder
+     * @param ProductLoader $productLoader
      */
     public function __construct(
         \Magento\CatalogInventory\Model\Stock\ItemRegistry $stockItemRegistry,
         \Magento\Catalog\Model\ProductTypes\ConfigInterface $config,
-        Data\StockItemBuilder $stockItemBuilder
+        Data\StockItemBuilder $stockItemBuilder,
+        ProductLoader $productLoader
     ) {
         $this->stockItemRegistry = $stockItemRegistry;
         $this->config = $config;
         $this->stockItemBuilder = $stockItemBuilder;
+        $this->productLoader = $productLoader;
     }
 
     /**
@@ -77,59 +88,54 @@ class StockItem implements StockItemInterface
     }
 
     /**
-     * @param \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDo
-     * @return $this
+     * @param string $productSku
+     * @return \Magento\CatalogInventory\Service\V1\Data\StockItem
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
-    public function saveStockItem($stockItemDo)
+    public function getStockItemBySku($productSku)
     {
-        $stockItem = $this->stockItemRegistry->retrieve($stockItemDo->getProductId());
-        $stockItem->setData($stockItemDo->__toArray());
-        $stockItem->save();
-        return $this;
+        $product = $this->productLoader->load($productSku);
+        if (!$product->getId()) {
+            throw new NoSuchEntityException("Product with SKU \"{$productSku}\" does not exist");
+        }
+        $stockItem = $this->stockItemRegistry->retrieve($product->getId());
+        $this->stockItemBuilder->populateWithArray($stockItem->getData());
+        return $this->stockItemBuilder->create();
     }
 
     /**
-     * @param int $productId
-     * @param int $qty
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDo
      * @return $this
      */
-    public function subtractQty($productId, $qty)
+    public function saveStockItem($stockItemDo)
     {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        $stockItem->subtractQty($qty);
+        $stockItem = $this->stockItemRegistry->retrieve($stockItemDo->getProductId());
+        $stockItem->setData($stockItemDo->__toArray());
+        $stockItem->save();
+        $this->stockItemRegistry->erase($stockItemDo->getProductId());
         return $this;
     }
 
     /**
-     * @param int $productId
-     * @return bool
+     * @param string $productSku
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItemDetails $stockItemDetailsDo
+     * @return string
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
-    public function canSubtractQty($productId)
+    public function saveStockItemBySku($productSku, Data\StockItemDetails $stockItemDetailsDo)
     {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->canSubtractQty();
-    }
-
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return $this
-     */
-    public function addQty($productId, $qty)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        $stockItem->addQty($qty);
-        return $this;
-    }
+        $product = $this->productLoader->load($productSku);
+        if (!$product->getId()) {
+            throw new NoSuchEntityException("Product with SKU \"{$productSku}\" does not exist");
+        }
 
-    /**
-     * @param int $productId
-     * @return int
-     */
-    public function getMinQty($productId)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->getMinQty();
+        $stockItem = $this->stockItemRegistry->retrieve($product->getId());
+        $stockItemDo = $this->stockItemBuilder->populateWithArray($stockItem->getData())->create();
+        $dataToSave = $this->stockItemBuilder->mergeDataObjectWithArray(
+            $stockItemDo,
+            $stockItemDetailsDo->__toArray()
+        )->__toArray();
+        return $stockItem->setData($dataToSave)->save()->getId();
     }
 
     /**
@@ -152,16 +158,6 @@ class StockItem implements StockItemInterface
         return $stockItem->getMaxSaleQty();
     }
 
-    /**
-     * @param int $productId
-     * @return float
-     */
-    public function getNotifyStockQty($productId)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->getNotifyStockQty();
-    }
-
     /**
      * @param int $productId
      * @return bool
@@ -182,16 +178,6 @@ class StockItem implements StockItemInterface
         return $stockItem->getQtyIncrements();
     }
 
-    /**
-     * @param int $productId
-     * @return int
-     */
-    public function getBackorders($productId)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->getBackorders();
-    }
-
     /**
      * @param int $productId
      * @return int
@@ -202,27 +188,6 @@ class StockItem implements StockItemInterface
         return $stockItem->getManageStock();
     }
 
-    /**
-     * @param int $productId
-     * @return bool
-     */
-    public function getCanBackInStock($productId)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->getCanBackInStock();
-    }
-
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return bool
-     */
-    public function checkQty($productId, $qty)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->checkQty($qty);
-    }
-
     /**
      * @param int $productId
      * @param int $qty
@@ -289,17 +254,6 @@ class StockItem implements StockItemInterface
         return $stockItem->getStockQty();
     }
 
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return \Magento\Framework\Object
-     */
-    public function checkQtyIncrements($productId, $qty)
-    {
-        $stockItem = $this->stockItemRegistry->retrieve($productId);
-        return $stockItem->checkQtyIncrements($qty);
-    }
-
     /**
      * @param int $productTypeId
      * @return bool
@@ -315,7 +269,7 @@ class StockItem implements StockItemInterface
 
     /**
      * @param int|null $filter
-     * @return bool
+     * @return bool|array
      */
     public function getIsQtyTypeIds($filter = null)
     {
diff --git a/app/code/Magento/CatalogInventory/Service/V1/StockItemInterface.php b/app/code/Magento/CatalogInventory/Service/V1/StockItemServiceInterface.php
similarity index 73%
rename from app/code/Magento/CatalogInventory/Service/V1/StockItemInterface.php
rename to app/code/Magento/CatalogInventory/Service/V1/StockItemServiceInterface.php
index fa2d737de7a..f99ff0a56d9 100644
--- a/app/code/Magento/CatalogInventory/Service/V1/StockItemInterface.php
+++ b/app/code/Magento/CatalogInventory/Service/V1/StockItemServiceInterface.php
@@ -26,7 +26,7 @@ namespace Magento\CatalogInventory\Service\V1;
 /**
  * Stock item interface
  */
-interface StockItemInterface
+interface StockItemServiceInterface
 {
     /**
      * @param int $productId
@@ -35,36 +35,25 @@ interface StockItemInterface
     public function getStockItem($productId);
 
     /**
-     * @param \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItem
+     * @param string $productSku
      * @return \Magento\CatalogInventory\Service\V1\Data\StockItem
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
-    public function saveStockItem($stockItem);
-
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return $this
-     */
-    public function subtractQty($productId, $qty);
-
-    /**
-     * @param int $productId
-     * @return bool
-     */
-    public function canSubtractQty($productId);
+    public function getStockItemBySku($productSku);
 
     /**
-     * @param int $productId
-     * @param int $qty
-     * @return $this
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItem
+     * @return \Magento\CatalogInventory\Service\V1\Data\StockItem
      */
-    public function addQty($productId, $qty);
+    public function saveStockItem($stockItem);
 
     /**
-     * @param int $productId
-     * @return int
+     * @param string $productSku
+     * @param \Magento\CatalogInventory\Service\V1\Data\StockItemDetails $stockItemDetailsDo
+     * @return string
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
-    public function getMinQty($productId);
+    public function saveStockItemBySku($productSku, Data\StockItemDetails $stockItemDetailsDo);
 
     /**
      * @param int $productId
@@ -78,12 +67,6 @@ interface StockItemInterface
      */
     public function getMaxSaleQty($productId);
 
-    /**
-     * @param int $productId
-     * @return int
-     */
-    public function getNotifyStockQty($productId);
-
     /**
      * @param int $productId
      * @return bool
@@ -96,31 +79,12 @@ interface StockItemInterface
      */
     public function getQtyIncrements($productId);
 
-    /**
-     * @param int $productId
-     * @return int
-     */
-    public function getBackorders($productId);
-
     /**
      * @param int $productId
      * @return int mixed
      */
     public function getManageStock($productId);
 
-    /**
-     * @param int $productId
-     * @return bool
-     */
-    public function getCanBackInStock($productId);
-
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return bool
-     */
-    public function checkQty($productId, $qty);
-
     /**
      * @param int $productId
      * @param int $qty
@@ -163,13 +127,6 @@ interface StockItemInterface
      */
     public function getStockQty($productId);
 
-    /**
-     * @param int $productId
-     * @param int $qty
-     * @return bool
-     */
-    public function checkQtyIncrements($productId, $qty);
-
     /**
      * @param int $productTypeId
      * @return bool
diff --git a/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php b/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php
index 9457bc59849..c4fbbec8f3c 100644
--- a/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php
+++ b/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php
@@ -25,6 +25,7 @@ namespace Magento\CatalogInventory\Service\V1;
 
 use Magento\CatalogInventory\Model\Stock;
 use Magento\CatalogInventory\Model\Stock\Status;
+use Magento\Framework\Exception\NoSuchEntityException;
 
 /**
  * Service related to Product Stock Status
@@ -36,19 +37,141 @@ class StockStatusService implements StockStatusServiceInterface
      */
     protected $stockStatus;
 
+    /**
+     * @var \Magento\Store\Model\Resolver\Website
+     */
+    protected $scopeResolver;
+
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\ProductLoader
+     */
+    protected $productLoader;
+
+    /**
+     * @var StockItemService
+     */
+    protected $stockItemService;
+
+    /**
+     * @var Data\StockStatusBuilder
+     */
+    protected $stockStatusBuilder;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Resource\Stock\Status\CollectionFactory
+     */
+    protected $itemsFactory;
+
+    /**
+     * @var Data\LowStockResultBuilder
+     */
+    protected $lowStockResultBuilder;
+
     /**
      * @param Status $stockStatus
+     * @param StockItemService $stockItemService
+     * @param \Magento\Catalog\Service\V1\Product\ProductLoader $productLoader
+     * @param \Magento\Store\Model\Resolver\Website $scopeResolver
+     * @param Data\StockStatusBuilder $stockStatusBuilder
+     * @param \Magento\CatalogInventory\Model\Resource\Stock\Status\CollectionFactory $itemsFactory
+     * @param Data\LowStockResultBuilder $lowStockResultBuilder
      */
-    public function __construct(Status $stockStatus)
-    {
+    public function __construct(
+        Status $stockStatus,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
+        \Magento\Catalog\Service\V1\Product\ProductLoader $productLoader,
+        \Magento\Store\Model\Resolver\Website $scopeResolver,
+        Data\StockStatusBuilder $stockStatusBuilder,
+        \Magento\CatalogInventory\Model\Resource\Stock\Status\CollectionFactory $itemsFactory,
+        Data\LowStockResultBuilder $lowStockResultBuilder
+    ) {
         $this->stockStatus = $stockStatus;
+        $this->stockItemService = $stockItemService;
+        $this->productLoader = $productLoader;
+        $this->scopeResolver = $scopeResolver;
+        $this->stockStatusBuilder = $stockStatusBuilder;
+        $this->itemsFactory = $itemsFactory;
+        $this->lowStockResultBuilder = $lowStockResultBuilder;
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getProductStockStatus($productIds, $websiteId, $stockId = Stock::DEFAULT_STOCK_ID)
+    public function getProductStockStatus($productId, $websiteId, $stockId = Stock::DEFAULT_STOCK_ID)
     {
-        return $this->stockStatus->getProductStockStatus($productIds, $websiteId, $stockId);
+        $stockStatusData = $this->stockStatus->getProductStockStatus([$productId], $websiteId, $stockId);
+        $stockStatus = empty($stockStatusData[$productId]) ? null : $stockStatusData[$productId];
+
+        return $stockStatus;
+    }
+
+    /**
+     * Assign Stock Status to Product
+     *
+     * @param \Magento\Catalog\Model\Product $product
+     * @param int $stockId
+     * @param int $stockStatus
+     * @return \Magento\CatalogInventory\Service\V1\StockStatusService
+     */
+    public function assignProduct(
+        \Magento\Catalog\Model\Product $product,
+        $stockId = Stock::DEFAULT_STOCK_ID,
+        $stockStatus = null
+    ) {
+        $this->stockStatus->assignProduct($product, $stockId, $stockStatus);
+        return $this;
+    }
+
+    /**
+     * {inheritdoc}
+     */
+    public function getProductStockStatusBySku($sku)
+    {
+        $product = $this->productLoader->load($sku);
+        $productId = $product->getId();
+        if (!$productId) {
+            throw new NoSuchEntityException("Product with SKU \"{$sku}\" does not exist");
+        }
+
+        $data = $this->stockStatus->getProductStockStatus(
+            [$productId],
+            $this->scopeResolver->getScope()->getId()
+        );
+        $stockStatus = (bool)$data[$productId];
+
+        $result = [
+            Data\StockStatus::STOCK_STATUS => $stockStatus,
+            Data\StockStatus::STOCK_QTY => $this->stockItemService->getStockQty($productId)
+        ];
+
+        $this->stockStatusBuilder->populateWithArray($result);
+
+        return $this->stockStatusBuilder->create();
+    }
+
+    /**
+     * Retrieves a list of SKU's with low inventory qty
+     *
+     * {@inheritdoc}
+     */
+    public function getLowStockItems($lowStockCriteria)
+    {
+        /** @var \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection $itemCollection */
+        $itemCollection = $this->itemsFactory->create();
+        $itemCollection->addWebsiteFilter($this->scopeResolver->getScope());
+        $itemCollection->addQtyFilter($lowStockCriteria->getQty());
+        $itemCollection->setCurPage($lowStockCriteria->getCurrentPage());
+        $itemCollection->setPageSize($lowStockCriteria->getPageSize());
+
+        $countOfItems = $itemCollection->getSize();
+        $listOfSku = [];
+        foreach ($itemCollection as $item) {
+            $listOfSku[] = $item->getSku();
+        }
+
+        $this->lowStockResultBuilder->setSearchCriteria($lowStockCriteria);
+        $this->lowStockResultBuilder->setTotalCount($countOfItems);
+        $this->lowStockResultBuilder->setItems($listOfSku);
+        return $this->lowStockResultBuilder->create();
     }
 }
diff --git a/app/code/Magento/CatalogInventory/Service/V1/StockStatusServiceInterface.php b/app/code/Magento/CatalogInventory/Service/V1/StockStatusServiceInterface.php
index 30214e24014..95fca6c21a1 100644
--- a/app/code/Magento/CatalogInventory/Service/V1/StockStatusServiceInterface.php
+++ b/app/code/Magento/CatalogInventory/Service/V1/StockStatusServiceInterface.php
@@ -33,10 +33,25 @@ interface StockStatusServiceInterface
     /**
      * Retrieve Product Stock Status
      *
-     * @param int[] $productIds
+     * @param int $productId
      * @param int $websiteId
      * @param int $stockId
      * @return array
      */
-    public function getProductStockStatus($productIds, $websiteId, $stockId = Stock::DEFAULT_STOCK_ID);
+    public function getProductStockStatus($productId, $websiteId, $stockId = Stock::DEFAULT_STOCK_ID);
+
+    /**
+     * @param string $sku
+     * @return \Magento\CatalogInventory\Service\V1\Data\StockStatus
+     * @throw \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function getProductStockStatusBySku($sku);
+
+    /**
+     * Retrieves a list of SKU's with low inventory qty
+     *
+     * @param \Magento\CatalogInventory\Service\V1\Data\LowStockCriteria $lowStockCriteria
+     * @return \Magento\CatalogInventory\Service\V1\Data\LowStockResult contains string[]
+     */
+    public function getLowStockItems($lowStockCriteria);
 }
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml
index bad18e477cf..1d3ac028b4b 100644
--- a/app/code/Magento/CatalogInventory/etc/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/di.xml
@@ -25,6 +25,7 @@
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
     <preference for="Magento\CatalogInventory\Service\V1\StockStatusServiceInterface" type="Magento\CatalogInventory\Service\V1\StockStatusService" />
+    <preference for="Magento\CatalogInventory\Service\V1\StockItemServiceInterface" type="Magento\CatalogInventory\Service\V1\StockItemService" />
     <type name="Magento\CatalogInventory\Model\Observer">
         <arguments>
             <argument name="resourceIndexerStock" xsi:type="object">Magento\CatalogInventory\Model\Resource\Indexer\Stock\Proxy</argument>
diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml
index e1ec586ba12..e68c5c32c53 100644
--- a/app/code/Magento/CatalogInventory/etc/events.xml
+++ b/app/code/Magento/CatalogInventory/etc/events.xml
@@ -30,9 +30,6 @@
     <event name="catalog_product_load_after">
         <observer name="inventory" instance="Magento\CatalogInventory\Model\Observer" method="addInventoryData" />
     </event>
-    <event name="catalog_product_clear">
-        <observer name="inventory" instance="Magento\CatalogInventory\Model\Observer" method="removeInventoryData" />
-    </event>
     <event name="catalog_product_collection_load_after">
         <observer name="inventory" instance="Magento\CatalogInventory\Model\Observer" method="addStockStatusToCollection" />
     </event>
diff --git a/app/code/Magento/CatalogInventory/etc/webapi.xml b/app/code/Magento/CatalogInventory/etc/webapi.xml
new file mode 100644
index 00000000000..de443919ca7
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/etc/webapi.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="../../../../../app/code/Magento/Webapi/etc/webapi.xsd">
+    <route url="/V1/stockItem/:productSku" method="GET">
+        <service class="Magento\CatalogInventory\Service\V1\StockItemServiceInterface" method="getStockItemBySku"/>
+        <resources>
+            <resource ref="Magento_CatalogInventory::cataloginventory"/>
+        </resources>
+    </route>
+    <route url="/V1/stockItem/:productSku" method="POST">
+        <service class="Magento\CatalogInventory\Service\V1\StockItemServiceInterface" method="saveStockItemBySku"/>
+        <resources>
+            <resource ref="Magento_CatalogInventory::cataloginventory"/>
+        </resources>
+    </route>
+    <route url="/V1/stockItem/status/:sku" method="GET">
+        <service class="Magento\CatalogInventory\Service\V1\StockStatusServiceInterface"
+                 method="getProductStockStatusBySku"/>
+        <resources>
+            <resource ref="Magento_CatalogInventory::cataloginventory"/>
+        </resources>
+    </route>
+    <route url="/V1/stockItem/lowStock/" method="PUT">
+        <service class="Magento\CatalogInventory\Service\V1\StockStatusServiceInterface" method="getLowStockItems"/>
+        <resources>
+            <resource ref="Magento_CatalogInventory::cataloginventory"/>
+        </resources>
+    </route>
+</routes>
diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php
index 487e127dd3d..aa41d5983ac 100644
--- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php
+++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php
@@ -127,7 +127,7 @@ class Widget extends Action
             )->setCategoryIds(
                 array($categoryId)
             );
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $block->getTreeJson($category)
             );
         }
diff --git a/app/code/Magento/CatalogSearch/Controller/Ajax.php b/app/code/Magento/CatalogSearch/Controller/Ajax.php
index dcddb02ece0..319fb28ed17 100644
--- a/app/code/Magento/CatalogSearch/Controller/Ajax.php
+++ b/app/code/Magento/CatalogSearch/Controller/Ajax.php
@@ -43,6 +43,6 @@ class Ajax extends Action
         }
 
         $suggestData = $this->_objectManager->get('Magento\CatalogSearch\Helper\Data')->getSuggestData();
-        $this->getResponse()->setHeader('Content-type', 'application/json', true)->setBody(json_encode($suggestData));
+        $this->getResponse()->representJson(json_encode($suggestData));
     }
 }
diff --git a/app/code/Magento/Centinel/Controller/Adminhtml/Centinel/Index.php b/app/code/Magento/Centinel/Controller/Adminhtml/Centinel/Index.php
index fb010b723c4..54f37d367e8 100644
--- a/app/code/Magento/Centinel/Controller/Adminhtml/Centinel/Index.php
+++ b/app/code/Magento/Centinel/Controller/Adminhtml/Centinel/Index.php
@@ -71,7 +71,9 @@ class Index extends \Magento\Backend\App\Action
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
             $result['message'] = __('Validation failed.');
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Checkout/Controller/Onepage.php b/app/code/Magento/Checkout/Controller/Onepage.php
index e2bec519374..6e3c6b7b7b8 100755
--- a/app/code/Magento/Checkout/Controller/Onepage.php
+++ b/app/code/Magento/Checkout/Controller/Onepage.php
@@ -344,7 +344,9 @@ class Onepage extends Action
         if ($this->getRequest()->isPost()) {
             $method = $this->getRequest()->getPost('method');
             $result = $this->getOnepage()->saveCheckoutMethod($method);
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -388,7 +390,9 @@ class Onepage extends Action
                 }
             }
 
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -414,7 +418,9 @@ class Onepage extends Action
                     'html' => $this->_getShippingMethodsHtml()
                 );
             }
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -438,7 +444,7 @@ class Onepage extends Action
                     array('request' => $this->getRequest(), 'quote' => $this->getOnepage()->getQuote())
                 );
                 $this->getOnepage()->getQuote()->collectTotals();
-                $this->getResponse()->setBody(
+                $this->getResponse()->representJson(
                     $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
                 );
 
@@ -449,7 +455,9 @@ class Onepage extends Action
                 );
             }
             $this->getOnepage()->getQuote()->collectTotals()->save();
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -494,7 +502,9 @@ class Onepage extends Action
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
             $result['error'] = __('Unable to set Payment Method');
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -564,7 +574,7 @@ class Onepage extends Action
                 $result['error_messages'] = __(
                     'Please agree to all the terms and conditions before placing the order.'
                 );
-                $this->getResponse()->setBody(
+                $this->getResponse()->representJson(
                     $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
                 );
                 return;
@@ -643,7 +653,9 @@ class Onepage extends Action
             $result['redirect'] = $redirectUrl;
         }
 
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Checkout/Model/Cart.php b/app/code/Magento/Checkout/Model/Cart.php
index 6e08d5989b4..5b9813aa09c 100644
--- a/app/code/Magento/Checkout/Model/Cart.php
+++ b/app/code/Magento/Checkout/Model/Cart.php
@@ -89,7 +89,7 @@ class Cart extends \Magento\Framework\Object implements \Magento\Checkout\Model\
     protected $messageManager;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
@@ -102,7 +102,7 @@ class Cart extends \Magento\Framework\Object implements \Magento\Checkout\Model\
      * @param Session $checkoutSession
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Framework\Message\ManagerInterface $messageManager
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -114,7 +114,7 @@ class Cart extends \Magento\Framework\Object implements \Magento\Checkout\Model\
         Session $checkoutSession,
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Framework\Message\ManagerInterface $messageManager,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_eventManager = $eventManager;
diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images.php
index 2bb5d511fe5..c572f8794fb 100644
--- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images.php
+++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images.php
@@ -90,14 +90,16 @@ class Images extends \Magento\Backend\App\Action
     {
         try {
             $this->_initAction();
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_view->getLayout()->createBlock(
                     'Magento\Cms\Block\Adminhtml\Wysiwyg\Images\Tree'
                 )->getTreeJson()
             );
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -114,7 +116,9 @@ class Images extends \Magento\Backend\App\Action
             $this->_view->renderLayout();
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -133,7 +137,9 @@ class Images extends \Magento\Backend\App\Action
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -148,7 +154,9 @@ class Images extends \Magento\Backend\App\Action
             $this->getStorage()->deleteDirectory($path);
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -180,7 +188,9 @@ class Images extends \Magento\Backend\App\Action
             }
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -198,7 +208,9 @@ class Images extends \Magento\Backend\App\Action
         } catch (\Exception $e) {
             $result = array('error' => $e->getMessage(), 'errorcode' => $e->getCode());
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
index 3425fda9d52..74bb63b1fa1 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
@@ -58,6 +58,11 @@ class Matrix extends \Magento\Backend\Block\Template
      */
     protected $_localeCurrency;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemServiceInterface
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurableType
@@ -65,6 +70,7 @@ class Matrix extends \Magento\Backend\Block\Template
      * @param \Magento\Catalog\Model\ProductFactory $productFactory
      * @param \Magento\Framework\Registry $coreRegistry
      * @param \Magento\Framework\Locale\CurrencyInterface $localeCurrency
+     * @param \Magento\CatalogInventory\Service\V1\StockItemServiceInterface $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -74,6 +80,7 @@ class Matrix extends \Magento\Backend\Block\Template
         \Magento\Catalog\Model\ProductFactory $productFactory,
         \Magento\Framework\Registry $coreRegistry,
         \Magento\Framework\Locale\CurrencyInterface $localeCurrency,
+        \Magento\CatalogInventory\Service\V1\StockItemServiceInterface $stockItemService,
         array $data = array()
     ) {
         $this->_configurableType = $configurableType;
@@ -81,6 +88,7 @@ class Matrix extends \Magento\Backend\Block\Template
         $this->_config = $config;
         $this->_coreRegistry = $coreRegistry;
         $this->_localeCurrency = $localeCurrency;
+        $this->stockItemService = $stockItemService;
         parent::__construct($context, $data);
     }
 
@@ -287,4 +295,13 @@ class Matrix extends \Magento\Backend\Block\Template
     {
         return $this->getUrl('catalog/product_gallery/upload');
     }
+
+    /**
+     * @param int $productId
+     * @return float
+     */
+    public function getProductStockQty($productId)
+    {
+        return $this->stockItemService->getStockItem($productId)->getQty();
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributes.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributes.php
index 676dbc3aee0..e6f5549ad2f 100644
--- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributes.php
+++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributes.php
@@ -71,7 +71,7 @@ class SuggestConfigurableAttributes extends Action
      */
     public function indexAction()
     {
-        $this->getResponse()->setBody(
+        $this->getResponse()->representJson(
             $this->coreHelper->jsonEncode(
                 $this->attributeList->getSuggestedAttributes($this->getRequest()->getParam('label_part'))
             )
diff --git a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProduct.php b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProduct.php
index 6cb61684da9..a1a12127f1e 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProduct.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProduct.php
@@ -31,24 +31,23 @@ class ConfigurableProduct
      * Initialize stock item for configurable product type
      *
      * @param \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option $subject
+     * @param callable $proceed
      * @param \Magento\Sales\Model\Quote\Item\Option $option
      * @param \Magento\Sales\Model\Quote\Item $quoteItem
-     * @param int $qty
      *
-     * @return void
+     * @return \Magento\CatalogInventory\Model\Stock\Item
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function beforeInitialize(
+    public function aroundGetStockItem(
         \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option $subject,
+        \Closure $proceed,
         \Magento\Sales\Model\Quote\Item\Option $option,
-        \Magento\Sales\Model\Quote\Item $quoteItem,
-        $qty
+        \Magento\Sales\Model\Quote\Item $quoteItem
     ) {
-        /* @var $stockItem \Magento\CatalogInventory\Model\Stock\Item */
-        $stockItem = $option->getProduct()->getStockItem();
-
+        $stockItem = $proceed($option, $quoteItem);
         if ($quoteItem->getProductType() == \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE) {
             $stockItem->setProductName($quoteItem->getName());
         }
+        return $stockItem;
     }
 }
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
index 249759260ae..1dddc29458c 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
@@ -131,7 +131,7 @@ $productByUsedAttributes = $this->getAssociatedProducts();
                     <td class="col-price" data-column="price">
                         <?php echo $this->renderPrice($price);?>
                     </td>
-                    <td class="col-qty" data-column="qty"><?php echo $product->getStockItem()->getQty()?></td>
+                    <td class="col-qty" data-column="qty"><?php echo $this->getProductStockQty($product->getId()) ?></td>
                     <td class="col-weight" data-column="weight"><?php echo $product->getWeight()?></td>
                     <?php
                     foreach ($usedProductAttributes as $attribute) {
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index.php b/app/code/Magento/Customer/Controller/Adminhtml/Index.php
index 7a07a12c9b6..3f943deeb08 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Index.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index.php
@@ -793,7 +793,7 @@ class Index extends \Magento\Backend\App\Action
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/System/Config/Validatevat.php b/app/code/Magento/Customer/Controller/Adminhtml/System/Config/Validatevat.php
index 3e3b0bd1d94..0c45c2ec434 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/System/Config/Validatevat.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/System/Config/Validatevat.php
@@ -85,6 +85,6 @@ class Validatevat extends \Magento\Backend\App\Action
         );
 
         $body = $coreHelper->jsonEncode(array('valid' => $valid, 'group' => $groupId, 'success' => $success));
-        $this->getResponse()->setBody($body);
+        $this->getResponse()->representJson($body);
     }
 }
diff --git a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor.php b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor.php
index 212faed41be..c3be7c77fd3 100644
--- a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor.php
+++ b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor.php
@@ -108,7 +108,7 @@ class Editor extends \Magento\Backend\App\Action
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
             $response = array('error' => __('Sorry, but we can\'t load the theme list.'));
         }
-        $this->getResponse()->setBody($coreHelper->jsonEncode($response));
+        $this->getResponse()->representJson($coreHelper->jsonEncode($response));
     }
 
     /**
@@ -204,12 +204,9 @@ class Editor extends \Magento\Backend\App\Action
             $response = array('message' => $successMessage, 'themeId' => $themeCustomization->getId());
         } catch (\Exception $e) {
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
-            $this->getResponse()->setBody(
-                $coreHelper->jsonEncode(array('error' => __('This theme is not assigned.')))
-            );
             $response = array('error' => true, 'message' => __('This theme is not assigned.'));
         }
-        $this->getResponse()->setBody($coreHelper->jsonEncode($response));
+        $this->getResponse()->representJson($coreHelper->jsonEncode($response));
     }
 
     /**
@@ -239,7 +236,7 @@ class Editor extends \Magento\Backend\App\Action
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
             $response = array('error' => true, 'message' => __('This theme is not saved.'));
         }
-        $this->getResponse()->setBody($coreHelper->jsonEncode($response));
+        $this->getResponse()->representJson($coreHelper->jsonEncode($response));
     }
 
     /**
@@ -281,7 +278,7 @@ class Editor extends \Magento\Backend\App\Action
 
         /** @var $coreHelper \Magento\Core\Helper\Data */
         $coreHelper = $this->_objectManager->get('Magento\Core\Helper\Data');
-        $this->getResponse()->setBody($coreHelper->jsonEncode($response));
+        $this->getResponse()->representJson($coreHelper->jsonEncode($response));
     }
 
     /**
@@ -359,7 +356,7 @@ class Editor extends \Magento\Backend\App\Action
         }
         /** @var $coreHelper \Magento\Core\Helper\Data */
         $coreHelper = $this->_objectManager->get('Magento\Core\Helper\Data');
-        $this->getResponse()->setBody($coreHelper->jsonEncode($response));
+        $this->getResponse()->representJson($coreHelper->jsonEncode($response));
     }
 
     /**
diff --git a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Files.php b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Files.php
index 6698e14fd5e..5024da14ad9 100644
--- a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Files.php
+++ b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Files.php
@@ -36,7 +36,7 @@ class Files extends \Magento\Theme\Controller\Adminhtml\System\Design\Wysiwyg\Fi
     public function treeJsonAction()
     {
         try {
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_view->getLayout()->createBlock(
                     'Magento\DesignEditor\Block\Adminhtml\Editor\Tools\Files\Tree'
                 )->getTreeJson(
@@ -45,7 +45,9 @@ class Files extends \Magento\Theme\Controller\Adminhtml\System\Design\Wysiwyg\Fi
             );
         } catch (\Exception $e) {
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array()));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array())
+            );
         }
     }
 
@@ -66,7 +68,9 @@ class Files extends \Magento\Theme\Controller\Adminhtml\System\Design\Wysiwyg\Fi
             );
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 }
diff --git a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Tools.php b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Tools.php
index 9e2ba5c8dc3..bacd1b8d584 100644
--- a/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Tools.php
+++ b/app/code/Magento/DesignEditor/Controller/Adminhtml/System/Design/Editor/Tools.php
@@ -80,7 +80,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => __('We cannot upload the CSS file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -114,7 +116,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => __('We can\'t save the custom css file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -130,7 +134,9 @@ class Tools extends \Magento\Backend\App\Action
             $customization = $editableTheme->getCustomization();
             $customJsFiles = $customization->getFilesByType(\Magento\Framework\View\Design\Theme\Customization\File\Js::TYPE);
             $result = array('error' => false, 'files' => $customization->generateFileInfo($customJsFiles));
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         } catch (\Exception $e) {
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
@@ -165,7 +171,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => __('We cannot upload the JS file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -210,7 +218,9 @@ class Tools extends \Magento\Backend\App\Action
             $result = array('error' => true, 'message' => __('We cannot upload the CSS file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -244,7 +254,9 @@ class Tools extends \Magento\Backend\App\Action
             $result = array('error' => true, 'message' => __('We can\'t save image sizes.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -286,7 +298,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => $errorMessage);
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -330,7 +344,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => $errorMessage);
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -377,7 +393,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => $errorMessage);
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -430,7 +448,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => $errorMessage);
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
@@ -464,7 +484,9 @@ class Tools extends \Magento\Backend\App\Action
             $response = array('error' => true, 'message' => $errorMessage);
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php
index 0022a288e52..6b24d9a09ba 100644
--- a/app/code/Magento/Dhl/Model/Carrier.php
+++ b/app/code/Magento/Dhl/Model/Carrier.php
@@ -28,25 +28,26 @@ use Magento\Sales\Model\Quote\Address\RateRequest;
 use Magento\Sales\Model\Quote\Address\RateResult\Error;
 use Magento\Shipping\Model\Carrier\AbstractCarrier;
 use Magento\Shipping\Model\Rate\Result;
+use Magento\Catalog\Model\Product\Type;
 
 /**
  * DHL International (API v1.4)
  */
 class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shipping\Model\Carrier\CarrierInterface
 {
-    /**
+    /**#@+
      * Carrier Product indicator
      */
     const DHL_CONTENT_TYPE_DOC = 'D';
-
     const DHL_CONTENT_TYPE_NON_DOC = 'N';
+    /**#@-*/
 
-    /**
+    /**#@+
      * Minimum allowed values for shipping package dimensions
      */
     const DIMENSION_MIN_CM = 3;
-
     const DIMENSION_MIN_IN = 1;
+    /**#@-*/
 
     /**
      * Container types that could be customized
@@ -65,21 +66,21 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      *
      * @var RateRequest|null
      */
-    protected $_request = null;
+    protected $_request;
 
     /**
      * Rate result data
      *
      * @var Result|null
      */
-    protected $_result = null;
+    protected $_result;
 
     /**
      * Countries parameters data
      *
      * @var \Magento\Shipping\Model\Simplexml\Element|null
      */
-    protected $_countryParams = null;
+    protected $_countryParams;
 
     /**
      * Errors placeholder
@@ -198,6 +199,11 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      */
     protected $_httpClientFactory;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Sales\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
@@ -221,6 +227,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      * @param \Magento\Framework\App\Filesystem $filesystem
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -237,6 +244,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         \Magento\Directory\Model\CountryFactory $countryFactory,
         \Magento\Directory\Model\CurrencyFactory $currencyFactory,
         \Magento\Directory\Helper\Data $directoryData,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Shipping\Helper\Carrier $carrierHelper,
         \Magento\Framework\Stdlib\DateTime\DateTime $coreDate,
         \Magento\Framework\Module\Dir\Reader $configReader,
@@ -257,6 +265,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $this->mathDivision = $mathDivision;
         $this->_dateTime = $dateTime;
         $this->_httpClientFactory = $httpClientFactory;
+        $this->stockItemService = $stockItemService;
         parent::__construct(
             $scopeConfig,
             $rateErrorFactory,
@@ -271,6 +280,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             $countryFactory,
             $currencyFactory,
             $directoryData,
+            $stockItemService,
             $data
         );
         if ($this->getConfigData('content_type') == self::DHL_CONTENT_TYPE_DOC) {
@@ -322,21 +332,14 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $origCity = $this->_getDefaultValue($requestDhl->getOrigCity(), Shipment::XML_PATH_STORE_CITY);
         $origPostcode = $this->_getDefaultValue($requestDhl->getOrigPostcode(), Shipment::XML_PATH_STORE_ZIP);
 
-        $requestDhl->setOrigCompanyName(
-            $origCompanyName
-        )->setCountryId(
-            $origCountryId
-        )->setOrigState(
-            $origState
-        )->setOrigCity(
-            $origCity
-        )->setOrigPostal(
-            $origPostcode
-        );
+        $requestDhl->setOrigCompanyName($origCompanyName)
+            ->setCountryId($origCountryId)
+            ->setOrigState($origState)
+            ->setOrigCity($origCity)
+            ->setOrigPostal($origPostcode);
         $this->setRequest($requestDhl);
 
         $this->_result = $this->_getQuotes();
-
         $this->_updateFreeMethodQuote($request);
 
         return $this->_result;
@@ -350,12 +353,10 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      */
     protected function _setFreeMethodRequest($freeMethod)
     {
-        $rawRequest = $this->_rawRequest;
-
-        $rawRequest->setFreeMethodRequest(true);
-        $freeWeight = $this->getTotalNumOfBoxes($rawRequest->getFreeMethodWeight());
-        $rawRequest->setWeight($freeWeight);
-        $rawRequest->setService($freeMethod);
+        $this->_rawRequest->setFreeMethodRequest(true);
+        $freeWeight = $this->getTotalNumOfBoxes($this->_rawRequest->getFreeMethodWeight());
+        $this->_rawRequest->setWeight($freeWeight);
+        $this->_rawRequest->setService($freeMethod);
     }
 
     /**
@@ -376,10 +377,9 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      */
     protected function _addParams(\Magento\Framework\Object $requestObject)
     {
-        $request = $this->_request;
         foreach ($this->_requestVariables as $code => $objectCode) {
-            if ($request->getDhlId()) {
-                $value = $request->getData($objectCode['code']);
+            if ($this->_request->getDhlId()) {
+                $value = $this->_request->getData($objectCode['code']);
             } else {
                 $value = $this->getConfigData($code);
             }
@@ -423,45 +423,29 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
 
         $shippingWeight = $request->getPackageWeight();
 
-        $requestObject->setValue(
-            round($request->getPackageValue(), 2)
-        )->setValueWithDiscount(
-            $request->getPackageValueWithDiscount()
-        )->setCustomsValue(
-            $request->getPackageCustomsValue()
-        )->setDestStreet(
-            $this->string->substr(str_replace("\n", '', $request->getDestStreet()), 0, 35)
-        )->setDestStreetLine2(
-            $request->getDestStreetLine2()
-        )->setDestCity(
-            $request->getDestCity()
-        )->setOrigCompanyName(
-            $request->getOrigCompanyName()
-        )->setOrigCity(
-            $request->getOrigCity()
-        )->setOrigPhoneNumber(
-            $request->getOrigPhoneNumber()
-        )->setOrigPersonName(
-            $request->getOrigPersonName()
-        )->setOrigEmail(
-            $this->_scopeConfig->getValue(
-                'trans_email/ident_general/email',
-                \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
-                $requestObject->getStoreId()
+        $requestObject->setValue(round($request->getPackageValue(), 2))
+            ->setValueWithDiscount($request->getPackageValueWithDiscount())
+            ->setCustomsValue($request->getPackageCustomsValue())
+            ->setDestStreet($this->string->substr(str_replace("\n", '', $request->getDestStreet()), 0, 35))
+            ->setDestStreetLine2($request->getDestStreetLine2())
+            ->setDestCity($request->getDestCity())
+            ->setOrigCompanyName($request->getOrigCompanyName())
+            ->setOrigCity($request->getOrigCity())
+            ->setOrigPhoneNumber($request->getOrigPhoneNumber())
+            ->setOrigPersonName($request->getOrigPersonName())
+            ->setOrigEmail(
+                $this->_scopeConfig->getValue(
+                    'trans_email/ident_general/email',
+                    \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+                    $requestObject->getStoreId()
+                )
             )
-        )->setOrigCity(
-            $request->getOrigCity()
-        )->setOrigPostal(
-            $request->getOrigPostal()
-        )->setOrigStreetLine2(
-            $request->getOrigStreetLine2()
-        )->setDestPhoneNumber(
-            $request->getDestPhoneNumber()
-        )->setDestPersonName(
-            $request->getDestPersonName()
-        )->setDestCompanyName(
-            $request->getDestCompanyName()
-        );
+            ->setOrigCity($request->getOrigCity())
+            ->setOrigPostal($request->getOrigPostal())
+            ->setOrigStreetLine2($request->getOrigStreetLine2())
+            ->setDestPhoneNumber($request->getDestPhoneNumber())
+            ->setDestPersonName($request->getDestPersonName())
+            ->setDestCompanyName($request->getDestCompanyName());
 
         $originStreet2 = $this->_scopeConfig->getValue(
             Shipment::XML_PATH_STORE_ADDRESS2,
@@ -485,23 +469,17 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
 
         // for DHL, Puerto Rico state for US will assume as Puerto Rico country
         // for Puerto Rico, dhl will ship as international
-        if ($destCountry == self::USA_COUNTRY_ID && ($request->getDestPostcode() == '00912' ||
-            $request->getDestRegionCode() == self::PUERTORICO_COUNTRY_ID)
+        if ($destCountry == self::USA_COUNTRY_ID
+            && ($request->getDestPostcode() == '00912' || $request->getDestRegionCode() == self::PUERTORICO_COUNTRY_ID)
         ) {
             $destCountry = self::PUERTORICO_COUNTRY_ID;
         }
 
-        $requestObject->setDestCountryId(
-            $destCountry
-        )->setDestState(
-            $request->getDestRegionCode()
-        )->setWeight(
-            $shippingWeight
-        )->setFreeMethodWeight(
-            $request->getFreeMethodWeight()
-        )->setOrderShipment(
-            $request->getOrderShipment()
-        );
+        $requestObject->setDestCountryId($destCountry)
+            ->setDestState($request->getDestRegionCode())
+            ->setWeight($shippingWeight)
+            ->setFreeMethodWeight($request->getFreeMethodWeight())
+            ->setOrderShipment($request->getOrderShipment());
 
         if ($request->getPackageId()) {
             $requestObject->setPackageId($request->getPackageId());
@@ -522,7 +500,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
     public function getAllowedMethods()
     {
         $contentType = $this->getConfigData('content_type');
-        $allowedMethods = array();
+
         if ($this->_isDomestic) {
             $allowedMethods = array_merge(
                 explode(',', $this->getConfigData('doc_methods')),
@@ -709,9 +687,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $fullItems = array();
 
         foreach ($allItems as $item) {
-            if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE &&
-                $item->getProduct()->getShipmentType()
-            ) {
+            if ($item->getProductType() == Type::TYPE_BUNDLE && $item->getProduct()->getShipmentType()) {
                 continue;
             }
 
@@ -724,17 +700,23 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
                 if (!$item->getParentItem()->getProduct()->getShipmentType()) {
                     continue;
                 }
-                $qty = $item->getIsQtyDecimal() ? $item->getParentItem()->getQty() : $item->getParentItem()->getQty() *
-                    $item->getQty();
+                if ($item->getIsQtyDecimal()) {
+                    $qty = $item->getParentItem()->getQty();
+                } else {
+                    $qty = $item->getParentItem()->getQty() * $item->getQty();
+                }
             }
 
             $itemWeight = $item->getWeight();
-            if ($item->getIsQtyDecimal() && $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
-            ) {
-                $stockItem = $item->getProduct()->getStockItem();
-                if ($stockItem->getIsDecimalDivided()) {
-                    if ($stockItem->getEnableQtyIncrements() && $stockItem->getQtyIncrements()) {
-                        $itemWeight = $itemWeight * $stockItem->getQtyIncrements();
+            if ($item->getIsQtyDecimal() && $item->getProductType() != Type::TYPE_BUNDLE) {
+                $productId = $item->getProduct()->getId();
+                $isDecimalDivided = $this->stockItemService->getStockItem($productId)
+                    ->getIsDecimalDivided();
+                if ($isDecimalDivided) {
+                    if ($this->stockItemService->getEnableQtyIncrements($productId)
+                        && $this->stockItemService->getQtyIncrements($productId)
+                    ) {
+                        $itemWeight = $itemWeight * $this->stockItemService->getQtyIncrements($productId);
                         $qty = round($item->getWeight() / $itemWeight * $qty);
                         $changeQty = false;
                     } else {
@@ -759,10 +741,10 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
                 return array();
             }
 
-            if ($changeQty &&
-                !$item->getParentItem() &&
-                $item->getIsQtyDecimal() &&
-                $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
+            if ($changeQty
+                && !$item->getParentItem()
+                && $item->getIsQtyDecimal()
+                && $item->getProductType() != Type::TYPE_BUNDLE
             ) {
                 $qty = 1;
             }
@@ -1022,9 +1004,9 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             // IsDutiable flag and Dutiable node indicates that cargo is not a documentation
             $nodeBkgDetails->addChild('IsDutiable', 'Y');
             $nodeDutiable = $nodeGetQuote->addChild('Dutiable');
-            $baseCurrencyCode = $this->_storeManager->getWebsite(
-                $this->_request->getWebsiteId()
-            )->getBaseCurrencyCode();
+            $baseCurrencyCode = $this->_storeManager
+                ->getWebsite($this->_request->getWebsiteId())
+                ->getBaseCurrencyCode();
             $nodeDutiable->addChild('DeclaredCurrency', $baseCurrencyCode);
             $nodeDutiable->addChild('DeclaredValue', sprintf("%.2F", $rawRequest->getValue()));
         }
@@ -1059,12 +1041,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             if (strpos(trim($response), '<?xml') === 0) {
                 $xml = simplexml_load_string($response);
                 if (is_object($xml)) {
-                    if (in_array(
-                        $xml->getName(),
-                        array('ErrorResponse', 'ShipmentValidateErrorResponse')
-                    ) || isset(
-                        $xml->GetQuoteResponse->Note->Condition
-                    )
+                    if (in_array($xml->getName(), array('ErrorResponse', 'ShipmentValidateErrorResponse'))
+                        || isset($xml->GetQuoteResponse->Note->Condition)
                     ) {
                         $code = null;
                         $data = null;
@@ -1082,7 +1060,9 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
                                     break;
                                 }
                             }
-                            throw new \Magento\Framework\Model\Exception(__('Error #%1 : %2', trim($code), trim($data)));
+                            throw new \Magento\Framework\Model\Exception(
+                                __('Error #%1 : %2', trim($code), trim($data))
+                            );
                         }
 
                         $code = isset($nodeCondition->ConditionCode) ? (string)$nodeCondition->ConditionCode : 0;
@@ -1142,26 +1122,18 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
      */
     protected function _addRate(\SimpleXMLElement $shipmentDetails)
     {
-        if (isset(
-            $shipmentDetails->ProductShortName
-        ) && isset(
-            $shipmentDetails->ShippingCharge
-        ) && isset(
-            $shipmentDetails->GlobalProductCode
-        ) && isset(
-            $shipmentDetails->CurrencyCode
-        ) && array_key_exists(
-            (string)$shipmentDetails->GlobalProductCode,
-            $this->getAllowedMethods()
-        )
+        if (isset($shipmentDetails->ProductShortName)
+            && isset($shipmentDetails->ShippingCharge)
+            && isset($shipmentDetails->GlobalProductCode)
+            && isset($shipmentDetails->CurrencyCode)
+            && array_key_exists((string)$shipmentDetails->GlobalProductCode, $this->getAllowedMethods())
         ) {
             // DHL product code, e.g. '3', 'A', 'Q', etc.
             $dhlProduct = (string)$shipmentDetails->GlobalProductCode;
-            $totalEstimate = (double)(string)$shipmentDetails->ShippingCharge;
+            $totalEstimate = (float)(string)$shipmentDetails->ShippingCharge;
             $currencyCode = (string)$shipmentDetails->CurrencyCode;
-            $baseCurrencyCode = $this->_storeManager->getWebsite(
-                $this->_request->getWebsiteId()
-            )->getBaseCurrencyCode();
+            $baseCurrencyCode = $this->_storeManager->getWebsite($this->_request->getWebsiteId())
+                ->getBaseCurrencyCode();
             $dhlProductDescription = $this->getDhlProductTitle($dhlProduct);
 
             if ($currencyCode != $baseCurrencyCode) {
@@ -1193,8 +1165,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
                 );
                 if (!empty($this->_rates)) {
                     foreach ($this->_rates as $product) {
-                        if ($product['data']['term'] == $data['term'] &&
-                            $product['data']['price_total'] == $data['price_total']
+                        if ($product['data']['term'] == $data['term']
+                            && $product['data']['price_total'] == $data['price_total']
                         ) {
                             return $this;
                         }
@@ -1387,19 +1359,12 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             $packageWeight += $piece['params']['weight'];
         }
 
-        $request->setPackages(
-            $packages
-        )->setPackageWeight(
-            $packageWeight
-        )->setPackageValue(
-            $customsValue
-        )->setValueWithDiscount(
-            $customsValue
-        )->setPackageCustomsValue(
-            $customsValue
-        )->setFreeMethodWeight(
-            0
-        );
+        $request->setPackages($packages)
+            ->setPackageWeight($packageWeight)
+            ->setPackageValue($customsValue)
+            ->setValueWithDiscount($customsValue)
+            ->setPackageCustomsValue($customsValue)
+            ->setFreeMethodWeight(0);
     }
 
     /**
@@ -1462,10 +1427,10 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $xml->addChild('LanguageCode', 'EN', '');
         $xml->addChild('PiecesEnabled', 'Y', '');
 
-        /* Billing */
+        /** Billing */
         $nodeBilling = $xml->addChild('Billing', '', '');
         $nodeBilling->addChild('ShipperAccountNumber', (string)$this->getConfigData('account'));
-        /*
+        /**
          * Method of Payment:
          * S (Shipper)
          * R (Receiver)
@@ -1473,14 +1438,14 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
          */
         $nodeBilling->addChild('ShippingPaymentType', 'S');
 
-        /*
+        /**
          * Shipment bill to account – required if Shipping PaymentType is other than 'S'
          */
         $nodeBilling->addChild('BillingAccountNumber', (string)$this->getConfigData('account'));
         $nodeBilling->addChild('DutyPaymentType', 'S');
         $nodeBilling->addChild('DutyAccountNumber', (string)$this->getConfigData('account'));
 
-        /* Receiver */
+        /** Receiver */
         $nodeConsignee = $xml->addChild('Consignee', '', '');
 
         $companyName = $rawRequest->getRecipientContactCompanyName() ? $rawRequest
@@ -1511,7 +1476,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $nodeContact->addChild('PersonName', substr($rawRequest->getRecipientContactPersonName(), 0, 34));
         $nodeContact->addChild('PhoneNumber', substr($rawRequest->getRecipientContactPhoneNumber(), 0, 24));
 
-        /* Commodity
+        /**
+         * Commodity
          * The CommodityCode element contains commodity code for shipment contents. Its
          * value should lie in between 1 to 9999.This field is mandatory.
          */
@@ -1523,7 +1489,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             $rawRequest->getRecipientAddressCountryCode()
         );
 
-        /* Dutiable */
+        /** Dutiable */
         if ($this->getConfigData('content_type') == self::DHL_CONTENT_TYPE_NON_DOC && !$this->_isDomestic) {
             $nodeDutiable = $xml->addChild('Dutiable', '', '');
             $nodeDutiable->addChild(
@@ -1534,7 +1500,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             $nodeDutiable->addChild('DeclaredCurrency', $baseCurrencyCode);
         }
 
-        /* Reference
+        /**
+         * Reference
          * This element identifies the reference information. It is an optional field in the
          * shipment validation request. Only the first reference will be taken currently.
          */
@@ -1542,10 +1509,10 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         $nodeReference->addChild('ReferenceID', 'shipment reference');
         $nodeReference->addChild('ReferenceType', 'St');
 
-        /* Shipment Details */
+        /** Shipment Details */
         $this->_shipmentDetails($xml, $rawRequest, $originRegion);
 
-        /* Shipper */
+        /** Shipper */
         $nodeShipper = $xml->addChild('Shipper', '', '');
         $nodeShipper->addChild('ShipperID', (string)$this->getConfigData('account'));
         $nodeShipper->addChild('CompanyName', $rawRequest->getShipperContactCompanyName());
@@ -1659,15 +1626,12 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
 
         if (!$originRegion) {
             $nodeShipmentDetails->addChild('Weight', round($rawRequest->getPackageWeight(), 1));
-
             $nodeShipmentDetails->addChild('WeightUnit', substr($this->_getWeightUnit(), 0, 1));
-
             $nodeShipmentDetails->addChild('GlobalProductCode', $rawRequest->getShippingMethod());
             $nodeShipmentDetails->addChild('LocalProductCode', $rawRequest->getShippingMethod());
-
             $nodeShipmentDetails->addChild('Date', $this->_coreDate->date('Y-m-d'));
             $nodeShipmentDetails->addChild('Contents', 'DHL Parcel');
-            /*
+            /**
              * The DoorTo Element defines the type of delivery service that applies to the shipment.
              * The valid values are DD (Door to Door), DA (Door to Airport) , AA and DC (Door to
              * Door non-compliant)
@@ -1691,14 +1655,12 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             }
             $nodeShipmentDetails->addChild('PackageType', $packageType);
             $nodeShipmentDetails->addChild('Weight', $rawRequest->getPackageWeight());
-
             $nodeShipmentDetails->addChild('DimensionUnit', substr($this->_getDimensionUnit(), 0, 1));
             $nodeShipmentDetails->addChild('WeightUnit', substr($this->_getWeightUnit(), 0, 1));
-
             $nodeShipmentDetails->addChild('GlobalProductCode', $rawRequest->getShippingMethod());
             $nodeShipmentDetails->addChild('LocalProductCode', $rawRequest->getShippingMethod());
 
-            /*
+            /**
              * The DoorTo Element defines the type of delivery service that applies to the shipment.
              * The valid values are DD (Door to Door), DA (Door to Airport) , AA and DC (Door to
              * Door non-compliant)
@@ -1750,14 +1712,14 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
         foreach ($trackings as $tracking) {
             $xml->addChild('AWBNumber', $tracking, '');
         }
-        /*
+        /**
          * Checkpoint details selection flag
          * LAST_CHECK_POINT_ONLY
          * ALL_CHECK_POINTS
          */
         $xml->addChild('LevelOfDetails', 'ALL_CHECK_POINTS', '');
 
-        /*
+        /**
          * Value that indicates for getting the tracking details with the additional
          * piece details and its respective Piece Details, Piece checkpoints along with
          * Shipment Details if queried.
@@ -1810,18 +1772,14 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
             if (!is_object($xml)) {
                 $errorTitle = __('Response is in the wrong format');
             }
-            if (is_object(
-                $xml
-            ) && (isset(
-                $xml->Response->Status->ActionStatus
-            ) && $xml->Response->Status->ActionStatus == 'Failure' || isset(
-                $xml->GetQuoteResponse->Note->Condition
-            ))
+            if (is_object($xml)
+                && (isset($xml->Response->Status->ActionStatus)
+                    && $xml->Response->Status->ActionStatus == 'Failure'
+                    || isset($xml->GetQuoteResponse->Note->Condition))
             ) {
                 if (isset($xml->Response->Status->Condition)) {
                     $nodeCondition = $xml->Response->Status->Condition;
                 }
-
                 $code = isset($nodeCondition->ConditionCode) ? (string)$nodeCondition->ConditionCode : 0;
                 $data = isset($nodeCondition->ConditionData) ? (string)$nodeCondition->ConditionData : '';
                 $this->_errors[$code] = __('Error #%1 : %2', $code, $data);
@@ -1845,16 +1803,12 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
                     if (isset($shipmentInfo->ShipmentEvent)) {
                         foreach ($shipmentInfo->ShipmentEvent as $shipmentEvent) {
                             $shipmentEventArray = array();
-                            $shipmentEventArray['activity'] = (string)$shipmentEvent->ServiceEvent->EventCode .
-                                ' ' .
-                                (string)$shipmentEvent->ServiceEvent->Description;
+                            $shipmentEventArray['activity'] = (string)$shipmentEvent->ServiceEvent->EventCode
+                                . ' ' . (string)$shipmentEvent->ServiceEvent->Description;
                             $shipmentEventArray['deliverydate'] = (string)$shipmentEvent->Date;
                             $shipmentEventArray['deliverytime'] = (string)$shipmentEvent->Time;
                             $shipmentEventArray['deliverylocation'] = (string)$shipmentEvent->ServiceArea
-                                ->Description .
-                                ' [' .
-                                (string)$shipmentEvent->ServiceArea->ServiceAreaCode .
-                                ']';
+                                ->Description . ' [' . (string)$shipmentEvent->ServiceArea->ServiceAreaCode . ']';
                             $packageProgress[] = $shipmentEventArray;
                         }
                         $awbinfoData['progressdetail'] = $packageProgress;
diff --git a/app/code/Magento/Dhl/etc/module.xml b/app/code/Magento/Dhl/etc/module.xml
index f2422aba3b8..a0e44e80765 100644
--- a/app/code/Magento/Dhl/etc/module.xml
+++ b/app/code/Magento/Dhl/etc/module.xml
@@ -34,6 +34,7 @@
             <module name="Magento_Sales"/>
             <module name="Magento_Checkout"/>
             <module name="Magento_Catalog"/>
+            <module name="Magento_CatalogInventory"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/Directory/Controller/Adminhtml/Json.php b/app/code/Magento/Directory/Controller/Adminhtml/Json.php
index cd9547813aa..af8e1ea2205 100644
--- a/app/code/Magento/Directory/Controller/Adminhtml/Json.php
+++ b/app/code/Magento/Directory/Controller/Adminhtml/Json.php
@@ -54,6 +54,8 @@ class Json extends \Magento\Backend\App\Action
                 }
             }
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($arrRes));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($arrRes)
+        );
     }
 }
diff --git a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File.php b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File.php
index 340555eeceb..cc2f3521647 100644
--- a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File.php
+++ b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File.php
@@ -113,7 +113,9 @@ class File extends \Magento\Backend\App\Action
             $result = array('error' => $e->getMessage(), 'errorcode' => $e->getCode());
         }
 
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Downloadable/Model/Product/Type.php b/app/code/Magento/Downloadable/Model/Product/Type.php
index d11ca2dd414..e9c082f7858 100644
--- a/app/code/Magento/Downloadable/Model/Product/Type.php
+++ b/app/code/Magento/Downloadable/Model/Product/Type.php
@@ -292,6 +292,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
                             $sampleModel->setSampleFile($sampleFileName);
                         }
                         $sampleModel->save();
+                        $product->setLastAddedSampleId($sampleModel->getId());
                     }
                 }
                 if ($_deleteItems) {
@@ -366,6 +367,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
                             $linkModel->setSampleFile($linkSampleFileName);
                         }
                         $linkModel->save();
+                        $product->setLastAddedLinkId($linkModel->getId());
                     }
                 }
                 if ($_deleteItems) {
diff --git a/app/code/Magento/Downloadable/Service/V1/Data/FileContent.php b/app/code/Magento/Downloadable/Service/V1/Data/FileContent.php
new file mode 100644
index 00000000000..8b6c6a80df2
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContent.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class FileContent extends AbstractObject
+{
+    const DATA = 'data';
+    const NAME = 'name';
+
+    /**
+     * Retrieve data (base64 encoded content)
+     *
+     * @return string
+     */
+    public function getData()
+    {
+        return $this->_get(self::DATA);
+    }
+
+    /**
+     * Retrieve file name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->_get(self::NAME);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/Data/FileContentBuilder.php b/app/code/Magento/Downloadable/Service/V1/Data/FileContentBuilder.php
new file mode 100644
index 00000000000..b0c443c3da9
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentBuilder.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+use \Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class FileContentBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set data (base64 encoded content)
+     *
+     * @param string $data
+     * @return $this
+     */
+    public function setData($data)
+    {
+        return $this->_set(FileContent::DATA, $data);
+    }
+
+    /**
+     * Set file name
+     *
+     * @param string $name
+     * @return $this
+     */
+    public function setName($name)
+    {
+        return $this->_set(FileContent::NAME, $name);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploader.php b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploader.php
new file mode 100644
index 00000000000..57ff82e322d
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploader.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+use \Magento\Core\Model\File\Uploader;
+use \Magento\Framework\Io\File;
+use \Magento\Framework\App\Filesystem;
+use \Magento\Core\Model\File\Validator\NotProtectedExtension;
+use \Magento\Core\Helper\File\Storage;
+use \Magento\Core\Helper\File\Storage\Database;
+use \Magento\Downloadable\Model\Link as LinkConfig;
+use \Magento\Downloadable\Model\Sample as SampleConfig;
+
+class FileContentUploader extends Uploader implements FileContentUploaderInterface
+{
+    /**
+     * Default MIME type
+     */
+    const DEFAULT_MIME_TYPE = 'application/octet-stream';
+
+    /**
+     * Filename prefix for temporary files
+     *
+     * @var string
+     */
+    protected $filePrefix = 'magento_api';
+
+    /**
+     * @var \Magento\Framework\Filesystem\Directory\WriteInterface
+     */
+    protected $mediaDirectory;
+
+    /**
+     * @var \Magento\Framework\Filesystem\Directory\WriteInterface
+     */
+    protected $systemTmpDirectory;
+
+    /**
+     * @var LinkConfig
+     */
+    protected $linkConfig;
+
+    /**
+     * @var SampleConfig
+     */
+    protected $sampleConfig;
+
+    /**
+     * @param Database $coreFileStorageDb
+     * @param Storage $coreFileStorage
+     * @param NotProtectedExtension $validator
+     * @param Filesystem $filesystem
+     * @param LinkConfig $linkConfig
+     * @param SampleConfig $sampleConfig
+     */
+    public function __construct(
+        Database $coreFileStorageDb,
+        Storage $coreFileStorage,
+        NotProtectedExtension $validator,
+        Filesystem $filesystem,
+        LinkConfig $linkConfig,
+        SampleConfig $sampleConfig
+    ) {
+        $this->_validator = $validator;
+        $this->_coreFileStorage = $coreFileStorage;
+        $this->_coreFileStorageDb = $coreFileStorageDb;
+        $this->mediaDirectory = $filesystem->getDirectoryWrite(Filesystem::MEDIA_DIR);
+        $this->systemTmpDirectory = $filesystem->getDirectoryWrite(Filesystem::SYS_TMP_DIR);
+        $this->linkConfig = $linkConfig;
+        $this->sampleConfig = $sampleConfig;
+    }
+
+    /**
+     * Decode base64 encoded content and save it in system tmp folder
+     *
+     * @param FileContent $fileContent
+     * @return array
+     */
+    protected function decodeContent(FileContent $fileContent)
+    {
+        $tmpFileName = $this->getTmpFileName();
+        $fileSize = $this->systemTmpDirectory->writeFile($tmpFileName, base64_decode($fileContent->getData()));
+
+        return array(
+            'name' => $fileContent->getName(),
+            'type' => self::DEFAULT_MIME_TYPE,
+            'tmp_name' => $this->systemTmpDirectory->getAbsolutePath($tmpFileName),
+            'error' => 0,
+            'size' => $fileSize,
+        );
+    }
+
+    /**
+     * Generate temporary file name
+     *
+     * @return string
+     */
+    protected function getTmpFileName()
+    {
+        return uniqid($this->filePrefix, true);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upload(FileContent $fileContent, $contentType)
+    {
+        $this->_file = $this->decodeContent($fileContent);
+        if (!file_exists($this->_file['tmp_name'])) {
+            throw new \InvalidArgumentException('There was an error during file content upload.');
+        }
+        $this->_fileExists = true;
+        $this->_uploadType = self::SINGLE_STYLE;
+        $this->setAllowRenameFiles(true);
+        $this->setFilesDispersion(true);
+        $result = $this->save($this->getDestinationDirectory($contentType));
+        $result['status'] = 'new';
+        $result['name'] = substr($result['file'], strrpos($result['file'], '/') + 1);
+        return $result;
+    }
+
+    /**
+     * Retrieve destination directory for given content type
+     *
+     * @param string $contentType
+     * @return string
+     * @throws \InvalidArgumentException
+     */
+    protected function getDestinationDirectory($contentType)
+    {
+        switch ($contentType) {
+            case 'link_file':
+                $directory = $this->mediaDirectory->getAbsolutePath($this->linkConfig->getBaseTmpPath());
+                break;
+            case 'link_sample_file':
+                $directory = $this->mediaDirectory->getAbsolutePath($this->linkConfig->getBaseSampleTmpPath());
+                break;
+            case 'sample':
+                $directory = $this->mediaDirectory->getAbsolutePath($this->sampleConfig->getBaseTmpPath());
+                break;
+            default:
+                throw new \InvalidArgumentException('Invalid downloadable file content type.');
+        }
+        return $directory;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploaderInterface.php b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploaderInterface.php
new file mode 100644
index 00000000000..e50ec68dfc3
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploaderInterface.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+interface FileContentUploaderInterface
+{
+    /**
+     * Upload provided downloadable file content
+     *
+     * @param FileContent $fileContent
+     * @param string $contentType
+     * @return array
+     * @throws \InvalidArgumentException
+     */
+    public function upload(FileContent $fileContent, $contentType);
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/Data/FileContentValidator.php b/app/code/Magento/Downloadable/Service/V1/Data/FileContentValidator.php
new file mode 100644
index 00000000000..5c0615c498a
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentValidator.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+use \Magento\Framework\Exception\InputException;
+
+class FileContentValidator
+{
+    /**
+     * Check if gallery entry content is valid
+     *
+     * @param FileContent $fileContent
+     * @return bool
+     * @throws InputException
+     */
+    public function isValid(FileContent $fileContent)
+    {
+        $decodedContent = @base64_decode($fileContent->getData(), true);
+        if (empty($decodedContent)) {
+            throw new InputException('Provided content must be valid base64 encoded data.');
+        }
+
+        if (!$this->isFileNameValid($fileContent->getName())) {
+            throw new InputException('Provided file name contains forbidden characters.');
+        }
+        return true;
+    }
+
+    /**
+     * Check if given filename is valid
+     *
+     * @param string $fileName
+     * @return bool
+     */
+    protected function isFileNameValid($fileName)
+    {
+        // Cannot contain \ / : * ? " < > |
+        if (!preg_match('/^[^\\/?*:";<>()|{}\\\\]+$/', $fileName)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContent.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContent.php
new file mode 100644
index 00000000000..72de1163db1
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContent.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class DownloadableLinkContent extends AbstractObject
+{
+    const TITLE = 'title';
+    const PRICE = 'price';
+    const NUMBER_OF_DOWNLOADS = 'number_of_downloads';
+    const UNLIMITED = 'unlimited';
+    const SHAREABLE = 'shareable';
+    const SORT_ORDER = 'sort_order';
+    const LINK_FILE = 'link_file';
+    const LINK_URL = 'link_url';
+    const LINK_TYPE = 'link_type';
+    const SAMPLE_FILE = 'file';
+    const SAMPLE_URL = 'url';
+    const SAMPLE_TYPE = 'sample_type';
+
+    /**
+     * Retrieve link title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->_get(self::TITLE);
+    }
+
+    /**
+     * Retrieve link sort order
+     *
+     * @return int
+     */
+    public function getSortOrder()
+    {
+        return $this->_get(self::SORT_ORDER);
+    }
+
+    /**
+     * Retrieve link price
+     *
+     * @return string
+     */
+    public function getPrice()
+    {
+        return $this->_get(self::PRICE);
+    }
+
+    /**
+     * Retrieve number of allowed downloads of the link
+     *
+     * @return int
+     */
+    public function getNumberOfDownloads()
+    {
+        return $this->_get(self::NUMBER_OF_DOWNLOADS);
+    }
+
+    /**
+     * Check if link is shareable
+     *
+     * @return bool
+     */
+    public function isShareable()
+    {
+        return $this->_get(self::SHAREABLE);
+    }
+
+    /**
+     * Retrieve link file content
+     *
+     * @return \Magento\Downloadable\Service\V1\Data\FileContent|null
+     */
+    public function getLinkFile()
+    {
+        return $this->_get(self::LINK_FILE);
+    }
+
+    /**
+     * Retrieve link URL
+     *
+     * @return string|null
+     */
+    public function getLinkUrl()
+    {
+        return $this->_get(self::LINK_URL);
+    }
+
+    /**
+     * Retrieve link type ('url' or 'file')
+     *
+     * @return string|null
+     */
+    public function getLinkType()
+    {
+        return $this->_get(self::LINK_TYPE);
+    }
+
+    /**
+     * Retrieve sample file content
+     *
+     * @return \Magento\Downloadable\Service\V1\Data\FileContent|null
+     */
+    public function getSampleFile()
+    {
+        return $this->_get(self::SAMPLE_FILE);
+    }
+
+    /**
+     * Retrieve sample URL
+     *
+     * @return string|null
+     */
+    public function getSampleUrl()
+    {
+        return $this->_get(self::SAMPLE_URL);
+    }
+
+    /**
+     * Retrieve sample type ('url' or 'file')
+     *
+     * @return string|null
+     */
+    public function getSampleType()
+    {
+        return $this->_get(self::SAMPLE_TYPE);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentBuilder.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentBuilder.php
new file mode 100644
index 00000000000..f344be1800e
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentBuilder.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * Downloadable Link Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use \Magento\Framework\Service\Data\AbstractObjectBuilder;
+use \Magento\Downloadable\Service\V1\Data\FileContent;
+
+class DownloadableLinkContentBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set link title
+     *
+     * @param string $title
+     * @return $this
+     */
+    public function setTitle($title)
+    {
+        return $this->_set(DownloadableLinkContent::TITLE, $title);
+    }
+
+    /**
+     * Set link sort order
+     *
+     * @param int $sortOrder
+     * @return $this
+     */
+    public function setSortOrder($sortOrder)
+    {
+        return $this->_set(DownloadableLinkContent::SORT_ORDER, $sortOrder);
+    }
+
+    /**
+     * Set link price
+     *
+     * @param string $price
+     * @return $this
+     */
+    public function setPrice($price)
+    {
+        return $this->_set(DownloadableLinkContent::PRICE, $price);
+    }
+
+    /**
+     * Set number of allowed downloads of the link
+     *
+     * @param int $numberOfDownloads
+     * @return $this
+     */
+    public function setNumberOfDownloads($numberOfDownloads)
+    {
+        return $this->_set(DownloadableLinkContent::NUMBER_OF_DOWNLOADS, $numberOfDownloads);
+    }
+
+    /**
+     * Check if link is shareable
+     *
+     * @param bool $shareable
+     * @return $this
+     */
+    public function setShareable($shareable)
+    {
+        return $this->_set(DownloadableLinkContent::SHAREABLE, $shareable);
+    }
+
+    /**
+     * Set link file content
+     *
+     * @param FileContent $linkFile
+     * @return $this
+     */
+    public function setLinkFile(FileContent $linkFile)
+    {
+        return $this->_set(DownloadableLinkContent::LINK_FILE, $linkFile);
+    }
+
+    /**
+     * Set link URL
+     *
+     * @param string $linkUrl
+     * @return $this
+     */
+    public function setLinkUrl($linkUrl)
+    {
+        return $this->_set(DownloadableLinkContent::LINK_URL, $linkUrl);
+    }
+
+    /**
+     * Set link type ('url' or 'file')
+     *
+     * @param string $linkType
+     * @return $this
+     */
+    public function setLinkType($linkType)
+    {
+        return $this->_set(DownloadableLinkContent::LINK_TYPE, $linkType);
+    }
+
+    /**
+     * Set sample file content
+     *
+     * @param FileContent $sampleFile
+     * @return $this
+     */
+    public function setSampleFile($sampleFile)
+    {
+        return $this->_set(DownloadableLinkContent::SAMPLE_FILE, $sampleFile);
+    }
+
+    /**
+     * Set sample URL
+     *
+     * @param string $sampleUrl
+     * @return $this
+     */
+    public function setSampleUrl($sampleUrl)
+    {
+        return $this->_set(DownloadableLinkContent::SAMPLE_URL, $sampleUrl);
+    }
+
+    /**
+     * Set sample type ('url' or 'file')
+     *
+     * @param string $sampleType
+     * @return $this
+     */
+    public function setSampleType($sampleType)
+    {
+        return $this->_set(DownloadableLinkContent::SAMPLE_TYPE, $sampleType);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidator.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidator.php
new file mode 100644
index 00000000000..13413efd2d4
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidator.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use \Magento\Downloadable\Service\V1\Data\FileContentValidator;
+use \Magento\Framework\Url\Validator as UrlValidator;
+use \Magento\Framework\Exception\InputException;
+
+class DownloadableLinkContentValidator
+{
+    /**
+     * @var FileContentValidator
+     */
+    protected $fileContentValidator;
+
+    /**
+     * @var UrlValidator
+     */
+    protected $urlValidator;
+
+    /**
+     * @param FileContentValidator $fileContentValidator
+     * @param UrlValidator $urlValidator
+     */
+    public function __construct(
+        FileContentValidator $fileContentValidator,
+        UrlValidator $urlValidator
+    ) {
+        $this->fileContentValidator = $fileContentValidator;
+        $this->urlValidator = $urlValidator;
+    }
+
+    /**
+     * Check if link content is valid
+     *
+     * @param DownloadableLinkContent $linkContent
+     * @return bool
+     * @throws InputException
+     */
+    public function isValid(DownloadableLinkContent $linkContent)
+    {
+        if (!is_numeric($linkContent->getPrice()) || $linkContent->getPrice() < 0) {
+            throw new InputException('Link price must have numeric positive value.');
+        }
+        if (!is_int($linkContent->getNumberOfDownloads()) || $linkContent->getNumberOfDownloads() < 0) {
+            throw new InputException('Number of downloads must be a positive integer.');
+        }
+        if (!is_int($linkContent->getSortOrder()) || $linkContent->getSortOrder() < 0) {
+            throw new InputException('Sort order must be a positive integer.');
+        }
+
+        $this->validateLinkResource($linkContent);
+        $this->validateSampleResource($linkContent);
+        return true;
+    }
+
+    /**
+     * Validate link resource (file or URL)
+     *
+     * @param DownloadableLinkContent $linkContent
+     * @throws InputException
+     * @return void
+     */
+    protected function validateLinkResource(DownloadableLinkContent $linkContent)
+    {
+        if ($linkContent->getLinkType() == 'url'
+            && !$this->urlValidator->isValid($linkContent->getLinkUrl())
+        ) {
+            throw new InputException('Link URL must have valid format.');
+        }
+        if ($linkContent->getLinkType() == 'file'
+            && (!$linkContent->getLinkFile() || !$this->fileContentValidator->isValid($linkContent->getLinkFile()))
+        ) {
+            throw new InputException('Provided file content must be valid base64 encoded data.');
+        }
+    }
+
+    /**
+     * Validate sample resource (file or URL)
+     *
+     * @param DownloadableLinkContent $linkContent
+     * @throws InputException
+     * @return void
+     */
+    protected function validateSampleResource(DownloadableLinkContent $linkContent)
+    {
+        if ($linkContent->getSampleType() == 'url'
+            && !$this->urlValidator->isValid($linkContent->getSampleUrl())
+        ) {
+            throw new InputException('Sample URL must have valid format.');
+        }
+        if ($linkContent->getSampleType() == 'file'
+            && (!$linkContent->getSampleFile() || !$this->fileContentValidator->isValid($linkContent->getSampleFile()))
+        ) {
+            throw new InputException('Provided file content must be valid base64 encoded data.');
+        }
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfo.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfo.php
new file mode 100644
index 00000000000..0e841b08e7f
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfo.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+class DownloadableLinkInfo extends AbstractObject
+{
+    const ID = 'id';
+
+    const TITLE = 'title';
+
+    const SORT_ORDER = 'sort_order';
+
+    const SHAREABLE = 'shareable';
+
+    const PRICE = 'price';
+
+    const NUMBER_OF_DOWNLOADS = 'number_of_downloads';
+
+    const SAMPLE_RESOURCE = 'sample_resource';
+
+    const LINK_RESOURCE = 'link_resource';
+
+    /**
+     * Product link id
+     *
+     * @return int|null Sample(or link) id
+     */
+    public function getId()
+    {
+        return $this->_get(self::ID);
+    }
+
+    /**
+     * Link title
+     *
+     * @return string|null
+     */
+    public function getTitle()
+    {
+        return $this->_get(self::TITLE);
+    }
+
+    /**
+     * Sort order index for link
+     *
+     * @return int
+     */
+    public function getSortOrder()
+    {
+        return (int)$this->_get(self::SORT_ORDER);
+    }
+
+    /**
+     * Link shareable status
+     * 0 -- No
+     * 1 -- Yes
+     * 2 -- Use config default value
+     *
+     * @return int
+     */
+    public function getShareable()
+    {
+        return (int)$this->_get(self::SHAREABLE);
+    }
+
+    /**
+     * Link price
+     *
+     * @return float
+     */
+    public function getPrice()
+    {
+        return $this->_get(self::PRICE);
+    }
+
+    /**
+     * Number of downloads per user
+     * Null for unlimited downloads
+     *
+     * @return int|null
+     */
+    public function getNumberOfDownloads()
+    {
+        return $this->_get(self::NUMBER_OF_DOWNLOADS);
+    }
+
+    /**
+     * File or URL of sample if any
+     *
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo|null
+     */
+    public function getSampleResource()
+    {
+        return $this->_get(self::SAMPLE_RESOURCE);
+    }
+
+    /**
+     * File or URL of link
+     *
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo
+     */
+    public function getLinkResource()
+    {
+        return $this->_get(self::LINK_RESOURCE);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfoBuilder.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfoBuilder.php
new file mode 100644
index 00000000000..28853bfc59b
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfoBuilder.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Downloadable Link Info Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class DownloadableLinkInfoBuilder extends AbstractObjectBuilder
+{
+    /**
+     * @param int|null $value
+     * @return $this
+     */
+    public function setId($value)
+    {
+        return $this->_set(DownloadableLinkInfo::ID, $value);
+    }
+
+    /**
+     * @param string $value
+     * @return $this
+     */
+    public function setTitle($value)
+    {
+        return $this->_set(DownloadableLinkInfo::TITLE, $value);
+    }
+
+    /**
+     * @param int $value
+     * @return $this
+     */
+    public function setSortOrder($value)
+    {
+        return $this->_set(DownloadableLinkInfo::SORT_ORDER, $value);
+    }
+
+    /**
+     * @param int $value
+     * @return $this
+     */
+    public function setShareable($value)
+    {
+        return $this->_set(DownloadableLinkInfo::SHAREABLE, $value);
+    }
+
+    /**
+     * Link price
+     *
+     * @param float|null $value
+     * @return $this
+     */
+    public function setPrice($value = 0.0)
+    {
+        return $this->_set(DownloadableLinkInfo::PRICE, $value);
+    }
+
+    /**
+     * Number of downloads per user
+     *
+     * @param int|null $value
+     * @return $this
+     */
+    public function setNumberOfDownloads($value = null)
+    {
+        return $this->_set(DownloadableLinkInfo::NUMBER_OF_DOWNLOADS, $value);
+    }
+
+    /**
+     * Sample data object
+     *
+     * @param \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo|null $value
+     * @return $this
+     */
+    public function setSampleResource($value = null)
+    {
+        return $this->_set(DownloadableLinkInfo::SAMPLE_RESOURCE, $value);
+    }
+
+    /**
+     * Link data object
+     *
+     * @param \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo $value
+     * @return $this
+     */
+    public function setLinkResource($value)
+    {
+        return $this->_set(DownloadableLinkInfo::LINK_RESOURCE, $value);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfo.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfo.php
new file mode 100644
index 00000000000..29959bea145
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfo.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class DownloadableResourceInfo extends AbstractObject
+{
+    const FILE = 'file';
+
+    const URL = 'url';
+
+    const TYPE = 'type';
+
+    /**
+     * Return file path or null when type is 'url'
+     *
+     * @return string|null relative file path
+     */
+    public function getFile()
+    {
+        return $this->_get(self::FILE);
+    }
+
+    /**
+     * Return URL or NULL when type is 'file'
+     *
+     * @return string|null file URL
+     */
+    public function getUrl()
+    {
+        return $this->_get(self::URL);
+    }
+
+    /**
+     * Possible types are 'file' and 'url'
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->_get(self::TYPE);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfoBuilder.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfoBuilder.php
new file mode 100644
index 00000000000..13549c5801f
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfoBuilder.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Downloadable Link Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class DownloadableResourceInfoBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set file path
+     *
+     * @param string|null $value
+     * @return $this
+     */
+    public function setFile($value)
+    {
+        return $this->_set(DownloadableResourceInfo::FILE, $value);
+    }
+
+    /**
+     * Set URL
+     *
+     * @param string|null $value
+     * @return $this
+     */
+    public function setUrl($value)
+    {
+        return $this->_set(DownloadableResourceInfo::URL, $value);
+    }
+
+    /**
+     * Set value type
+     *
+     * @param string $value
+     * @throws \Magento\Framework\Exception\InputException
+     * @return $this
+     */
+    public function setType($value)
+    {
+        $allowedValues = ['url', 'file'];
+        if (!in_array($value, $allowedValues)) {
+            $values = '\'' . implode('\' and \'', $allowedValues) . '\'';
+            throw new \Magento\Framework\Exception\InputException('Allowed type values are '. $values);
+        }
+        return $this->_set(DownloadableResourceInfo::TYPE, $value);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfo.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfo.php
new file mode 100644
index 00000000000..532d15fbf06
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfo.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class DownloadableSampleInfo extends AbstractObject
+{
+    const ID = 'id';
+
+    const TITLE = 'title';
+
+    const SORT_ORDER = 'sort_order';
+
+    const SAMPLE_RESOURCE = 'sample_resource';
+
+    /**
+     * Product sample id
+     *
+     * @return int|null Sample(or link) id
+     */
+    public function getId()
+    {
+        return $this->_get(self::ID);
+    }
+
+    /**
+     * Sample title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->_get(self::TITLE);
+    }
+
+    /**
+     * File or URL of sample
+     *
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo
+     */
+    public function getSampleResource()
+    {
+        return $this->_get(self::SAMPLE_RESOURCE);
+    }
+
+    /**
+     * Sort order index for sample
+     *
+     * @return int
+     */
+    public function getSortOrder()
+    {
+        return (int)$this->_get(self::SORT_ORDER);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfoBuilder.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfoBuilder.php
new file mode 100644
index 00000000000..7540f4b11e7
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfoBuilder.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Downloadable Link Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class DownloadableSampleInfoBuilder extends AbstractObjectBuilder
+{
+    /**
+     * @param string $value
+     * @return $this
+     */
+    public function setTitle($value)
+    {
+        return $this->_set(DownloadableLinkInfo::TITLE, $value);
+    }
+
+    /**
+     * @param int|null $value
+     * @return $this
+     */
+    public function setId($value)
+    {
+        return $this->_set(DownloadableLinkInfo::ID, $value);
+    }
+
+    /**
+     * @param int $value
+     * @return $this
+     */
+    public function setSortOrder($value)
+    {
+        return $this->_set(DownloadableLinkInfo::SORT_ORDER, $value);
+    }
+
+    /**
+     * File or URL of sample if any
+     *
+     * @param \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo $sampleResource
+     * @return $this
+     */
+    public function setSampleResource($sampleResource)
+    {
+        return $this->_set(DownloadableLinkInfo::SAMPLE_RESOURCE, $sampleResource);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadService.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadService.php
new file mode 100644
index 00000000000..b2f7368e857
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadService.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+class ReadService implements ReadServiceInterface
+{
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var \Magento\Downloadable\Model\Product\Type
+     */
+    protected $downloadableType;
+
+    /**
+     * @var \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkInfoBuilder
+     */
+    protected $linkBuilder;
+
+    /**
+     * @var \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableSampleInfoBuilder
+     */
+    protected $sampleBuilder;
+
+    /**
+     * @var \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfoBuilder
+     */
+    protected $resourceBuilder;
+
+    /**
+     * @param \Magento\Catalog\Model\ProductRepository $productRepository
+     * @param \Magento\Downloadable\Model\Product\Type $downloadableType
+     * @param Data\DownloadableLinkInfoBuilder $linkBuilder
+     * @param Data\DownloadableSampleInfoBuilder $sampleBuilder
+     * @param Data\DownloadableResourceInfoBuilder $resourceBuilder
+     */
+    public function __construct(
+        \Magento\Catalog\Model\ProductRepository $productRepository,
+        \Magento\Downloadable\Model\Product\Type $downloadableType,
+        \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkInfoBuilder $linkBuilder,
+        \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableSampleInfoBuilder $sampleBuilder,
+        \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfoBuilder $resourceBuilder
+    ) {
+        $this->productRepository = $productRepository;
+        $this->downloadableType = $downloadableType;
+        $this->linkBuilder = $linkBuilder;
+        $this->sampleBuilder = $sampleBuilder;
+        $this->resourceBuilder = $resourceBuilder;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getLinks($productSku)
+    {
+        $linkList = [];
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->productRepository->get($productSku);
+        $links = $this->downloadableType->getLinks($product);
+        /** @var \Magento\Downloadable\Model\Link $link */
+        foreach ($links as $link) {
+            $linkList[] = $this->buildLink($link);
+        }
+        return $linkList;
+    }
+
+    /**
+     * Build a link data object
+     *
+     * @param \Magento\Downloadable\Model\Link $resourceData
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkInfo
+     */
+    protected function buildLink($resourceData)
+    {
+        $this->setBasicFields($resourceData, $this->linkBuilder);
+        $this->linkBuilder->setPrice($resourceData->getPrice());
+        $this->linkBuilder->setNumberOfDownloads($resourceData->getNumberOfDownloads());
+        $this->linkBuilder->setShareable($resourceData->getIsShareable());
+        $this->linkBuilder->setLinkResource($this->entityInfoGenerator('link', $resourceData));
+        return $this->linkBuilder->create();
+    }
+
+    /**
+     * Subroutine for buildLink and buildSample
+     *
+     * @param \Magento\Downloadable\Model\Link|\Magento\Downloadable\Model\Sample $resourceData
+     * @param Data\DownloadableLinkInfoBuilder|Data\DownloadableSampleInfoBuilder $builder
+     * @return null
+     */
+    protected function setBasicFields($resourceData, $builder)
+    {
+        $builder->populateWithArray([]);
+        $builder->setId($resourceData->getId());
+        $storeTitle = $resourceData->getStoreTitle();
+        $title = $resourceData->getTitle();
+        if (!empty($storeTitle)) {
+            $builder->setTitle($storeTitle);
+        } else {
+            $builder->setTitle($title);
+        }
+        $builder->setSortOrder($resourceData->getSortOrder());
+        $builder->setSampleResource($this->entityInfoGenerator('sample', $resourceData));
+    }
+
+    /**
+     * Build a sample data object
+     *
+     * @param \Magento\Downloadable\Model\Sample $resourceData
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableSampleInfo
+     */
+    protected function buildSample($resourceData)
+    {
+        $this->setBasicFields($resourceData, $this->sampleBuilder);
+        return $this->sampleBuilder->create();
+    }
+
+    /**
+     * Build file info data object
+     *
+     * @param string $entityType 'link' or 'sample'
+     * @param \Magento\Downloadable\Model\Link|\Magento\Downloadable\Model\Sample $resourceData
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfo|null
+     */
+    protected function entityInfoGenerator($entityType, $resourceData)
+    {
+        $type = $resourceData->getData($entityType . '_type');
+        if (empty($type)) {
+            return null;
+        }
+        $this->resourceBuilder->populateWithArray([]);
+        $this->resourceBuilder->setType($type);
+        $this->resourceBuilder->setUrl($resourceData->getData($entityType . '_url'));
+        $this->resourceBuilder->setFile($resourceData->getData($entityType . '_file'));
+        return $this->resourceBuilder->create();
+
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSamples($productSku)
+    {
+        $sampleList = [];
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->productRepository->get($productSku);
+        $samples = $this->downloadableType->getSamples($product);
+        /** @var \Magento\Downloadable\Model\Sample $sample */
+        foreach ($samples as $sample) {
+            $sampleList[] = $this->buildSample($sample);
+        }
+        return $sampleList;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceInterface.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceInterface.php
new file mode 100644
index 00000000000..8cdfc74a049
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceInterface.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+interface ReadServiceInterface
+{
+    /**
+     * List of samples for downloadable product
+     *
+     * @param string $productSku
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableSampleInfo[]
+     */
+    public function getSamples($productSku);
+
+    /**
+     * List of links with associated samples
+     *
+     * @param string $productSku
+     * @return \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkInfo[]
+     */
+    public function getLinks($productSku);
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteService.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteService.php
new file mode 100644
index 00000000000..10a01277a51
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteService.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+use \Magento\Downloadable\Service\V1\Data\FileContentUploaderInterface;
+use \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent;
+use \Magento\Catalog\Model\ProductRepository;
+use \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContentValidator;
+use \Magento\Downloadable\Model\Link;
+use \Magento\Framework\Exception\InputException;
+use \Magento\Framework\Json\EncoderInterface;
+use \Magento\Downloadable\Model\LinkFactory;
+use \Magento\Framework\Exception\NoSuchEntityException;
+
+class WriteService implements WriteServiceInterface
+{
+    /**
+     * @var ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var DownloadableLinkContentValidator
+     */
+    protected $linkContentValidator;
+
+    /**
+     * @var FileContentUploaderInterface
+     */
+    protected $fileContentUploader;
+
+    /**
+     * @var EncoderInterface
+     */
+    protected $jsonEncoder;
+
+    /**
+     * @var \Magento\Downloadable\Model\LinkFactory
+     */
+    protected $linkFactory;
+
+    /**
+     * @param ProductRepository $productRepository
+     * @param DownloadableLinkContentValidator $linkContentValidator
+     * @param FileContentUploaderInterface $fileContentUploader
+     * @param EncoderInterface $jsonEncoder
+     * @param LinkFactory $linkFactory
+     */
+    public function __construct(
+        ProductRepository $productRepository,
+        DownloadableLinkContentValidator $linkContentValidator,
+        FileContentUploaderInterface $fileContentUploader,
+        EncoderInterface $jsonEncoder,
+        LinkFactory $linkFactory
+    ) {
+        $this->productRepository = $productRepository;
+        $this->linkContentValidator = $linkContentValidator;
+        $this->fileContentUploader = $fileContentUploader;
+        $this->jsonEncoder = $jsonEncoder;
+        $this->linkFactory = $linkFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function create($productSku, DownloadableLinkContent $linkContent, $isGlobalScopeContent = false)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        if ($product->getTypeId() !== \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
+            throw new InputException('Product type of the product must be \'downloadable\'.');
+        }
+        if (!$this->linkContentValidator->isValid($linkContent)) {
+            throw new InputException('Provided link information is invalid.');
+        }
+
+        if (!in_array($linkContent->getLinkType(), array('url', 'file'))) {
+            throw new InputException('Invalid link type.');
+        }
+        $title = $linkContent->getTitle();
+        if (empty($title)) {
+            throw new InputException('Link title cannot be empty.');
+        }
+
+        $linkData = array(
+            'link_id' => 0,
+            'is_delete' => 0,
+            'type' => $linkContent->getLinkType(),
+            'sort_order' => $linkContent->getSortOrder(),
+            'title' => $linkContent->getTitle(),
+            'price' => $linkContent->getPrice(),
+            'number_of_downloads' => $linkContent->getNumberOfDownloads(),
+            'is_shareable' => $linkContent->isShareable()
+        );
+
+        if ($linkContent->getLinkType() == 'file') {
+            $linkData['file'] = $this->jsonEncoder->encode(array(
+                $this->fileContentUploader->upload($linkContent->getLinkFile(), 'link_file')
+            ));
+        } else {
+            $linkData['link_url'] = $linkContent->getLinkUrl();
+        }
+
+        if ($linkContent->getSampleType() == 'file') {
+            $linkData['sample']['type'] = 'file';
+            $linkData['sample']['file'] = $this->jsonEncoder->encode(array(
+                $this->fileContentUploader->upload($linkContent->getSampleFile(), 'link_sample_file')
+            ));
+        } elseif ($linkContent->getSampleType() == 'url') {
+            $linkData['sample']['type'] = 'url';
+            $linkData['sample']['url'] = $linkContent->getSampleUrl();
+        }
+
+        $downloadableData = array('link' => array($linkData));
+        $product->setDownloadableData($downloadableData);
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $product->save();
+        return $product->getLastAddedLinkId();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update($productSku, $linkId, DownloadableLinkContent $linkContent, $isGlobalScopeContent = false)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        /** @var $link \Magento\Downloadable\Model\Link */
+        $link = $this->linkFactory->create()->load($linkId);
+        if (!$link->getId()) {
+            throw new NoSuchEntityException('There is no downloadable link with provided ID.');
+        }
+        if ($link->getProductId() != $product->getId()) {
+            throw new InputException('Provided downloadable link is not related to given product.');
+        }
+        if (!$this->linkContentValidator->isValid($linkContent)) {
+            throw new InputException('Provided link information is invalid.');
+        }
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $title = $linkContent->getTitle();
+        if (empty($title)) {
+            if ($isGlobalScopeContent) {
+                throw new InputException('Link title cannot be empty.');
+            }
+            // use title from GLOBAL scope
+            $link->setTitle(null);
+        } else {
+            $link->setTitle($linkContent->getTitle());
+        }
+
+        $link->setProductId($product->getId())
+            ->setStoreId($product->getStoreId())
+            ->setWebsiteId($product->getStore()->getWebsiteId())
+            ->setProductWebsiteIds($product->getWebsiteIds())
+            ->setSortOrder($linkContent->getSortOrder())
+            ->setPrice($linkContent->getPrice())
+            ->setIsShareable($linkContent->isShareable())
+            ->setNumberOfDownloads($linkContent->getNumberOfDownloads())
+            ->save();
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($linkId)
+    {
+        /** @var $link \Magento\Downloadable\Model\Link */
+        $link = $this->linkFactory->create()->load($linkId);
+        if (!$link->getId()) {
+            throw new NoSuchEntityException('There is no downloadable link with provided ID.');
+        }
+        $link->delete();
+        return true;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceInterface.php b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceInterface.php
new file mode 100644
index 00000000000..d3668b4deba
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceInterface.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+use \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent;
+
+interface WriteServiceInterface
+{
+    /**
+     * Add downloadable link to the given product
+     *
+     * @param string $productSku
+     * @param \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent $linkContent
+     * @param bool $isGlobalScopeContent
+     * @return int link ID
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function create($productSku, DownloadableLinkContent $linkContent, $isGlobalScopeContent = false);
+
+    /**
+     * Update downloadable link of the given product (link type and its resources cannot be changed)
+     *
+     * @param string $productSku
+     * @param int $linkId
+     * @param \Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent $linkContent
+     * @param bool $isGlobalScopeContent
+     * @return bool
+     */
+    public function update($productSku, $linkId, DownloadableLinkContent $linkContent, $isGlobalScopeContent = false);
+
+    /**
+     * Delete downloadable link
+     *
+     * @param int $linkId
+     * @return bool
+     */
+    public function delete($linkId);
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContent.php b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContent.php
new file mode 100644
index 00000000000..349d35f84f7
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContent.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class DownloadableSampleContent extends AbstractObject
+{
+    const TITLE = 'title';
+    const SORT_ORDER = 'sort_order';
+    const SAMPLE_FILE = 'file';
+    const SAMPLE_URL = 'url';
+    const SAMPLE_TYPE = 'sample_type';
+
+    /**
+     * Retrieve sample title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->_get(self::TITLE);
+    }
+
+    /**
+     * Retrieve sample type ('url' or 'file')
+     *
+     * @return string|null
+     */
+    public function getSampleType()
+    {
+        return $this->_get(self::SAMPLE_TYPE);
+    }
+
+    /**
+     * Retrieve sample file content
+     *
+     * @return \Magento\Downloadable\Service\V1\Data\FileContent|null
+     */
+    public function getSampleFile()
+    {
+        return $this->_get(self::SAMPLE_FILE);
+    }
+
+    /**
+     * Retrieve sample sort order
+     *
+     * @return int
+     */
+    public function getSortOrder()
+    {
+        return $this->_get(self::SORT_ORDER);
+    }
+
+    /**
+     * Retrieve sample URL
+     *
+     * @return string|null
+     */
+    public function getSampleUrl()
+    {
+        return $this->_get(self::SAMPLE_URL);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentBuilder.php b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentBuilder.php
new file mode 100644
index 00000000000..11b7b09c342
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentBuilder.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Downloadable Link Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample\Data;
+
+use \Magento\Framework\Service\Data\AbstractObjectBuilder;
+use \Magento\Downloadable\Service\V1\Data\FileContent;
+
+class DownloadableSampleContentBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set link title
+     *
+     * @param string $title
+     * @return $this
+     */
+    public function setTitle($title)
+    {
+        return $this->_set(DownloadableSampleContent::TITLE, $title);
+    }
+
+    /**
+     * Set sample file content
+     *
+     * @param FileContent $sampleFile
+     * @return $this
+     */
+    public function setSampleFile($sampleFile)
+    {
+        return $this->_set(DownloadableSampleContent::SAMPLE_FILE, $sampleFile);
+    }
+
+    /**
+     * Set sample type ('url' or 'file')
+     *
+     * @param string $sampleType
+     * @return $this
+     */
+    public function setSampleType($sampleType)
+    {
+        return $this->_set(DownloadableSampleContent::SAMPLE_TYPE, $sampleType);
+    }
+
+    /**
+     * Set sample URL
+     *
+     * @param string $sampleUrl
+     * @return $this
+     */
+    public function setSampleUrl($sampleUrl)
+    {
+        return $this->_set(DownloadableSampleContent::SAMPLE_URL, $sampleUrl);
+    }
+
+    /**
+     * Set sample sort order
+     *
+     * @param int $sortOrder
+     * @return $this
+     */
+    public function setSortOrder($sortOrder)
+    {
+        return $this->_set(DownloadableSampleContent::SORT_ORDER, $sortOrder);
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidator.php b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidator.php
new file mode 100644
index 00000000000..1677d150fd5
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidator.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample\Data;
+
+use \Magento\Downloadable\Service\V1\Data\FileContentValidator;
+use \Magento\Framework\Url\Validator as UrlValidator;
+use \Magento\Framework\Exception\InputException;
+
+class DownloadableSampleContentValidator
+{
+    /**
+     * @var UrlValidator
+     */
+    protected $urlValidator;
+
+    /**
+     * @var FileContentValidator
+     */
+    protected $fileContentValidator;
+
+    /**
+     * @param FileContentValidator $fileContentValidator
+     * @param UrlValidator $urlValidator
+     */
+    public function __construct(
+        FileContentValidator $fileContentValidator,
+        UrlValidator $urlValidator
+    ) {
+        $this->fileContentValidator = $fileContentValidator;
+        $this->urlValidator = $urlValidator;
+    }
+
+    /**
+     * Check if sample content is valid
+     *
+     * @param DownloadableSampleContent $sampleContent
+     * @return bool
+     * @throws InputException
+     */
+    public function isValid(DownloadableSampleContent $sampleContent)
+    {
+        if (!is_int($sampleContent->getSortOrder()) || $sampleContent->getSortOrder() < 0) {
+            throw new InputException('Sort order must be a positive integer.');
+        }
+
+        $this->validateSampleResource($sampleContent);
+        return true;
+    }
+
+    /**
+     * Validate sample resource (file or URL)
+     *
+     * @param DownloadableSampleContent $sampleContent
+     * @throws InputException
+     * @return void
+     */
+    protected function validateSampleResource(DownloadableSampleContent $sampleContent)
+    {
+        $sampleFile = $sampleContent->getSampleFile();
+        if ($sampleContent->getSampleType() == 'file'
+            && (!$sampleFile || !$this->fileContentValidator->isValid($sampleFile))
+        ) {
+            throw new InputException('Provided file content must be valid base64 encoded data.');
+        }
+
+        if ($sampleContent->getSampleType() == 'url'
+            && !$this->urlValidator->isValid($sampleContent->getSampleUrl())
+        ) {
+            throw new InputException('Sample URL must have valid format.');
+        }
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteService.php b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteService.php
new file mode 100644
index 00000000000..2fc1545949a
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteService.php
@@ -0,0 +1,188 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample;
+
+use \Magento\Downloadable\Service\V1\Data\FileContentUploaderInterface;
+use \Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent;
+use \Magento\Catalog\Model\ProductRepository;
+use \Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContentValidator;
+use \Magento\Framework\Exception\InputException;
+use \Magento\Framework\Json\EncoderInterface;
+use \Magento\Downloadable\Model\SampleFactory;
+use \Magento\Framework\Exception\NoSuchEntityException;
+
+class WriteService implements WriteServiceInterface
+{
+    /**
+     * @var ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var DownloadableSampleContentValidator
+     */
+    protected $contentValidator;
+
+    /**
+     * @var FileContentUploaderInterface
+     */
+    protected $fileContentUploader;
+
+    /**
+     * @var EncoderInterface
+     */
+    protected $jsonEncoder;
+
+    /**
+     * @var \Magento\Downloadable\Model\LinkFactory
+     */
+    protected $linkFactory;
+
+    /**
+     * @param ProductRepository $productRepository
+     * @param DownloadableSampleContentValidator $contentValidator
+     * @param FileContentUploaderInterface $fileContentUploader
+     * @param EncoderInterface $jsonEncoder
+     * @param SampleFactory $sampleFactory
+     */
+    public function __construct(
+        ProductRepository $productRepository,
+        DownloadableSampleContentValidator $contentValidator,
+        FileContentUploaderInterface $fileContentUploader,
+        EncoderInterface $jsonEncoder,
+        SampleFactory $sampleFactory
+    ) {
+        $this->productRepository = $productRepository;
+        $this->contentValidator = $contentValidator;
+        $this->fileContentUploader = $fileContentUploader;
+        $this->jsonEncoder = $jsonEncoder;
+        $this->sampleFactory = $sampleFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function create($productSku, DownloadableSampleContent $sampleContent, $isGlobalScopeContent = false)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        if ($product->getTypeId() !== \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
+            throw new InputException('Product type of the product must be \'downloadable\'.');
+        }
+        if (!$this->contentValidator->isValid($sampleContent)) {
+            throw new InputException('Provided sample information is invalid.');
+        }
+
+        if (!in_array($sampleContent->getSampleType(), array('url', 'file'))) {
+            throw new InputException('Invalid sample type.');
+        }
+
+        $title = $sampleContent->getTitle();
+        if (empty($title)) {
+            throw new InputException('Sample title cannot be empty.');
+        }
+
+        $sampleData = array(
+            'sample_id' => 0,
+            'is_delete' => 0,
+            'type' => $sampleContent->getSampleType(),
+            'sort_order' => $sampleContent->getSortOrder(),
+            'title' => $sampleContent->getTitle(),
+        );
+
+        if ($sampleContent->getSampleType() == 'file') {
+            $sampleData['file'] = $this->jsonEncoder->encode(array(
+                $this->fileContentUploader->upload($sampleContent->getSampleFile(), 'sample')
+            ));
+        } else {
+            $sampleData['sample_url'] = $sampleContent->getSampleUrl();
+        }
+
+        $downloadableData = array('sample' => array($sampleData));
+        $product->setDownloadableData($downloadableData);
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $product->save();
+        return $product->getLastAddedSampleId();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update(
+        $productSku,
+        $sampleId,
+        DownloadableSampleContent $sampleContent,
+        $isGlobalScopeContent = false
+    ) {
+        $product = $this->productRepository->get($productSku, true);
+        /** @var $sample \Magento\Downloadable\Model\Sample */
+        $sample = $this->sampleFactory->create()->load($sampleId);
+        if (!$sample->getId()) {
+            throw new NoSuchEntityException('There is no downloadable sample with provided ID.');
+        }
+        if ($sample->getProductId() != $product->getId()) {
+            throw new InputException('Provided downloadable sample is not related to given product.');
+        }
+        if (!$this->contentValidator->isValid($sampleContent)) {
+            throw new InputException('Provided sample information is invalid.');
+        }
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+
+        $title = $sampleContent->getTitle();
+        if (empty($title)) {
+            if ($isGlobalScopeContent) {
+                throw new InputException('Sample title cannot be empty.');
+            }
+            // use title from GLOBAL scope
+            $sample->setTitle(null);
+        } else {
+            $sample->setTitle($sampleContent->getTitle());
+        }
+
+        $sample->setProductId($product->getId())
+            ->setStoreId($product->getStoreId())
+            ->setSortOrder($sampleContent->getSortOrder())
+            ->save();
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($sampleId)
+    {
+        /** @var $sample \Magento\Downloadable\Model\Sample */
+        $sample = $this->sampleFactory->create()->load($sampleId);
+        if (!$sample->getId()) {
+            throw new NoSuchEntityException('There is no downloadable sample with provided ID.');
+        }
+        $sample->delete();
+        return true;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceInterface.php b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceInterface.php
new file mode 100644
index 00000000000..572dbe3f353
--- /dev/null
+++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceInterface.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample;
+
+use \Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent;
+
+interface WriteServiceInterface
+{
+    /**
+     * Add downloadable sample to the given product
+     *
+     * @param string $productSku
+     * @param \Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent $sampleContent
+     * @param bool $isGlobalScopeContent
+     * @return int sample ID
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function create($productSku, DownloadableSampleContent $sampleContent, $isGlobalScopeContent = false);
+
+    /**
+     * Update downloadable sample of the given product (sample type and its resource cannot be changed)
+     *
+     * @param string $productSku
+     * @param int $sampleId
+     * @param \Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent $sampleContent
+     * @param bool $isGlobalScopeContent
+     * @return bool
+     */
+    public function update(
+        $productSku,
+        $sampleId,
+        DownloadableSampleContent $sampleContent,
+        $isGlobalScopeContent = false
+    );
+
+    /**
+     * Delete downloadable sample
+     *
+     * @param int $sampleId
+     * @return bool
+     */
+    public function delete($sampleId);
+}
diff --git a/app/code/Magento/Downloadable/etc/di.xml b/app/code/Magento/Downloadable/etc/di.xml
index 8d51abb5b46..4f186c9934e 100644
--- a/app/code/Magento/Downloadable/etc/di.xml
+++ b/app/code/Magento/Downloadable/etc/di.xml
@@ -75,4 +75,8 @@
             </argument>
         </arguments>
     </type>
+    <preference for="\Magento\Downloadable\Service\V1\DownloadableLink\ReadServiceInterface" type="\Magento\Downloadable\Service\V1\DownloadableLink\ReadService" />
+    <preference for="\Magento\Downloadable\Service\V1\DownloadableLink\WriteServiceInterface" type="\Magento\Downloadable\Service\V1\DownloadableLink\WriteService" />
+    <preference for="\Magento\Downloadable\Service\V1\Data\FileContentUploaderInterface" type="\Magento\Downloadable\Service\V1\Data\FileContentUploader" />
+    <preference for="\Magento\Downloadable\Service\V1\DownloadableSample\WriteServiceInterface" type="\Magento\Downloadable\Service\V1\DownloadableSample\WriteService" />
 </config>
diff --git a/app/code/Magento/Downloadable/etc/webapi.xml b/app/code/Magento/Downloadable/etc/webapi.xml
new file mode 100644
index 00000000000..fd1001d7890
--- /dev/null
+++ b/app/code/Magento/Downloadable/etc/webapi.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="../../../../../app/code/Magento/Webapi/etc/webapi.xsd">
+    <route url="/V1/products/:productSku/downloadable-links" method="GET">
+        <service class="Magento\Downloadable\Service\V1\DownloadableLink\ReadServiceInterface" method="getLinks"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/downloadable-links/samples" method="GET">
+        <service class="Magento\Downloadable\Service\V1\DownloadableLink\ReadServiceInterface" method="getSamples"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/downloadable-links" method="POST">
+        <service class="Magento\Downloadable\Service\V1\DownloadableLink\WriteServiceInterface" method="create"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/downloadable-links/:linkId" method="PUT">
+        <service class="Magento\Downloadable\Service\V1\DownloadableLink\WriteServiceInterface" method="update"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/downloadable-links/:linkId" method="DELETE">
+        <service class="Magento\Downloadable\Service\V1\DownloadableLink\WriteServiceInterface" method="delete"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/downloadable-links/samples" method="POST">
+        <service class="Magento\Downloadable\Service\V1\DownloadableSample\WriteServiceInterface" method="create"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/downloadable-links/samples/:sampleId" method="PUT">
+        <service class="Magento\Downloadable\Service\V1\DownloadableSample\WriteServiceInterface" method="update"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+    <route url="/V1/products/downloadable-links/samples/:sampleId" method="DELETE">
+        <service class="Magento\Downloadable\Service\V1\DownloadableSample\WriteServiceInterface" method="delete"/>
+        <resources>
+            <resource ref="Magento_Downloadable::downloadable" />
+        </resources>
+    </route>
+</routes>
diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
index d037f999c20..5ff4a9bd0d1 100644
--- a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
+++ b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
@@ -347,7 +347,7 @@ abstract class AbstractCollection extends \Magento\Framework\Data\Collection\Db
 
         if (is_numeric($attribute)) {
             $attribute = $this->getEntity()->getAttribute($attribute)->getAttributeCode();
-        } else if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AttributeInterface) {
+        } elseif ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AttributeInterface) {
             $attribute = $attribute->getAttributeCode();
         }
 
@@ -357,7 +357,7 @@ abstract class AbstractCollection extends \Magento\Framework\Data\Collection\Db
                 $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
             }
             $conditionSql = '(' . implode(') OR (', $sqlArr) . ')';
-        } else if (is_string($attribute)) {
+        } elseif (is_string($attribute)) {
             if ($condition === null) {
                 $condition = '';
             }
diff --git a/app/code/Magento/Email/Controller/Adminhtml/Email/Template.php b/app/code/Magento/Email/Controller/Adminhtml/Email/Template.php
index 6f9f80768f5..95fececde1f 100644
--- a/app/code/Magento/Email/Controller/Adminhtml/Email/Template.php
+++ b/app/code/Magento/Email/Controller/Adminhtml/Email/Template.php
@@ -261,7 +261,7 @@ class Template extends \Magento\Backend\App\Action
             $templateBlock = $this->_view->getLayout()->createBlock('Magento\Email\Block\Adminhtml\Template\Edit');
             $template->setData('orig_template_used_default_for', $templateBlock->getUsedDefaultForPaths(false));
 
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($template->getData())
             );
         } catch (\Exception $e) {
diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php
index 2b1a595d3f3..8582336c635 100644
--- a/app/code/Magento/Fedex/Model/Carrier.php
+++ b/app/code/Magento/Fedex/Model/Carrier.php
@@ -133,6 +133,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
      * @param \Magento\Directory\Model\CountryFactory $countryFactory
      * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
      * @param \Magento\Directory\Helper\Data $directoryData
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Logger $logger
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\Module\Dir\Reader $configReader
@@ -155,6 +156,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
         \Magento\Directory\Model\CountryFactory $countryFactory,
         \Magento\Directory\Model\CurrencyFactory $currencyFactory,
         \Magento\Directory\Helper\Data $directoryData,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Logger $logger,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Framework\Module\Dir\Reader $configReader,
@@ -177,6 +179,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
             $countryFactory,
             $currencyFactory,
             $directoryData,
+            $stockItemService,
             $data
         );
         $wsdlBasePath = $configReader->getModuleDir('etc', 'Magento_Fedex') . '/wsdl/';
diff --git a/app/code/Magento/Fedex/etc/module.xml b/app/code/Magento/Fedex/etc/module.xml
index 1635c68fe69..8f13222ae32 100644
--- a/app/code/Magento/Fedex/etc/module.xml
+++ b/app/code/Magento/Fedex/etc/module.xml
@@ -32,6 +32,7 @@
             <module name="Magento_Core"/>
             <module name="Magento_Catalog"/>
             <module name="Magento_Sales"/>
+            <module name="Magento_CatalogInventory"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php b/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php
index 0510cf67eae..c92b4d9cc1f 100644
--- a/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php
+++ b/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php
@@ -348,9 +348,8 @@ class Items extends \Magento\Backend\App\Action
     public function statusAction()
     {
         if ($this->getRequest()->isAjax()) {
-            $this->getResponse()->setHeader('Content-Type', 'application/json');
             $params = array('is_running' => $this->_getFlag()->isLocked());
-            return $this->getResponse()->setBody(
+            return $this->getResponse()->representJson(
                 $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($params)
             );
         }
@@ -377,10 +376,7 @@ class Items extends \Magento\Backend\App\Action
             )
         );
         if ($this->getRequest()->isAjax()) {
-            $this->getResponse()->setHeader(
-                'Content-Type',
-                'application/json'
-            )->setBody(
+            $this->getResponse()->representJson(
                 $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array('redirect' => $redirectUrl))
             );
         } else {
diff --git a/app/code/Magento/GoogleShopping/Model/Attribute/Content.php b/app/code/Magento/GoogleShopping/Model/Attribute/Content.php
index 7633d70cd5c..b750290f0f9 100644
--- a/app/code/Magento/GoogleShopping/Model/Attribute/Content.php
+++ b/app/code/Magento/GoogleShopping/Model/Attribute/Content.php
@@ -42,7 +42,7 @@ class Content extends \Magento\GoogleShopping\Model\Attribute\DefaultAttribute
     {
         $mapValue = $this->getProductAttributeValue($product);
         $description = $this->getGroupAttributeDescription();
-        if (!is_null($description)) {
+        if (!is_null($description) && !is_null($description->getAttributeId())) {
             $mapValue = $description->getProductAttributeValue($product);
         }
 
diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
index ec2d14c2585..154086e87ce 100644
--- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
@@ -470,4 +470,15 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
     public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
     {
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function beforeSave($product)
+    {
+        if ($product->hasData('product_options')) {
+            throw new \Exception('Custom options for grouped product type are not supported');
+        }
+        return parent::beforeSave($product);
+    }
 }
diff --git a/app/code/Magento/Integration/Controller/Adminhtml/Integration.php b/app/code/Magento/Integration/Controller/Adminhtml/Integration.php
index ab82118a0f7..e161451c1eb 100644
--- a/app/code/Magento/Integration/Controller/Adminhtml/Integration.php
+++ b/app/code/Magento/Integration/Controller/Adminhtml/Integration.php
@@ -266,7 +266,7 @@ class Integration extends Action
                 }
                 if ($this->getRequest()->isXmlHttpRequest()) {
                     $isTokenExchange = $integration->getEndpoint() && $integration->getIdentityLinkUrl() ? '1' : '0';
-                    $this->getResponse()->setBody(
+                    $this->getResponse()->representJson(
                         $this->_coreHelper->jsonEncode(
                             array('integrationId' => $integration->getId(), 'isTokenExchange' => $isTokenExchange)
                         )
@@ -446,7 +446,7 @@ class Integration extends Action
                 IntegrationModel::CONSUMER_ID => $integration->getConsumerId(),
                 'popup_content' => $popupContent
             );
-            $this->getResponse()->setBody($this->_coreHelper->jsonEncode($result));
+            $this->getResponse()->representJson($this->_coreHelper->jsonEncode($result));
         } catch (\Magento\Framework\Model\Exception $e) {
             $this->messageManager->addError($e->getMessage());
             $this->_redirect('*/*');
@@ -494,7 +494,7 @@ class Integration extends Action
     protected function _redirect($path, $arguments = array())
     {
         if ($this->getRequest()->isXmlHttpRequest()) {
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_coreHelper->jsonEncode(array('_redirect' => $this->getUrl($path, $arguments)))
             );
             return $this;
diff --git a/app/code/Magento/Paypal/Model/Observer.php b/app/code/Magento/Paypal/Model/Observer.php
index c2d6515ab78..5a8782ba831 100644
--- a/app/code/Magento/Paypal/Model/Observer.php
+++ b/app/code/Magento/Paypal/Model/Observer.php
@@ -202,7 +202,7 @@ class Observer
                     $result['redirect'] = false;
                     $result['success'] = false;
                     $controller->getResponse()->clearHeader('Location');
-                    $controller->getResponse()->setBody($this->_coreData->jsonEncode($result));
+                    $controller->getResponse()->representJson($this->_coreData->jsonEncode($result));
                 }
             }
         }
diff --git a/app/code/Magento/RecurringPayment/Block/Adminhtml/Payment/View/Items.php b/app/code/Magento/RecurringPayment/Block/Adminhtml/Payment/View/Items.php
index 665f4e87a0f..b6a979ea3ce 100644
--- a/app/code/Magento/RecurringPayment/Block/Adminhtml/Payment/View/Items.php
+++ b/app/code/Magento/RecurringPayment/Block/Adminhtml/Payment/View/Items.php
@@ -25,8 +25,6 @@ namespace Magento\RecurringPayment\Block\Adminhtml\Payment\View;
 
 /**
  * Adminhtml recurring payment items grid
- *
- * @author      Magento Core Team <core@magentocommerce.com>
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
@@ -34,6 +32,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      * Retrieve required options from parent
      *
      * @return void
+     * @throws \Magento\Framework\Model\Exception
      */
     protected function _beforeToHtml()
     {
diff --git a/app/code/Magento/Reports/Model/Resource/Product/Lowstock/Collection.php b/app/code/Magento/Reports/Model/Resource/Product/Lowstock/Collection.php
index 7989688d704..839db3bcb64 100644
--- a/app/code/Magento/Reports/Model/Resource/Product/Lowstock/Collection.php
+++ b/app/code/Magento/Reports/Model/Resource/Product/Lowstock/Collection.php
@@ -47,7 +47,7 @@ class Collection extends \Magento\Reports\Model\Resource\Product\Collection
     protected $_inventoryItemTableAlias = 'lowstock_inventory_item';
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
     protected $stockItemService;
 
@@ -78,7 +78,7 @@ class Collection extends \Magento\Reports\Model\Resource\Product\Collection
      * @param \Magento\Catalog\Model\Resource\Product $product
      * @param \Magento\Reports\Model\Event\TypeFactory $eventTypeFactory
      * @param \Magento\Catalog\Model\Product\Type $productType
-     * @param \Magento\CatalogInventory\Service\V1\StockItem $stockItemService
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\CatalogInventory\Model\Resource\Stock\Item $itemResource
      * @param mixed $connection
      *
@@ -106,7 +106,7 @@ class Collection extends \Magento\Reports\Model\Resource\Product\Collection
         \Magento\Catalog\Model\Resource\Product $product,
         \Magento\Reports\Model\Event\TypeFactory $eventTypeFactory,
         \Magento\Catalog\Model\Product\Type $productType,
-        \Magento\CatalogInventory\Service\V1\StockItem $stockItemService,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\CatalogInventory\Model\Resource\Stock\Item $itemResource,
         $connection = null
     ) {
diff --git a/app/code/Magento/Review/Controller/Adminhtml/Product.php b/app/code/Magento/Review/Controller/Adminhtml/Product.php
index e2877ab0958..c96d02271c3 100644
--- a/app/code/Magento/Review/Controller/Adminhtml/Product.php
+++ b/app/code/Magento/Review/Controller/Adminhtml/Product.php
@@ -370,7 +370,7 @@ class Product extends \Magento\Backend\App\Action
             $response->setError(1);
             $response->setMessage(__('We can\'t get the product ID.'));
         }
-        $this->getResponse()->setBody($response->toJSON());
+        $this->getResponse()->representJson($response->toJSON());
     }
 
     /**
diff --git a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
index d7f7c8d3bb7..aca5ad37d2e 100644
--- a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
+++ b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
@@ -404,7 +404,7 @@ abstract class AbstractCondition extends \Magento\Framework\Object implements Co
                     if (in_array($option['value'], $value)) {
                         $valueArr[] = $option['label'];
                     }
-                } else {
+                } elseif (isset($option['value'])) {
                     if (is_array($option['value'])) {
                         foreach ($option['value'] as $optionValue) {
                             if ($optionValue['value'] == $value) {
diff --git a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
index c984002ae1e..0980463bccf 100644
--- a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
+++ b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
@@ -217,6 +217,15 @@ abstract class AbstractProduct extends \Magento\Rule\Model\Condition\AbstractCon
                 ->setEntityTypeFilter($entityTypeId)
                 ->load()
                 ->toOptionArray();
+        } elseif ($this->getAttribute() === 'type_id') {
+            foreach ($selectReady as $value => $label) {
+                if (is_array($label) && isset($label['value'])) {
+                    $selectOptions[] = $label;
+                } else {
+                    $selectOptions[] = array('value' => $value, 'label' => $label);
+                }
+            }
+            $selectReady = null;
         } elseif (is_object($this->getAttributeObject())) {
             $attributeObject = $this->getAttributeObject();
             if ($attributeObject->usesSource()) {
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Items/AbstractItems.php b/app/code/Magento/Sales/Block/Adminhtml/Items/AbstractItems.php
index e2a0a0bb002..ec740624191 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Items/AbstractItems.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Items/AbstractItems.php
@@ -51,33 +51,33 @@ class AbstractItems extends \Magento\Backend\Block\Template
      *
      * @var bool|null
      */
-    protected $_canEditQty = null;
+    protected $_canEditQty;
 
     /**
      * Core registry
      *
      * @var \Magento\Framework\Registry
      */
-    protected $_coreRegistry = null;
+    protected $_coreRegistry;
 
     /**
-     * @var \Magento\Catalog\Model\ProductFactory
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
      */
-    protected $_productFactory;
+    protected $stockItemService;
 
     /**
      * @param \Magento\Backend\Block\Template\Context $context
-     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Registry $registry
      * @param array $data
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
-        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Registry $registry,
         array $data = array()
     ) {
-        $this->_productFactory = $productFactory;
+        $this->stockItemService = $stockItemService;
         $this->_coreRegistry = $registry;
         parent::__construct($context, $data);
     }
@@ -331,14 +331,14 @@ class AbstractItems extends \Magento\Backend\Block\Template
     public function displayPriceInclTax(\Magento\Framework\Object $item)
     {
         $qty = $item->getQtyOrdered() ? $item->getQtyOrdered() : ($item->getQty() ? $item->getQty() : 1);
-        $baseTax = $item->getTaxBeforeDiscount() ? $item
-            ->getTaxBeforeDiscount() : ($item
-            ->getTaxAmount() ? $item
-            ->getTaxAmount() : 0);
-        $tax = $item->getBaseTaxBeforeDiscount() ? $item
-            ->getBaseTaxBeforeDiscount() : ($item
-            ->getBaseTaxAmount() ? $item
-            ->getBaseTaxAmount() : 0);
+
+        $baseTax = $item->getTaxBeforeDiscount()
+            ? $item->getTaxBeforeDiscount()
+            : ($item->getTaxAmount() ? $item->getTaxAmount() : 0);
+
+        $tax = $item->getBaseTaxBeforeDiscount()
+            ? $item->getBaseTaxBeforeDiscount()
+            : ($item->getBaseTaxAmount() ? $item->getBaseTaxAmount() : 0);
 
         $basePriceTax = 0;
         $priceTax = 0;
@@ -362,14 +362,13 @@ class AbstractItems extends \Magento\Backend\Block\Template
      */
     public function displaySubtotalInclTax($item)
     {
-        $baseTax = $item->getTaxBeforeDiscount() ? $item
-            ->getTaxBeforeDiscount() : ($item
-            ->getTaxAmount() ? $item
-            ->getTaxAmount() : 0);
-        $tax = $item->getBaseTaxBeforeDiscount() ? $item
-            ->getBaseTaxBeforeDiscount() : ($item
-            ->getBaseTaxAmount() ? $item
-            ->getBaseTaxAmount() : 0);
+        $baseTax = $item->getTaxBeforeDiscount()
+            ? $item->getTaxBeforeDiscount()
+            : ($item->getTaxAmount() ? $item->getTaxAmount() : 0);
+
+        $tax = $item->getBaseTaxBeforeDiscount()
+            ? $item->getBaseTaxBeforeDiscount()
+            : ($item->getBaseTaxAmount() ? $item->getBaseTaxAmount() : 0);
 
         return $this->displayPrices($item->getBaseRowTotal() + $baseTax, $item->getRowTotal() + $tax);
     }
@@ -397,7 +396,7 @@ class AbstractItems extends \Magento\Backend\Block\Template
     }
 
     /**
-     * Retrieve tax with persent html content
+     * Retrieve tax with percent html content
      *
      * @param \Magento\Framework\Object $item
      * @return string
@@ -462,11 +461,8 @@ class AbstractItems extends \Magento\Backend\Block\Template
          * Disable editing of quantity of item if creating of shipment forced
          * and ship partially disabled for order
          */
-        if ($this->getOrder()->getForcedShipmentWithInvoice() && ($this->canShipPartially(
-            $this->getOrder()
-        ) || $this->canShipPartiallyItem(
-            $this->getOrder()
-        ))
+        if ($this->getOrder()->getForcedShipmentWithInvoice()
+            && ($this->canShipPartially($this->getOrder()) || $this->canShipPartiallyItem($this->getOrder()))
         ) {
             return false;
         }
@@ -527,11 +523,11 @@ class AbstractItems extends \Magento\Backend\Block\Template
      */
     public function canReturnToStock()
     {
-        if ($this->_scopeConfig->getValue(
+        $canSubtract = $this->_scopeConfig->getValue(
             \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_CAN_SUBTRACT,
             \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-        )
-        ) {
+        );
+        if ($canSubtract) {
             return true;
         } else {
             return false;
@@ -546,20 +542,21 @@ class AbstractItems extends \Magento\Backend\Block\Template
      */
     public function canReturnItemToStock($item = null)
     {
-        $canReturnToStock = $this->_scopeConfig->getValue(
-            \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_CAN_SUBTRACT,
-            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-        );
-        if (!is_null($item)) {
+        if (null !== $item) {
             if (!$item->hasCanReturnToStock()) {
-                $product = $this->_productFactory->create()->load($item->getOrderItem()->getProductId());
-                if ($product->getId() && $product->getStockItem()->getManageStock()) {
+                $productId = $item->getOrderItem()->getProductId();
+                if ($productId && $this->stockItemService->getManageStock($productId)) {
                     $item->setCanReturnToStock(true);
                 } else {
                     $item->setCanReturnToStock(false);
                 }
             }
             $canReturnToStock = $item->getCanReturnToStock();
+        } else {
+            $canReturnToStock = $this->_scopeConfig->getValue(
+                \Magento\CatalogInventory\Model\Stock\Item::XML_PATH_CAN_SUBTRACT,
+                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+            );
         }
         return $canReturnToStock;
     }
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Items/Renderer/DefaultRenderer.php b/app/code/Magento/Sales/Block/Adminhtml/Items/Renderer/DefaultRenderer.php
index f78de758024..f7f6c1028c7 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Items/Renderer/DefaultRenderer.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Items/Renderer/DefaultRenderer.php
@@ -27,8 +27,6 @@ use Magento\Sales\Model\Order\Item;
 
 /**
  * Adminhtml sales order item renderer
- *
- * @author     Magento Core Team <core@magentocommerce.com>
  */
 class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
index e814cc6f8ab..10431e2c48b 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
@@ -29,8 +29,6 @@ use Magento\Framework\Session\SessionManagerInterface;
 
 /**
  * Adminhtml sales order create items grid block
- *
- * @author      Magento Core Team <core@magentocommerce.com>
  */
 class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
 {
@@ -46,7 +44,7 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
      *
      * @var \Magento\Tax\Helper\Data
      */
-    protected $_taxData = null;
+    protected $_taxData;
 
     /**
      * Wishlist factory
@@ -76,6 +74,11 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
      */
     protected $_messageHelper;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\Backend\Model\Session\Quote $sessionQuote
@@ -85,6 +88,7 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
      * @param \Magento\Tax\Model\Config $taxConfig
      * @param \Magento\Tax\Helper\Data $taxData
      * @param \Magento\GiftMessage\Helper\Message $messageHelper
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -96,6 +100,7 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
         \Magento\Tax\Model\Config $taxConfig,
         \Magento\Tax\Helper\Data $taxData,
         \Magento\GiftMessage\Helper\Message $messageHelper,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_messageHelper = $messageHelper;
@@ -103,6 +108,7 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
         $this->_giftMessageSave = $giftMessageSave;
         $this->_taxConfig = $taxConfig;
         $this->_taxData = $taxData;
+        $this->stockItemService = $stockItemService;
         parent::__construct($context, $sessionQuote, $orderCreate, $data);
     }
 
@@ -132,24 +138,27 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
             $item->setQty($item->getQty());
 
             if (!$item->getMessage()) {
-                //Getting stock items for last quantity validation before grid display
+                //Getting product ids for stock item last quantity validation before grid display
                 $stockItemToCheck = array();
 
                 $childItems = $item->getChildren();
                 if (count($childItems)) {
                     foreach ($childItems as $childItem) {
-                        $stockItemToCheck[] = $childItem->getProduct()->getStockItem();
+                        $stockItemToCheck[] = $childItem->getProduct()->getId();
                     }
                 } else {
-                    $stockItemToCheck[] = $item->getProduct()->getStockItem();
+                    $stockItemToCheck[] = $item->getProduct()->getId();
                 }
 
-                foreach ($stockItemToCheck as $stockItem) {
-                    if ($stockItem instanceof \Magento\CatalogInventory\Model\Stock\Item) {
-                        $check = $stockItem->checkQuoteItemQty($item->getQty(), $item->getQty(), $item->getQty());
-                        $item->setMessage($check->getMessage());
-                        $item->setHasError($check->getHasError());
-                    }
+                foreach ($stockItemToCheck as $productId) {
+                    $check = $this->stockItemService->checkQuoteItemQty(
+                        $productId,
+                        $item->getQty(),
+                        $item->getQty(),
+                        $item->getQty()
+                    );
+                    $item->setMessage($check->getMessage());
+                    $item->setHasError($check->getHasError());
                 }
             }
 
@@ -227,7 +236,6 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
         if (is_null($item)) {
             return $this->_messageHelper->getIsMessagesAvailable('items', $this->getQuote(), $this->getStore());
         }
-
         return $this->_messageHelper->getIsMessagesAvailable('item', $item, $this->getStore());
     }
 
@@ -249,12 +257,9 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
      */
     public function displayTotalsIncludeTax()
     {
-        $res = $this->_taxConfig->displayCartSubtotalInclTax(
-            $this->getStore()
-        ) || $this->_taxConfig->displayCartSubtotalBoth(
-            $this->getStore()
-        );
-        return $res;
+        $result = $this->_taxConfig->displayCartSubtotalInclTax($this->getStore())
+            || $this->_taxConfig->displayCartSubtotalBoth($this->getStore());
+        return $result;
     }
 
     /**
@@ -265,15 +270,13 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
     public function getSubtotal()
     {
         $address = $this->getQuoteAddress();
-        if ($this->displayTotalsIncludeTax()) {
-            if ($address->getSubtotalInclTax()) {
-                return $address->getSubtotalInclTax();
-            }
-            return $address->getSubtotal() + $address->getTaxAmount();
-        } else {
+        if (!$this->displayTotalsIncludeTax()) {
             return $address->getSubtotal();
         }
-        return false;
+        if ($address->getSubtotalInclTax()) {
+            return $address->getSubtotalInclTax();
+        }
+        return $address->getSubtotal() + $address->getTaxAmount();
     }
 
     /**
@@ -372,13 +375,13 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
         $html = '';
         $prices = $item->getProduct()->getTierPrice();
         if ($prices) {
-            $info = $item->getProductType() ==
-                \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE ? $this->_getBundleTierPriceInfo(
-                    $prices
-                ) : $this->_getTierPriceInfo(
-                    $prices
-                );
-            $html = implode('<br/>', $info);
+            if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
+                $info = $this->_getBundleTierPriceInfo($prices);
+            } else {
+                $info = $this->_getTierPriceInfo($prices);
+            }
+
+            $html = implode('<br />', $info);
         }
         return $html;
     }
@@ -428,19 +431,13 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
         $this->_moveToCustomerStorage = true;
         if ($optionIds = $item->getOptionByCode('option_ids')) {
             foreach (explode(',', $optionIds->getValue()) as $optionId) {
-                if ($option = $item->getProduct()->getOptionById($optionId)) {
-                    $optionValue = $item->getOptionByCode('option_' . $option->getId())->getValue();
-
+                $option = $item->getProduct()->getOptionById($optionId);
+                if ($option) {
                     $optionStr .= $option->getTitle() . ':';
-
                     $quoteItemOption = $item->getOptionByCode('option_' . $option->getId());
-                    $group = $option->groupFactory(
-                        $option->getType()
-                    )->setOption(
-                        $option
-                    )->setQuoteItemOption(
-                        $quoteItemOption
-                    );
+                    $group = $option->groupFactory($option->getType())
+                        ->setOption($option)
+                        ->setQuoteItemOption($quoteItemOption);
 
                     $optionStr .= $group->getEditableOptionValue($quoteItemOption->getValue());
                     $optionStr .= "\n";
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/Items.php
index 843964182bc..2a6765fe2e8 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/Items.php
@@ -24,7 +24,7 @@
 namespace Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create;
 
 /**
- * Adminhtml creditmemo items grid
+ * Adminhtml credit memo items grid
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
@@ -38,24 +38,24 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      *
      * @var \Magento\Sales\Helper\Data
      */
-    protected $_salesData = null;
+    protected $_salesData;
 
     /**
      * @param \Magento\Backend\Block\Template\Context $context
-     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Sales\Helper\Data $salesData
      * @param array $data
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
-        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Registry $registry,
         \Magento\Sales\Helper\Data $salesData,
         array $data = array()
     ) {
         $this->_salesData = $salesData;
-        parent::__construct($context, $productFactory, $registry, $data);
+        parent::__construct($context, $stockItemService, $registry, $data);
     }
 
     /**
@@ -139,7 +139,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
     }
 
     /**
-     * Retrieve order totalbar block data
+     * Retrieve order total bar block data
      *
      * @return array
      */
@@ -147,17 +147,17 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
     {
         $this->setPriceDataObject($this->getOrder());
 
-        $totalbarData = array();
-        $totalbarData[] = array(__('Paid Amount'), $this->displayPriceAttribute('total_invoiced'), false);
-        $totalbarData[] = array(__('Refund Amount'), $this->displayPriceAttribute('total_refunded'), false);
-        $totalbarData[] = array(__('Shipping Amount'), $this->displayPriceAttribute('shipping_invoiced'), false);
-        $totalbarData[] = array(__('Shipping Refund'), $this->displayPriceAttribute('shipping_refunded'), false);
-        $totalbarData[] = array(__('Order Grand Total'), $this->displayPriceAttribute('grand_total'), true);
-        return $totalbarData;
+        $totalBarData = array();
+        $totalBarData[] = array(__('Paid Amount'), $this->displayPriceAttribute('total_invoiced'), false);
+        $totalBarData[] = array(__('Refund Amount'), $this->displayPriceAttribute('total_refunded'), false);
+        $totalBarData[] = array(__('Shipping Amount'), $this->displayPriceAttribute('shipping_invoiced'), false);
+        $totalBarData[] = array(__('Shipping Refund'), $this->displayPriceAttribute('shipping_refunded'), false);
+        $totalBarData[] = array(__('Order Grand Total'), $this->displayPriceAttribute('grand_total'), true);
+        return $totalBarData;
     }
 
     /**
-     * Retrieve creditmemo model instance
+     * Retrieve credit memo model instance
      *
      * @return \Magento\Sales\Model\Order\Creditmemo
      */
@@ -238,21 +238,23 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
             if ($this->_canReturnToStock) {
                 $canReturnToStock = false;
                 foreach ($this->getCreditmemo()->getAllItems() as $item) {
-                    $product = $this->_productFactory->create()->load($item->getOrderItem()->getProductId());
-                    if ($product->getId() && $product->getStockItem()->getManageStock()) {
-                        $item->setCanReturnToStock($canReturnToStock = true);
+                    $productId = $item->getOrderItem()->getProductId();
+                    if ($productId && $this->stockItemService->getManageStock($productId)) {
+                        $canReturnToStock = true;
+                        $item->setCanReturnToStock($canReturnToStock);
                     } else {
                         $item->setCanReturnToStock(false);
                     }
                 }
-                $this->getCreditmemo()->getOrder()->setCanReturnToStock($this->_canReturnToStock = $canReturnToStock);
+                $this->_canReturnToStock = $canReturnToStock;
+                $this->getCreditmemo()->getOrder()->setCanReturnToStock($this->_canReturnToStock);
             }
         }
         return $this->_canReturnToStock;
     }
 
     /**
-     * Check allow to send new creditmemo email
+     * Check allow to send new credit memo email
      *
      * @return bool
      */
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/View/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/View/Items.php
index 18eee6b475b..a685c0dbd2d 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/View/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Creditmemo/View/Items.php
@@ -25,8 +25,6 @@ namespace Magento\Sales\Block\Adminhtml\Order\Creditmemo\View;
 
 /**
  * Adminhtml sales item renderer
- *
- * @author     Magento Core Team <core@magentocommerce.com>
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/Create/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/Create/Items.php
index 3ec26424e0e..5cecff1a009 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/Create/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/Create/Items.php
@@ -40,24 +40,24 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      *
      * @var \Magento\Sales\Helper\Data
      */
-    protected $_salesData = null;
+    protected $_salesData;
 
     /**
      * @param \Magento\Backend\Block\Template\Context $context
-     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Sales\Helper\Data $salesData
      * @param array $data
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
-        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Registry $registry,
         \Magento\Sales\Helper\Data $salesData,
         array $data = array()
     ) {
         $this->_salesData = $salesData;
-        parent::__construct($context, $productFactory, $registry, $data);
+        parent::__construct($context, $stockItemService, $registry, $data);
     }
 
     /**
@@ -74,14 +74,14 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
             array('class' => 'update-button', 'label' => __('Update Qty\'s'), 'onclick' => $onclick)
         );
         $this->_disableSubmitButton = true;
-        $_submitButtonClass = ' disabled';
+        $submitButtonClass = ' disabled';
         foreach ($this->getInvoice()->getAllItems() as $item) {
             /**
              * @see bug #14839
              */
             if ($item->getQty()/* || $this->getSource()->getData('base_grand_total')*/) {
                 $this->_disableSubmitButton = false;
-                $_submitButtonClass = '';
+                $submitButtonClass = '';
                 break;
             }
         }
@@ -95,7 +95,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
             'Magento\Backend\Block\Widget\Button',
             array(
                 'label' => $_submitLabel,
-                'class' => 'save submit-button primary' . $_submitButtonClass,
+                'class' => 'save submit-button primary' . $submitButtonClass,
                 'onclick' => 'disableElements(\'submit-button\');$(\'edit_form\').submit()',
                 'disabled' => $this->_disableSubmitButton
             )
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View/Items.php
index 5bdc307678a..4c691e3b7ef 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View/Items.php
@@ -25,8 +25,6 @@ namespace Magento\Sales\Block\Adminhtml\Order\Invoice\View;
 
 /**
  * Adminhtml sales item renderer
- *
- * @author     Magento Core Team <core@magentocommerce.com>
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
index ed4dbdf541c..50d72a5b4b5 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
@@ -27,8 +27,6 @@ use Magento\Sales\Model\Resource\Order\Item\Collection;
 
 /**
  * Adminhtml order items grid
- *
- * @author      Magento Core Team <core@magentocommerce.com>
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
index 27b502c28a3..a8fa90a493a 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
@@ -27,7 +27,6 @@ use Magento\Sales\Model\Order\Item;
 
 /**
  * Adminhtml sales order item renderer
- *
  */
 class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
@@ -45,9 +44,16 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      */
     protected $_checkoutHelper;
 
+    /**
+     * Giftmessage object
+     *
+     * @var \Magento\GiftMessage\Model\Message
+     */
+    protected $_giftMessage = array();
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
-     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\GiftMessage\Helper\Message $messageHelper
      * @param \Magento\Checkout\Helper\Data $checkoutHelper
@@ -55,7 +61,7 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
-        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Registry $registry,
         \Magento\GiftMessage\Helper\Message $messageHelper,
         \Magento\Checkout\Helper\Data $checkoutHelper,
@@ -63,7 +69,7 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
     ) {
         $this->_checkoutHelper = $checkoutHelper;
         $this->_messageHelper = $messageHelper;
-        parent::__construct($context, $productFactory, $registry, $data);
+        parent::__construct($context, $stockItemService, $registry, $data);
     }
 
     /**
@@ -107,13 +113,6 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
         return $this->getRequest()->getParam('reload') != 1;
     }
 
-    /**
-     * Giftmessage object
-     *
-     * @var \Magento\GiftMessage\Model\Message
-     */
-    protected $_giftMessage = array();
-
     /**
      * Retrieve default value for giftmessage sender
      *
@@ -146,14 +145,14 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
         if ($this->getItem()->getOrder()) {
             if ($this->getItem()->getOrder()->getShippingAddress()) {
                 return $this->getItem()->getOrder()->getShippingAddress()->getName();
-            } else if ($this->getItem()->getOrder()->getBillingAddress()) {
+            } elseif ($this->getItem()->getOrder()->getBillingAddress()) {
                 return $this->getItem()->getOrder()->getBillingAddress()->getName();
             }
         }
 
         if ($this->getItem()->getShippingAddress()) {
             return $this->getItem()->getShippingAddress()->getName();
-        } else if ($this->getItem()->getBillingAddress()) {
+        } elseif ($this->getItem()->getBillingAddress()) {
             return $this->getItem()->getBillingAddress()->getName();
         }
 
diff --git a/app/code/Magento/Sales/Block/Reorder/Sidebar.php b/app/code/Magento/Sales/Block/Reorder/Sidebar.php
index aec15184104..59f5f8f9699 100644
--- a/app/code/Magento/Sales/Block/Reorder/Sidebar.php
+++ b/app/code/Magento/Sales/Block/Reorder/Sidebar.php
@@ -23,14 +23,21 @@
  */
 namespace Magento\Sales\Block\Reorder;
 
+use Magento\Framework\View\Block\IdentityInterface;
+
 /**
  * Sales order view block
  *
  * @method Sidebar setOrders(\Magento\Sales\Model\Resource\Order\Collection $ordersCollection)
  * @method \Magento\Sales\Model\Resource\Order\Collection|null getOrders()
  */
-class Sidebar extends \Magento\Framework\View\Element\Template implements \Magento\Framework\View\Block\IdentityInterface
+class Sidebar extends \Magento\Framework\View\Element\Template implements IdentityInterface
 {
+    /**
+     * Limit of orders in side bar
+     */
+    const SIDEBAR_ORDER_LIMIT = 5;
+
     /**
      * @var string
      */
@@ -56,12 +63,18 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
      */
     protected $httpContext;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Sales\Model\Resource\Order\CollectionFactory $orderCollectionFactory
      * @param \Magento\Sales\Model\Order\Config $orderConfig
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Framework\App\Http\Context $httpContext
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -70,12 +83,14 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
         \Magento\Sales\Model\Order\Config $orderConfig,
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Framework\App\Http\Context $httpContext,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_orderCollectionFactory = $orderCollectionFactory;
         $this->_orderConfig = $orderConfig;
         $this->_customerSession = $customerSession;
         $this->httpContext = $httpContext;
+        $this->stockItemService = $stockItemService;
         parent::__construct($context, $data);
         $this->_isScopePrivate = true;
     }
@@ -100,25 +115,14 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
      */
     public function initOrders()
     {
-        $customerId = $this->getCustomerId()
-            ? $this->getCustomerId()
-            : $this->_customerSession->getCustomerId();
-
-        $orders = $this->_orderCollectionFactory->create()->addAttributeToFilter(
-            'customer_id',
-            $customerId
-        )->addAttributeToFilter(
-            'status',
-            array('in' => $this->_orderConfig->getVisibleOnFrontStatuses())
-        )->addAttributeToSort(
-            'created_at',
-            'desc'
-        )->setPage(
-            1,
-            1
-        );
-        //TODO: add filter by current website
+        $customerId = $this->getCustomerId() ? $this->getCustomerId() : $this->_customerSession->getCustomerId();
 
+        $orders = $this->_orderCollectionFactory->create()
+            ->addAttributeToFilter('customer_id', $customerId)
+            ->addAttributeToFilter('status', array('in' => $this->_orderConfig->getVisibleOnFrontStatuses()))
+            ->addAttributeToSort('created_at', 'desc')
+            ->setPage(1, 1);
+        //TODO: add filter by current website
         $this->setOrders($orders);
     }
 
@@ -131,7 +135,7 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
     {
         $items = array();
         $order = $this->getLastOrder();
-        $limit = 5;
+        $limit = self::SIDEBAR_ORDER_LIMIT;
 
         if ($order) {
             $website = $this->_storeManager->getStore()->getWebsiteId();
@@ -154,7 +158,7 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
     public function isItemAvailableForReorder(\Magento\Sales\Model\Order\Item $orderItem)
     {
         if ($orderItem->getProduct()) {
-            return $orderItem->getProduct()->getStockItem()->getIsInStock();
+            return $this->stockItemService->getIsInStock($orderItem->getProduct()->getId());
         }
         return false;
     }
@@ -177,12 +181,12 @@ class Sidebar extends \Magento\Framework\View\Element\Template implements \Magen
      */
     public function getLastOrder()
     {
-        if ($this->getOrders()) {
-            foreach ($this->getOrders() as $order) {
-                return $order;
-            }
+        if (!$this->getOrders()) {
+            return false;
+        }
+        foreach ($this->getOrders() as $order) {
+            return $order;
         }
-        return false;
     }
 
     /**
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order.php b/app/code/Magento/Sales/Controller/Adminhtml/Order.php
index da85ffbc0b0..a1333118757 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order.php
@@ -346,7 +346,7 @@ class Order extends \Magento\Backend\App\Action
             }
             if (is_array($response)) {
                 $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
-                $this->getResponse()->setBody($response);
+                $this->getResponse()->representJson($response);
             }
         }
     }
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo.php
index ba04710ceba..407c9c46c29 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo.php
@@ -274,17 +274,21 @@ class Creditmemo extends \Magento\Sales\Controller\Adminhtml\Creditmemo\Abstract
     public function updateQtyAction()
     {
         try {
-            $creditmemo = $this->_initCreditmemo(true);
+            $this->_initCreditmemo(true);
             $this->_view->loadLayout();
             $response = $this->_view->getLayout()->getBlock('order_items')->toHtml();
         } catch (\Magento\Framework\Model\Exception $e) {
             $response = array('error' => true, 'message' => $e->getMessage());
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         } catch (\Exception $e) {
             $response = array('error' => true, 'message' => __('Cannot update the item\'s quantity.'));
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         }
-        $this->getResponse()->setBody($response);
+        if (is_array($response)) {
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
+        }
     }
 
     /**
@@ -431,12 +435,16 @@ class Creditmemo extends \Magento\Sales\Controller\Adminhtml\Creditmemo\Abstract
             $response = $this->_view->getLayout()->getBlock('creditmemo_comments')->toHtml();
         } catch (\Magento\Framework\Model\Exception $e) {
             $response = array('error' => true, 'message' => $e->getMessage());
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         } catch (\Exception $e) {
             $response = array('error' => true, 'message' => __('Cannot add new comment.'));
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         }
-        $this->getResponse()->setBody($response);
+        if (is_array($response)) {
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
+        }
     }
 
     /**
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice.php
index fe3cbe0dffd..ac9deb269c5 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice.php
@@ -257,12 +257,16 @@ class Invoice extends \Magento\Sales\Controller\Adminhtml\Invoice\AbstractInvoic
             $response = $this->_view->getLayout()->getBlock('order_items')->toHtml();
         } catch (Exception $e) {
             $response = array('error' => true, 'message' => $e->getMessage());
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         } catch (\Exception $e) {
             $response = array('error' => true, 'message' => __('Cannot update item quantity.'));
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         }
-        $this->getResponse()->setBody($response);
+        if (is_array($response)) {
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
+        }
     }
 
     /**
@@ -467,12 +471,16 @@ class Invoice extends \Magento\Sales\Controller\Adminhtml\Invoice\AbstractInvoic
             $response = $this->_view->getLayout()->getBlock('invoice_comments')->toHtml();
         } catch (Exception $e) {
             $response = array('error' => true, 'message' => $e->getMessage());
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         } catch (\Exception $e) {
             $response = array('error' => true, 'message' => __('Cannot add new comment.'));
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         }
-        $this->getResponse()->setBody($response);
+        if (is_array($response)) {
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
+        }
     }
 
     /**
diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php
index 4ce2ec237a0..f2071482109 100644
--- a/app/code/Magento/Sales/Model/AdminOrder/Create.php
+++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php
@@ -187,6 +187,11 @@ class Create extends \Magento\Framework\Object implements \Magento\Checkout\Mode
      */
     protected $_scopeConfig;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\ObjectManager $objectManager
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
@@ -205,6 +210,7 @@ class Create extends \Magento\Framework\Object implements \Magento\Checkout\Mode
      * @param \Magento\Customer\Helper\Data $customerHelper
      * @param CustomerGroupServiceInterface $customerGroupService
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      */
     public function __construct(
@@ -225,6 +231,7 @@ class Create extends \Magento\Framework\Object implements \Magento\Checkout\Mode
         \Magento\Customer\Helper\Data $customerHelper,
         CustomerGroupServiceInterface $customerGroupService,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_objectManager = $objectManager;
@@ -244,6 +251,7 @@ class Create extends \Magento\Framework\Object implements \Magento\Checkout\Mode
         $this->_customerHelper = $customerHelper;
         $this->_customerGroupService = $customerGroupService;
         $this->_scopeConfig = $scopeConfig;
+        $this->stockItemService = $stockItemService;
         parent::__construct($data);
     }
 
@@ -979,12 +987,11 @@ class Create extends \Magento\Framework\Object implements \Magento\Checkout\Mode
                     }
 
                     if ($item) {
-                        if ($item->getProduct()->getStockItem()) {
-                            if (!$item->getProduct()->getStockItem()->getIsQtyDecimal()) {
-                                $itemQty = (int)$itemQty;
-                            } else {
-                                $item->setIsQtyDecimal(1);
-                            }
+                        $stockItemDo = $this->stockItemService->getStockItem($item->getProduct()->getId());
+                        if ($stockItemDo->getStockId() && !$stockItemDo->getIsQtyDecimal()) {
+                            $itemQty = (int)$itemQty;
+                        } else {
+                            $item->setIsQtyDecimal(1);
                         }
                         $itemQty = $itemQty > 0 ? $itemQty : 1;
                         if (isset($info['custom_price'])) {
diff --git a/app/code/Magento/Sales/Model/AdminOrder/Product/Quote/Initializer.php b/app/code/Magento/Sales/Model/AdminOrder/Product/Quote/Initializer.php
index 87c042146ab..f143e968898 100644
--- a/app/code/Magento/Sales/Model/AdminOrder/Product/Quote/Initializer.php
+++ b/app/code/Magento/Sales/Model/AdminOrder/Product/Quote/Initializer.php
@@ -32,6 +32,20 @@ namespace Magento\Sales\Model\AdminOrder\Product\Quote;
 
 class Initializer
 {
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
+    /**
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+     */
+    public function __construct(
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
+    ) {
+        $this->stockItemService = $stockItemService;
+    }
+
     /**
      * @param \Magento\Sales\Model\Quote $quote
      * @param \Magento\Catalog\Model\Product $product
@@ -43,8 +57,9 @@ class Initializer
         \Magento\Catalog\Model\Product $product,
         \Magento\Framework\Object $config
     ) {
-        $stockItem = $product->getStockItem();
-        if ($stockItem && $stockItem->getIsQtyDecimal()) {
+        /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDo */
+        $stockItemDo = $this->stockItemService->getStockItem($product->getId());
+        if ($stockItemDo->getStockId() && $stockItemDo->getIsQtyDecimal()) {
             $product->setIsQtyDecimal(1);
         } else {
             $config->setQty((int)$config->getQty());
diff --git a/app/code/Magento/Sales/Model/Convert/Quote.php b/app/code/Magento/Sales/Model/Convert/Quote.php
index c91e3d058e9..2ab28baada5 100644
--- a/app/code/Magento/Sales/Model/Convert/Quote.php
+++ b/app/code/Magento/Sales/Model/Convert/Quote.php
@@ -22,11 +22,11 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
+namespace Magento\Sales\Model\Convert;
+
 /**
  * Quote data convert model
  */
-namespace Magento\Sales\Model\Convert;
-
 class Quote extends \Magento\Framework\Object
 {
     /**
@@ -34,7 +34,7 @@ class Quote extends \Magento\Framework\Object
      *
      * @var \Magento\Framework\Event\ManagerInterface
      */
-    protected $_eventManager = null;
+    protected $_eventManager;
 
     /**
      * @var \Magento\Sales\Model\OrderFactory
@@ -101,18 +101,11 @@ class Quote extends \Magento\Framework\Object
             $order = $this->_orderFactory->create();
         }
         /* @var $order \Magento\Sales\Model\Order */
-
-        $order->setIncrementId(
-            $quote->getReservedOrderId()
-        )->setStoreId(
-            $quote->getStoreId()
-        )->setQuoteId(
-            $quote->getId()
-        )->setQuote(
-            $quote
-        )->setCustomer(
-            $quote->getCustomer()
-        );
+        $order->setIncrementId($quote->getReservedOrderId())
+            ->setStoreId($quote->getStoreId())
+            ->setQuoteId($quote->getId())
+            ->setQuote($quote)
+            ->setCustomer($quote->getCustomer());
 
         $this->_objectCopyService->copyFieldsetToTarget('sales_convert_quote', 'to_order', $quote, $order);
         $this->_eventManager->dispatch('sales_convert_quote_to_order', array('order' => $order, 'quote' => $quote));
@@ -149,15 +142,11 @@ class Quote extends \Magento\Framework\Object
      */
     public function addressToOrderAddress(\Magento\Sales\Model\Quote\Address $address)
     {
-        $orderAddress = $this->_orderAddressFactory->create()->setStoreId(
-            $address->getStoreId()
-        )->setAddressType(
-            $address->getAddressType()
-        )->setCustomerId(
-            $address->getCustomerId()
-        )->setCustomerAddressId(
-            $address->getCustomerAddressId()
-        );
+        $orderAddress = $this->_orderAddressFactory->create()
+            ->setStoreId($address->getStoreId())
+            ->setAddressType($address->getAddressType())
+            ->setCustomerId($address->getCustomerId())
+            ->setCustomerAddressId($address->getCustomerAddressId());
 
         $this->_objectCopyService->copyFieldsetToTarget(
             'sales_convert_quote_address',
@@ -208,23 +197,15 @@ class Quote extends \Magento\Framework\Object
      */
     public function itemToOrderItem(\Magento\Sales\Model\Quote\Item\AbstractItem $item)
     {
-        $orderItem = $this->_orderItemFactory->create()->setStoreId(
-            $item->getStoreId()
-        )->setQuoteItemId(
-            $item->getId()
-        )->setQuoteParentItemId(
-            $item->getParentItemId()
-        )->setProductId(
-            $item->getProductId()
-        )->setProductType(
-            $item->getProductType()
-        )->setQtyBackordered(
-            $item->getBackorders()
-        )->setProduct(
-            $item->getProduct()
-        )->setBaseOriginalPrice(
-            $item->getBaseOriginalPrice()
-        );
+        $orderItem = $this->_orderItemFactory->create()
+            ->setStoreId($item->getStoreId())
+            ->setQuoteItemId($item->getId())
+            ->setQuoteParentItemId($item->getParentItemId())
+            ->setProductId($item->getProductId())
+            ->setProductType($item->getProductType())
+            ->setQtyBackordered($item->getBackorders())
+            ->setProduct($item->getProduct())
+            ->setBaseOriginalPrice($item->getBaseOriginalPrice());
 
         $options = $item->getProductOrderOptions();
         if (!$options) {
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php
index 78eea184faa..efb987cf10c 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php
@@ -407,7 +407,7 @@ class Creditmemo extends \Magento\Sales\Model\AbstractModel
     }
 
     /**
-     * @return array
+     * @return \Magento\Sales\Model\Order\Creditmemo\Item[]
      */
     public function getAllItems()
     {
diff --git a/app/code/Magento/Sales/Model/Quote.php b/app/code/Magento/Sales/Model/Quote.php
index 72808e04807..d30e2ff1db9 100644
--- a/app/code/Magento/Sales/Model/Quote.php
+++ b/app/code/Magento/Sales/Model/Quote.php
@@ -299,6 +299,11 @@ class Quote extends \Magento\Framework\Model\AbstractModel
      */
     protected $_addressConverter;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -307,20 +312,21 @@ class Quote extends \Magento\Framework\Model\AbstractModel
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
-     * @param \Magento\Sales\Model\Quote\AddressFactory $quoteAddressFactory
+     * @param Quote\AddressFactory $quoteAddressFactory
      * @param \Magento\Customer\Model\CustomerFactory $customerFactory
      * @param CustomerGroupServiceInterface $customerGroupService
-     * @param \Magento\Sales\Model\Resource\Quote\Item\CollectionFactory $quoteItemCollectionFactory
-     * @param \Magento\Sales\Model\Quote\ItemFactory $quoteItemFactory
+     * @param Resource\Quote\Item\CollectionFactory $quoteItemCollectionFactory
+     * @param Quote\ItemFactory $quoteItemFactory
      * @param \Magento\Framework\Message\Factory $messageFactory
-     * @param \Magento\Sales\Model\Status\ListFactory $statusListFactory
+     * @param Status\ListFactory $statusListFactory
      * @param \Magento\Catalog\Model\ProductFactory $productFactory
-     * @param \Magento\Sales\Model\Quote\PaymentFactory $quotePaymentFactory
-     * @param \Magento\Sales\Model\Resource\Quote\Payment\CollectionFactory $quotePaymentCollectionFactory
+     * @param Quote\PaymentFactory $quotePaymentFactory
+     * @param Resource\Quote\Payment\CollectionFactory $quotePaymentCollectionFactory
      * @param \Magento\Framework\Object\Copy $objectCopyService
      * @param \Magento\Customer\Model\Converter $converter
      * @param \Magento\Customer\Service\V1\CustomerAddressServiceInterface $addressService
      * @param \Magento\Customer\Model\Address\Converter $addressConverter
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Model\Resource\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\Db $resourceCollection
      * @param array $data
@@ -347,6 +353,7 @@ class Quote extends \Magento\Framework\Model\AbstractModel
         \Magento\Customer\Model\Converter $converter,
         \Magento\Customer\Service\V1\CustomerAddressServiceInterface $addressService,
         \Magento\Customer\Model\Address\Converter $addressConverter,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Model\Resource\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\Db $resourceCollection = null,
         array $data = array()
@@ -370,6 +377,7 @@ class Quote extends \Magento\Framework\Model\AbstractModel
         $this->_converter = $converter;
         $this->_addressService = $addressService;
         $this->_addressConverter = $addressConverter;
+        $this->stockItemService = $stockItemService;
         parent::__construct($context, $registry, $resource, $resourceCollection, $data);
     }
 
@@ -725,7 +733,7 @@ class Quote extends \Magento\Framework\Model\AbstractModel
     /**
      * Get Data Object addresses of the customer
      *
-     * TODO: Refactor to use addressDataObject property is used insead of customer model MAGETWO-19930
+     * TODO: Refactor to use addressDataObject property is used instead of customer model MAGETWO-19930
      *
      * @return AddressDataObject[]
      */
@@ -1111,7 +1119,9 @@ class Quote extends \Magento\Framework\Model\AbstractModel
     public function hasItemsWithDecimalQty()
     {
         foreach ($this->getAllItems() as $item) {
-            if ($item->getProduct()->getStockItem() && $item->getProduct()->getStockItem()->getIsQtyDecimal()) {
+            /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDo */
+            $stockItemDo = $this->stockItemService->getStockItem($item->getProduct()->getId());
+            if ($stockItemDo->getStockId() && $stockItemDo->getIsQtyDecimal()) {
                 return true;
             }
         }
@@ -1279,7 +1289,9 @@ class Quote extends \Magento\Framework\Model\AbstractModel
             $request = new \Magento\Framework\Object(array('qty' => $request));
         }
         if (!$request instanceof \Magento\Framework\Object) {
-            throw new \Magento\Framework\Model\Exception(__('We found an invalid request for adding product to quote.'));
+            throw new \Magento\Framework\Model\Exception(
+                __('We found an invalid request for adding product to quote.')
+            );
         }
 
         $cartCandidates = $product->getTypeInstance()->prepareForCartAdvanced($request, $product, $processMode);
@@ -1427,7 +1439,9 @@ class Quote extends \Magento\Framework\Model\AbstractModel
     {
         $item = $this->getItemById($itemId);
         if (!$item) {
-            throw new \Magento\Framework\Model\Exception(__('This is the wrong quote item id to update configuration.'));
+            throw new \Magento\Framework\Model\Exception(
+                __('This is the wrong quote item id to update configuration.')
+            );
         }
         $productId = $item->getProduct()->getId();
 
@@ -1673,18 +1687,18 @@ class Quote extends \Magento\Framework\Model\AbstractModel
 
             $address->collectTotals();
 
-            $this->setSubtotal((double)$this->getSubtotal() + $address->getSubtotal());
-            $this->setBaseSubtotal((double)$this->getBaseSubtotal() + $address->getBaseSubtotal());
+            $this->setSubtotal((float)$this->getSubtotal() + $address->getSubtotal());
+            $this->setBaseSubtotal((float)$this->getBaseSubtotal() + $address->getBaseSubtotal());
 
             $this->setSubtotalWithDiscount(
-                (double)$this->getSubtotalWithDiscount() + $address->getSubtotalWithDiscount()
+                (float)$this->getSubtotalWithDiscount() + $address->getSubtotalWithDiscount()
             );
             $this->setBaseSubtotalWithDiscount(
-                (double)$this->getBaseSubtotalWithDiscount() + $address->getBaseSubtotalWithDiscount()
+                (float)$this->getBaseSubtotalWithDiscount() + $address->getBaseSubtotalWithDiscount()
             );
 
-            $this->setGrandTotal((double)$this->getGrandTotal() + $address->getGrandTotal());
-            $this->setBaseGrandTotal((double)$this->getBaseGrandTotal() + $address->getBaseGrandTotal());
+            $this->setGrandTotal((float)$this->getGrandTotal() + $address->getGrandTotal());
+            $this->setBaseGrandTotal((float)$this->getBaseGrandTotal() + $address->getBaseGrandTotal());
         }
 
         $this->_salesData->checkQuoteAmount($this, $this->getGrandTotal());
@@ -1731,7 +1745,7 @@ class Quote extends \Magento\Framework\Model\AbstractModel
                 $this->setVirtualItemsQty($this->getVirtualItemsQty() + $item->getQty());
             }
             $this->setItemsCount($this->getItemsCount() + 1);
-            $this->setItemsQty((double)$this->getItemsQty() + $item->getQty());
+            $this->setItemsQty((float)$this->getItemsQty() + $item->getQty());
         }
 
         return $this;
diff --git a/app/code/Magento/Sales/Model/Quote/Item.php b/app/code/Magento/Sales/Model/Quote/Item.php
index 557efea73a5..2d365304e74 100644
--- a/app/code/Magento/Sales/Model/Quote/Item.php
+++ b/app/code/Magento/Sales/Model/Quote/Item.php
@@ -48,8 +48,6 @@ namespace Magento\Sales\Model\Quote;
  * @method \Magento\Sales\Model\Quote\Item setName(string $value)
  * @method string getDescription()
  * @method \Magento\Sales\Model\Quote\Item setDescription(string $value)
- * @method string getAppliedRuleIds()
- * @method \Magento\Sales\Model\Quote\Item setAppliedRuleIds(string $value)
  * @method string getAdditionalData()
  * @method \Magento\Sales\Model\Quote\Item setAdditionalData(string $value)
  * @method int getFreeShipping()
@@ -63,19 +61,11 @@ namespace Magento\Sales\Model\Quote;
  * @method float getBasePrice()
  * @method \Magento\Sales\Model\Quote\Item setBasePrice(float $value)
  * @method float getCustomPrice()
- * @method float getDiscountPercent()
- * @method \Magento\Sales\Model\Quote\Item setDiscountPercent(float $value)
- * @method float getDiscountAmount()
- * @method \Magento\Sales\Model\Quote\Item setDiscountAmount(float $value)
- * @method float getBaseDiscountAmount()
- * @method \Magento\Sales\Model\Quote\Item setBaseDiscountAmount(float $value)
  * @method float getTaxPercent()
  * @method \Magento\Sales\Model\Quote\Item setTaxPercent(float $value)
  * @method \Magento\Sales\Model\Quote\Item setTaxAmount(float $value)
  * @method \Magento\Sales\Model\Quote\Item setBaseTaxAmount(float $value)
- * @method float getRowTotal()
  * @method \Magento\Sales\Model\Quote\Item setRowTotal(float $value)
- * @method float getBaseRowTotal()
  * @method \Magento\Sales\Model\Quote\Item setBaseRowTotal(float $value)
  * @method float getRowTotalWithDiscount()
  * @method \Magento\Sales\Model\Quote\Item setRowTotalWithDiscount(float $value)
@@ -92,11 +82,9 @@ namespace Magento\Sales\Model\Quote;
  * @method \Magento\Sales\Model\Quote\Item setRedirectUrl(string $value)
  * @method float getBaseCost()
  * @method \Magento\Sales\Model\Quote\Item setBaseCost(float $value)
- * @method float getPriceInclTax()
  * @method \Magento\Sales\Model\Quote\Item setPriceInclTax(float $value)
  * @method float getBasePriceInclTax()
  * @method \Magento\Sales\Model\Quote\Item setBasePriceInclTax(float $value)
- * @method float getRowTotalInclTax()
  * @method \Magento\Sales\Model\Quote\Item setRowTotalInclTax(float $value)
  * @method float getBaseRowTotalInclTax()
  * @method \Magento\Sales\Model\Quote\Item setBaseRowTotalInclTax(float $value)
@@ -178,7 +166,7 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
      * Flag stating that options were successfully saved
      *
      */
-    protected $_flagOptionsSaved = null;
+    protected $_flagOptionsSaved;
 
     /**
      * Array of errors associated with this quote item
@@ -202,6 +190,11 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
      */
     protected $_compareHelper;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -210,6 +203,7 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
      * @param \Magento\Framework\Locale\FormatInterface $localeFormat
      * @param Item\OptionFactory $itemOptionFactory
      * @param \Magento\Sales\Helper\Quote\Item\Compare $compareHelper
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Model\Resource\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\Db $resourceCollection
      * @param array $data
@@ -224,6 +218,7 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
         \Magento\Framework\Locale\FormatInterface $localeFormat,
         \Magento\Sales\Model\Quote\Item\OptionFactory $itemOptionFactory,
         \Magento\Sales\Helper\Quote\Item\Compare $compareHelper,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Model\Resource\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\Db $resourceCollection = null,
         array $data = array()
@@ -232,6 +227,7 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
         $this->_localeFormat = $localeFormat;
         $this->_itemOptionFactory = $itemOptionFactory;
         $this->_compareHelper = $compareHelper;
+        $this->stockItemService = $stockItemService;
         parent::__construct($context, $registry, $productFactory, $resource, $resourceCollection, $data);
     }
 
@@ -375,7 +371,8 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
             $qtyOptions = array();
             foreach ($this->getOptions() as $option) {
                 /** @var $option \Magento\Sales\Model\Quote\Item\Option */
-                if (is_object($option->getProduct()) && $option->getProduct()->getId() != $this->getProduct()->getId()
+                if (is_object($option->getProduct())
+                    && $option->getProduct()->getId() != $this->getProduct()->getId()
                 ) {
                     $productIds[$option->getProduct()->getId()] = $option->getProduct()->getId();
                 }
@@ -417,27 +414,19 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
             $product->setStoreId($this->getQuote()->getStoreId());
             $product->setCustomerGroupId($this->getQuote()->getCustomerGroupId());
         }
-        $this->setData(
-            'product',
-            $product
-        )->setProductId(
-            $product->getId()
-        )->setProductType(
-            $product->getTypeId()
-        )->setSku(
-            $this->getProduct()->getSku()
-        )->setName(
-            $product->getName()
-        )->setWeight(
-            $this->getProduct()->getWeight()
-        )->setTaxClassId(
-            $product->getTaxClassId()
-        )->setBaseCost(
-            $product->getCost()
-        );
-
-        if ($product->getStockItem()) {
-            $this->setIsQtyDecimal($product->getStockItem()->getIsQtyDecimal());
+        $this->setData('product', $product)
+            ->setProductId($product->getId())
+            ->setProductType($product->getTypeId())
+            ->setSku($this->getProduct()->getSku())
+            ->setName($product->getName())
+            ->setWeight($this->getProduct()->getWeight())
+            ->setTaxClassId($product->getTaxClassId())
+            ->setBaseCost($product->getCost());
+
+        /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDo */
+        $stockItemDo = $this->stockItemService->getStockItem($product->getId());
+        if ($stockItemDo->getStockId()) {
+            $this->setIsQtyDecimal($stockItemDo->getIsQtyDecimal());
         }
 
         $this->_eventManager->dispatch(
@@ -544,7 +533,7 @@ class Item extends \Magento\Sales\Model\Quote\Item\AbstractItem
     /**
      * Return real product type of item
      *
-     * @return unknown
+     * @return string
      */
     public function getRealProductType()
     {
diff --git a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Quote/Edit/Tab/Main.php b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Quote/Edit/Tab/Main.php
index 509ca904267..31e5e069561 100644
--- a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Quote/Edit/Tab/Main.php
+++ b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Quote/Edit/Tab/Main.php
@@ -242,7 +242,10 @@ class Main extends \Magento\Backend\Block\Widget\Form\Generic implements \Magent
         $fieldset->addField(
             'uses_per_customer',
             'text',
-            array('name' => 'uses_per_customer', 'label' => __('Uses per Customer'))
+            array('name' => 'uses_per_customer',
+                  'label' => __('Uses per Customer'),
+                  'note' => __('Usage limit enforced for logged in customers only.')
+            )
         );
 
         $dateFormat = $this->_localeDate->getDateFormat(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::FORMAT_TYPE_SHORT);
diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php
index 95a0e304116..71e3c20fb37 100644
--- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php
+++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php
@@ -499,7 +499,9 @@ class Quote extends \Magento\Backend\App\Action
                 $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
             }
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Shipping/Block/Adminhtml/Create/Items.php b/app/code/Magento/Shipping/Block/Adminhtml/Create/Items.php
index 47c319b91e0..e1d2b6a60c2 100644
--- a/app/code/Magento/Shipping/Block/Adminhtml/Create/Items.php
+++ b/app/code/Magento/Shipping/Block/Adminhtml/Create/Items.php
@@ -33,7 +33,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      *
      * @var \Magento\Sales\Helper\Data
      */
-    protected $_salesData = null;
+    protected $_salesData;
 
     /**
      * @var \Magento\Shipping\Model\CarrierFactory
@@ -42,7 +42,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 
     /**
      * @param \Magento\Backend\Block\Template\Context $context
-     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Sales\Helper\Data $salesData
      * @param \Magento\Shipping\Model\CarrierFactory $carrierFactory
@@ -50,7 +50,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
-        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Registry $registry,
         \Magento\Sales\Helper\Data $salesData,
         \Magento\Shipping\Model\CarrierFactory $carrierFactory,
@@ -58,7 +58,7 @@ class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
     ) {
         $this->_salesData = $salesData;
         $this->_carrierFactory = $carrierFactory;
-        parent::__construct($context, $productFactory, $registry, $data);
+        parent::__construct($context, $stockItemService, $registry, $data);
     }
 
     /**
diff --git a/app/code/Magento/Shipping/Block/Adminhtml/View/Items.php b/app/code/Magento/Shipping/Block/Adminhtml/View/Items.php
index 706e5a44c9f..127114d9e7a 100644
--- a/app/code/Magento/Shipping/Block/Adminhtml/View/Items.php
+++ b/app/code/Magento/Shipping/Block/Adminhtml/View/Items.php
@@ -22,14 +22,11 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
+namespace Magento\Shipping\Block\Adminhtml\View;
 
 /**
  * Adminhtml sales item renderer
- *
- * @author     Magento Core Team <core@magentocommerce.com>
  */
-namespace Magento\Shipping\Block\Adminhtml\View;
-
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
     /**
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment.php
index 89797072eaf..8a2967cbb17 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment.php
@@ -301,7 +301,7 @@ class Shipment extends \Magento\Sales\Controller\Adminhtml\Shipment\AbstractShip
             }
         }
         if ($isNeedCreateLabel) {
-            $this->getResponse()->setBody($responseAjax->toJson());
+            $this->getResponse()->representJson($responseAjax->toJson());
         } else {
             $this->_redirect('sales/order/view', array('order_id' => $shipment->getOrderId()));
         }
@@ -383,9 +383,12 @@ class Shipment extends \Magento\Sales\Controller\Adminhtml\Shipment\AbstractShip
             $response = array('error' => true, 'message' => __('Cannot add tracking number.'));
         }
         if (is_array($response)) {
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
         }
-        $this->getResponse()->setBody($response);
     }
 
     /**
@@ -417,9 +420,12 @@ class Shipment extends \Magento\Sales\Controller\Adminhtml\Shipment\AbstractShip
             $response = array('error' => true, 'message' => __('Cannot load track with retrieving identifier.'));
         }
         if (is_array($response)) {
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
         }
-        $this->getResponse()->setBody($response);
     }
 
     /**
@@ -448,12 +454,16 @@ class Shipment extends \Magento\Sales\Controller\Adminhtml\Shipment\AbstractShip
             $response = $this->_view->getLayout()->getBlock('shipment_comments')->toHtml();
         } catch (\Magento\Framework\Model\Exception $e) {
             $response = array('error' => true, 'message' => $e->getMessage());
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         } catch (\Exception $e) {
             $response = array('error' => true, 'message' => __('Cannot add new comment.'));
-            $response = $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response);
         }
-        $this->getResponse()->setBody($response);
+        if (is_array($response)) {
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($response)
+            );
+        } else {
+            $this->getResponse()->setBody($response);
+        }
     }
 
     /**
@@ -546,7 +556,7 @@ class Shipment extends \Magento\Sales\Controller\Adminhtml\Shipment\AbstractShip
             $response->setMessage(__('An error occurred while creating shipping label.'));
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php
index 4e49f5597e9..4b06f80ee66 100644
--- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php
+++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php
@@ -107,6 +107,11 @@ abstract class AbstractCarrierOnline extends AbstractCarrier
      */
     protected $_currencyFactory;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * Raw rate request data
      *
@@ -128,6 +133,7 @@ abstract class AbstractCarrierOnline extends AbstractCarrier
      * @param \Magento\Directory\Model\CountryFactory $countryFactory
      * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
      * @param \Magento\Directory\Helper\Data $directoryData
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param array $data
      *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -146,6 +152,7 @@ abstract class AbstractCarrierOnline extends AbstractCarrier
         \Magento\Directory\Model\CountryFactory $countryFactory,
         \Magento\Directory\Model\CurrencyFactory $currencyFactory,
         \Magento\Directory\Helper\Data $directoryData,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         array $data = array()
     ) {
         $this->_xmlElFactory = $xmlElFactory;
@@ -158,6 +165,7 @@ abstract class AbstractCarrierOnline extends AbstractCarrier
         $this->_countryFactory = $countryFactory;
         $this->_currencyFactory = $currencyFactory;
         $this->_directoryData = $directoryData;
+        $this->stockItemService = $stockItemService;
         parent::__construct($scopeConfig, $rateErrorFactory, $logAdapterFactory, $data);
     }
 
@@ -303,19 +311,23 @@ abstract class AbstractCarrierOnline extends AbstractCarrier
         $defaultErrorMsg = __('The shipping module is not available.');
         $showMethod = $this->getConfigData('showmethod');
 
+        /** @var $item \Magento\Sales\Model\Quote\Item */
         foreach ($this->getAllItems($request) as $item) {
-            if ($item->getProduct() && $item->getProduct()->getId()) {
-                $weight = $item->getProduct()->getWeight();
-                $stockItem = $item->getProduct()->getStockItem();
+            $product = $item->getProduct();
+            if ($product && $product->getId()) {
+                $weight = $product->getWeight();
+                $stockItemData = $this->stockItemService->getStockItem($product->getId());
                 $doValidation = true;
 
-                if ($stockItem->getIsQtyDecimal() && $stockItem->getIsDecimalDivided()) {
-                    if ($stockItem->getEnableQtyIncrements() && $stockItem->getQtyIncrements()) {
-                        $weight = $weight * $stockItem->getQtyIncrements();
+                if ($stockItemData->getIsQtyDecimal() && $stockItemData->getIsDecimalDivided()) {
+                    if ($this->stockItemService->getEnableQtyIncrements($product->getId())
+                        && $this->stockItemService->getQtyIncrements($product->getId())
+                    ) {
+                        $weight = $weight * $this->stockItemService->getQtyIncrements($product->getId());
                     } else {
                         $doValidation = false;
                     }
-                } elseif ($stockItem->getIsQtyDecimal() && !$stockItem->getIsDecimalDivided()) {
+                } elseif ($stockItemData->getIsQtyDecimal() && !$stockItemData->getIsDecimalDivided()) {
                     $weight = $weight * $item->getQty();
                 }
 
diff --git a/app/code/Magento/Shipping/Model/Shipping.php b/app/code/Magento/Shipping/Model/Shipping.php
index 21d3a7f0c16..1ce2afa6532 100644
--- a/app/code/Magento/Shipping/Model/Shipping.php
+++ b/app/code/Magento/Shipping/Model/Shipping.php
@@ -91,6 +91,11 @@ class Shipping implements RateCollectorInterface
      */
     protected $mathDivision;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService
+     */
+    protected $stockItemService;
+
     /**
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Shipping\Model\Config $shippingConfig
@@ -100,6 +105,7 @@ class Shipping implements RateCollectorInterface
      * @param \Magento\Shipping\Model\Shipment\RequestFactory $shipmentRequestFactory
      * @param \Magento\Directory\Model\RegionFactory $regionFactory
      * @param \Magento\Framework\Math\Division $mathDivision
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      */
     public function __construct(
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
@@ -109,7 +115,8 @@ class Shipping implements RateCollectorInterface
         \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory,
         \Magento\Shipping\Model\Shipment\RequestFactory $shipmentRequestFactory,
         \Magento\Directory\Model\RegionFactory $regionFactory,
-        \Magento\Framework\Math\Division $mathDivision
+        \Magento\Framework\Math\Division $mathDivision,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
     ) {
         $this->_scopeConfig = $scopeConfig;
         $this->_shippingConfig = $shippingConfig;
@@ -119,6 +126,7 @@ class Shipping implements RateCollectorInterface
         $this->_shipmentRequestFactory = $shipmentRequestFactory;
         $this->_regionFactory = $regionFactory;
         $this->mathDivision = $mathDivision;
+        $this->stockItemService = $stockItemService;
     }
 
     /**
@@ -328,9 +336,10 @@ class Shipping implements RateCollectorInterface
 
         $maxWeight = (double)$carrier->getConfigData('max_package_weight');
 
+        /** @var $item \Magento\Sales\Model\Quote\Item */
         foreach ($allItems as $item) {
-            if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE &&
-                $item->getProduct()->getShipmentType()
+            if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
+                && $item->getProduct()->getShipmentType()
             ) {
                 continue;
             }
@@ -344,17 +353,22 @@ class Shipping implements RateCollectorInterface
                 if (!$item->getParentItem()->getProduct()->getShipmentType()) {
                     continue;
                 }
-                $qty = $item->getIsQtyDecimal() ? $item->getParentItem()->getQty() : $item->getParentItem()->getQty() *
-                    $item->getQty();
+                $qty = $item->getIsQtyDecimal()
+                    ? $item->getParentItem()->getQty()
+                    : $item->getParentItem()->getQty() * $item->getQty();
             }
 
             $itemWeight = $item->getWeight();
-            if ($item->getIsQtyDecimal() && $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
+            if ($item->getIsQtyDecimal()
+                && $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
             ) {
-                $stockItem = $item->getProduct()->getStockItem();
-                if ($stockItem->getIsDecimalDivided()) {
-                    if ($stockItem->getEnableQtyIncrements() && $stockItem->getQtyIncrements()) {
-                        $itemWeight = $itemWeight * $stockItem->getQtyIncrements();
+                $productId = $item->getProduct()->getId();
+
+                if ($this->stockItemService->getStockItem($productId)->getIsDecimalDivided()) {
+                    if ($this->stockItemService->getEnableQtyIncrements($productId)
+                        && $this->stockItemService->getQtyIncrements($productId)
+                    ) {
+                        $itemWeight = $itemWeight * $this->stockItemService->getQtyIncrements($productId);
                         $qty = round($item->getWeight() / $itemWeight * $qty);
                         $changeQty = false;
                     } else {
@@ -380,10 +394,10 @@ class Shipping implements RateCollectorInterface
                 return array();
             }
 
-            if ($changeQty &&
-                !$item->getParentItem() &&
-                $item->getIsQtyDecimal() &&
-                $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
+            if ($changeQty
+                && !$item->getParentItem()
+                && $item->getIsQtyDecimal()
+                && $item->getProductType() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
             ) {
                 $qty = 1;
             }
diff --git a/app/code/Magento/Shipping/Model/Shipping/Labels.php b/app/code/Magento/Shipping/Model/Shipping/Labels.php
index 5383041a400..d9f8d6780f9 100644
--- a/app/code/Magento/Shipping/Model/Shipping/Labels.php
+++ b/app/code/Magento/Shipping/Model/Shipping/Labels.php
@@ -49,6 +49,7 @@ class Labels extends \Magento\Shipping\Model\Shipping
      * @param \Magento\Shipping\Model\Shipment\RequestFactory $shipmentRequestFactory
      * @param \Magento\Directory\Model\RegionFactory $regionFactory
      * @param \Magento\Framework\Math\Division $mathDivision
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Backend\Model\Auth\Session $authSession
      * @param \Magento\Shipping\Model\Shipment\Request $request
      */
@@ -61,6 +62,7 @@ class Labels extends \Magento\Shipping\Model\Shipping
         \Magento\Shipping\Model\Shipment\RequestFactory $shipmentRequestFactory,
         \Magento\Directory\Model\RegionFactory $regionFactory,
         \Magento\Framework\Math\Division $mathDivision,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Backend\Model\Auth\Session $authSession,
         \Magento\Shipping\Model\Shipment\Request $request
     ) {
@@ -74,7 +76,8 @@ class Labels extends \Magento\Shipping\Model\Shipping
             $rateResultFactory,
             $shipmentRequestFactory,
             $regionFactory,
-            $mathDivision
+            $mathDivision,
+            $stockItemService
         );
     }
 
diff --git a/app/code/Magento/Shipping/etc/module.xml b/app/code/Magento/Shipping/etc/module.xml
index e187b74e6aa..f9efc8cd202 100644
--- a/app/code/Magento/Shipping/etc/module.xml
+++ b/app/code/Magento/Shipping/etc/module.xml
@@ -42,6 +42,7 @@
             <module name="Magento_Payment"/>
             <module name="Magento_Theme"/>
             <module name="Magento_Tax"/>
+            <module name="Magento_CatalogInventory"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
index c7a08386d41..09310a3b95d 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
@@ -185,7 +185,7 @@ class Rate extends \Magento\Backend\App\Action
                 )
             );
         }
-        $this->getResponse()->setBody($responseContent);
+        $this->getResponse()->representJson($responseContent);
     }
 
     /**
@@ -321,7 +321,7 @@ class Rate extends \Magento\Backend\App\Action
                 array('success' => false, 'error_message' => __('An error occurred while deleting this tax rate.'))
             );
         }
-        $this->getResponse()->setBody($responseContent);
+        $this->getResponse()->representJson($responseContent);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
index 4286cf94cec..fa8f0be6eb3 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
@@ -74,7 +74,7 @@ class Tax extends \Magento\Backend\App\Action
                 )
             );
         }
-        $this->getResponse()->setBody($responseContent);
+        $this->getResponse()->representJson($responseContent);
     }
 
     /**
@@ -108,7 +108,7 @@ class Tax extends \Magento\Backend\App\Action
                 array('success' => false, 'error_message' => __('Something went wrong deleting this tax class.'))
             );
         }
-        $this->getResponse()->setBody($responseContent);
+        $this->getResponse()->representJson($responseContent);
     }
 
     /**
diff --git a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme.php b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme.php
index 54b2a41d9f9..5bbad678967 100644
--- a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme.php
+++ b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme.php
@@ -272,7 +272,9 @@ class Theme extends \Magento\Backend\App\Action
             $result = array('error' => true, 'message' => __('We cannot upload the CSS file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -317,7 +319,9 @@ class Theme extends \Magento\Backend\App\Action
             $result = array('error' => true, 'message' => __('We cannot upload the JS file.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
diff --git a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Wysiwyg/Files.php b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Wysiwyg/Files.php
index b3388af0069..11d2d82a2a4 100644
--- a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Wysiwyg/Files.php
+++ b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Wysiwyg/Files.php
@@ -75,7 +75,7 @@ class Files extends \Magento\Backend\App\Action
     public function treeJsonAction()
     {
         try {
-            $this->getResponse()->setBody(
+            $this->getResponse()->representJson(
                 $this->_view->getLayout()->createBlock(
                     'Magento\Theme\Block\Adminhtml\Wysiwyg\Files\Tree'
                 )->getTreeJson(
@@ -84,7 +84,9 @@ class Files extends \Magento\Backend\App\Action
             );
         } catch (\Exception $e) {
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array()));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode(array())
+            );
         }
     }
 
@@ -105,7 +107,9 @@ class Files extends \Magento\Backend\App\Action
             $result = array('error' => true, 'message' => __('Sorry, there was an unknown error.'));
             $this->_objectManager->get('Magento\Framework\Logger')->logException($e);
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -120,7 +124,9 @@ class Files extends \Magento\Backend\App\Action
             $this->_getStorage()->deleteDirectory($path);
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -139,7 +145,9 @@ class Files extends \Magento\Backend\App\Action
             $this->_getSession()->setStoragePath($this->storage->getCurrentPath());
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
@@ -156,7 +164,9 @@ class Files extends \Magento\Backend\App\Action
         } catch (\Exception $e) {
             $result = array('error' => $e->getMessage(), 'errorcode' => $e->getCode());
         }
-        $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+        $this->getResponse()->representJson(
+            $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+        );
     }
 
     /**
@@ -203,7 +213,9 @@ class Files extends \Magento\Backend\App\Action
             }
         } catch (\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
diff --git a/app/code/Magento/Theme/view/frontend/layout/print.xml b/app/code/Magento/Theme/view/frontend/layout/print.xml
index 3158fc4654c..a804c6c21a0 100644
--- a/app/code/Magento/Theme/view/frontend/layout/print.xml
+++ b/app/code/Magento/Theme/view/frontend/layout/print.xml
@@ -27,7 +27,12 @@
     <block class="Magento\Theme\Block\Html" name="root" output="1" template="print.phtml">
         <block class="Magento\Theme\Block\Html\Head" name="head" as="head"/>
         <container name="after_body_start" as="after_body_start" label="Page Top"/>
-        <container name="content" as="content" label="Main Content Area"/>
+        <container name="main" as="main" label="Main Content Container" htmlTag="div" htmlClass="column main">
+            <container name="content.top" label="Main Content Top"/>
+            <container name="content" label="Main Content Area"/>
+            <container name="content.aside" label="Main Content Aside"/>
+            <container name="content.bottom" label="Main Content Bottom"/>
+        </container>
     </block>
     <update handle="default_head_blocks"/>
     <referenceBlock name="head">
diff --git a/app/code/Magento/Translation/Controller/Ajax.php b/app/code/Magento/Translation/Controller/Ajax.php
index 258cde173a3..70fd664195a 100644
--- a/app/code/Magento/Translation/Controller/Ajax.php
+++ b/app/code/Magento/Translation/Controller/Ajax.php
@@ -58,8 +58,7 @@ class Ajax extends \Magento\Framework\App\Action\Action
         } catch (\Exception $e) {
             $response = "{error:true,message:'" . $e->getMessage() . "'}";
         }
-        $this->getResponse()->setBody($response);
-
+        $this->getResponse()->representJson($response);
         $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
     }
 }
diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php
index 85f3345115a..08346039f3c 100644
--- a/app/code/Magento/Ups/Model/Carrier.php
+++ b/app/code/Magento/Ups/Model/Carrier.php
@@ -147,6 +147,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface
      * @param \Magento\Directory\Model\CountryFactory $countryFactory
      * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
      * @param \Magento\Directory\Helper\Data $directoryData
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Framework\Logger $logger
      * @param \Magento\Framework\Locale\FormatInterface $localeFormat
      * @param Config $configHelper
@@ -168,6 +169,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface
         \Magento\Directory\Model\CountryFactory $countryFactory,
         \Magento\Directory\Model\CurrencyFactory $currencyFactory,
         \Magento\Directory\Helper\Data $directoryData,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         \Magento\Framework\Logger $logger,
         \Magento\Framework\Locale\FormatInterface $localeFormat,
         Config $configHelper,
@@ -190,6 +192,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface
             $countryFactory,
             $currencyFactory,
             $directoryData,
+            $stockItemService,
             $data
         );
     }
diff --git a/app/code/Magento/Ups/etc/module.xml b/app/code/Magento/Ups/etc/module.xml
index 5e3c327c26d..ae8aab01ae5 100644
--- a/app/code/Magento/Ups/etc/module.xml
+++ b/app/code/Magento/Ups/etc/module.xml
@@ -32,6 +32,7 @@
             <module name="Magento_Sales"/>
             <module name="Magento_Shipping"/>
             <module name="Magento_Directory"/>
+            <module name="Magento_CatalogInventory"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/User/Controller/Adminhtml/User.php b/app/code/Magento/User/Controller/Adminhtml/User.php
index d515bc6b32e..38eacb24a78 100644
--- a/app/code/Magento/User/Controller/Adminhtml/User.php
+++ b/app/code/Magento/User/Controller/Adminhtml/User.php
@@ -167,7 +167,7 @@ class User extends \Magento\Backend\App\AbstractAction
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
 
-        $this->getResponse()->setBody($response->toJson());
+        $this->getResponse()->representJson($response->toJson());
     }
 
     /**
diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php
index c150954b786..af59af66dd7 100644
--- a/app/code/Magento/Usps/Model/Carrier.php
+++ b/app/code/Magento/Usps/Model/Carrier.php
@@ -145,6 +145,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
      * @param \Magento\Directory\Model\CountryFactory $countryFactory
      * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
      * @param \Magento\Directory\Helper\Data $directoryData
+     * @param \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService
      * @param \Magento\Shipping\Helper\Carrier $carrierHelper
      * @param \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory
      * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
@@ -166,6 +167,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
         \Magento\Directory\Model\CountryFactory $countryFactory,
         \Magento\Directory\Model\CurrencyFactory $currencyFactory,
         \Magento\Directory\Helper\Data $directoryData,
+        \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService,
         CarrierHelper $carrierHelper,
         \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory,
         \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory,
@@ -188,6 +190,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
             $countryFactory,
             $currencyFactory,
             $directoryData,
+            $stockItemService,
             $data
         );
     }
diff --git a/app/code/Magento/Usps/etc/module.xml b/app/code/Magento/Usps/etc/module.xml
index fb7bdbc8ba9..8ef5554d207 100644
--- a/app/code/Magento/Usps/etc/module.xml
+++ b/app/code/Magento/Usps/etc/module.xml
@@ -32,6 +32,7 @@
             <module name="Magento_Core"/>
             <module name="Magento_Catalog"/>
             <module name="Magento_Sales"/>
+            <module name="Magento_CatalogInventory"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/Webapi/Controller/ErrorProcessor.php b/app/code/Magento/Webapi/Controller/ErrorProcessor.php
index 357e3737e10..fb6519eef84 100644
--- a/app/code/Magento/Webapi/Controller/ErrorProcessor.php
+++ b/app/code/Magento/Webapi/Controller/ErrorProcessor.php
@@ -143,7 +143,7 @@ class ErrorProcessor
                 $stackTrace
             );
 
-        } else if ($exception instanceof WebapiException) {
+        } elseif ($exception instanceof WebapiException) {
             $maskedException = $exception;
         } else {
             $maskedException = new WebapiException(
diff --git a/app/code/Magento/Webapi/Model/PathProcessor.php b/app/code/Magento/Webapi/Model/PathProcessor.php
index 710ef1cc54b..5dc7ed484bb 100644
--- a/app/code/Magento/Webapi/Model/PathProcessor.php
+++ b/app/code/Magento/Webapi/Model/PathProcessor.php
@@ -54,6 +54,7 @@ class PathProcessor
         $path = '/' . implode('/', $pathParts);
         return explode('/', ltrim($path, '/'), 2);
     }
+
     /**
      * Process path info
      *
diff --git a/app/code/Magento/Webapi/Model/Rest/Config.php b/app/code/Magento/Webapi/Model/Rest/Config.php
index 5111a6b6a82..56ccb5d485d 100644
--- a/app/code/Magento/Webapi/Model/Rest/Config.php
+++ b/app/code/Magento/Webapi/Model/Rest/Config.php
@@ -36,30 +36,20 @@ class Config
      * HTTP methods supported by REST.
      */
     const HTTP_METHOD_GET = 'GET';
-
     const HTTP_METHOD_DELETE = 'DELETE';
-
     const HTTP_METHOD_PUT = 'PUT';
-
     const HTTP_METHOD_POST = 'POST';
-
     /**#@-*/
 
     /**#@+
      * Keys that a used for config internal representation.
      */
     const KEY_IS_SECURE = 'isSecure';
-
     const KEY_CLASS = 'class';
-
     const KEY_METHOD = 'method';
-
     const KEY_ROUTE_PATH = 'routePath';
-
     const KEY_ACL_RESOURCES = 'resources';
-
     const KEY_PARAMETERS = 'parameters';
-
     /*#@-*/
 
     /** @var ModelConfig */
@@ -98,17 +88,11 @@ class Config
             $this->_formatRoutePath($routeData[self::KEY_ROUTE_PATH])
         );
 
-        $route->setServiceClass(
-            $routeData[self::KEY_CLASS]
-        )->setServiceMethod(
-            $routeData[self::KEY_METHOD]
-        )->setSecure(
-            $routeData[self::KEY_IS_SECURE]
-        )->setAclResources(
-            $routeData[self::KEY_ACL_RESOURCES]
-        )->setParameters(
-            $routeData[self::KEY_PARAMETERS]
-        );
+        $route->setServiceClass($routeData[self::KEY_CLASS])
+            ->setServiceMethod($routeData[self::KEY_METHOD])
+            ->setSecure($routeData[self::KEY_IS_SECURE])
+            ->setAclResources($routeData[self::KEY_ACL_RESOURCES])
+            ->setParameters($routeData[self::KEY_PARAMETERS]);
         return $route;
     }
 
diff --git a/app/code/Magento/Widget/Controller/Adminhtml/Widget.php b/app/code/Magento/Widget/Controller/Adminhtml/Widget.php
index e70b2e7b0ed..a4ff2b83d17 100644
--- a/app/code/Magento/Widget/Controller/Adminhtml/Widget.php
+++ b/app/code/Magento/Widget/Controller/Adminhtml/Widget.php
@@ -108,7 +108,9 @@ class Widget extends \Magento\Backend\App\Action
             }
         } catch (\Magento\Framework\Model\Exception $e) {
             $result = array('error' => true, 'message' => $e->getMessage());
-            $this->getResponse()->setBody($this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result));
+            $this->getResponse()->representJson(
+                $this->_objectManager->get('Magento\Core\Helper\Data')->jsonEncode($result)
+            );
         }
     }
 
diff --git a/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance.php b/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance.php
index 5ab886a6d95..fba0cf63076 100644
--- a/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance.php
+++ b/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance.php
@@ -203,7 +203,9 @@ class Instance extends \Magento\Backend\App\Action
             $response->setError(true);
             $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
         }
-        $this->setBody($response->toJson());
+        $responseJson = $response->toJson();
+        $this->_translateInline->processResponseBody($responseJson, true);
+        $this->getResponse()->representJson($responseJson);
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php
index 274a2276817..757925811cd 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php
@@ -60,7 +60,7 @@ class ProductForm extends FormTabs
      *
      * @var string
      */
-    protected $advancedSettings = '#ui-accordion-product_info_tabs-advanced-header-0[aria-selected="false"]';
+    protected $advancedSettings = '#product_info_tabs-advanced [data-role="trigger"]';
 
     /**
      * Advanced tab list
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Backend/ProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Backend/ProductForm.php
index 4972a686f67..d9d81ec8cc9 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Backend/ProductForm.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Backend/ProductForm.php
@@ -87,7 +87,7 @@ class ProductForm extends FormTabs
      *
      * @var string
      */
-    protected $advancedSettings = '#ui-accordion-product_info_tabs-advanced-header-0[aria-selected="false"]';
+    protected $advancedSettings = '#product_info_tabs-advanced [data-role="trigger"]';
 
     /**
      * Advanced tab list
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/CompareTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/CompareTest.php
index a1c4fe65e02..3940cf21690 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/CompareTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/CompareTest.php
@@ -30,11 +30,15 @@ class CompareTest extends \PHPUnit_Framework_TestCase
      */
     protected $_helper;
 
+    /**
+     * @var \Magento\Framework\ObjectManager
+     */
+    protected $_objectManager;
+
     protected function setUp()
     {
-        $this->_helper = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Catalog\Helper\Product\Compare'
-        );
+        $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->_helper = $this->_objectManager->get('Magento\Catalog\Helper\Product\Compare');
     }
 
     /**
@@ -43,9 +47,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
     public function testGetListUrl()
     {
         /** @var $empty \Magento\Catalog\Helper\Product\Compare */
-        $empty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Helper\Product\Compare'
-        );
+        $empty = $this->_objectManager->create('Magento\Catalog\Helper\Product\Compare');
         $this->assertContains('/catalog/product_compare/index/', $empty->getListUrl());
 
         $this->_populateCompareList();
@@ -57,11 +59,12 @@ class CompareTest extends \PHPUnit_Framework_TestCase
         $this->_testGetProductUrl('getAddUrl', '/catalog/product_compare/add/');
     }
 
+    /**
+     * @magentoAppIsolation enabled
+     */
     public function testGetAddToWishlistParams()
     {
-        $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
+        $product = $this->_objectManager->create('Magento\Catalog\Model\Product');
         $product->setId(10);
         $json = $this->_helper->getAddToWishlistParams($product);
         $params = (array)json_decode($json);
@@ -109,8 +112,8 @@ class CompareTest extends \PHPUnit_Framework_TestCase
      */
     public function testCalculate()
     {
-        /** @var $session \Magento\Catalog\Model\Session */
-        $session = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Catalog\Model\Session');
+        /** @var \Magento\Catalog\Model\Session $session */
+        $session = $this->_objectManager->get('Magento\Catalog\Model\Session');
         try {
             $session->unsCatalogCompareItemsCount();
             $this->assertFalse($this->_helper->hasItems());
@@ -137,9 +140,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
 
     protected function _testGetProductUrl($method, $expectedFullAction)
     {
-        $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
+        $product = $this->_objectManager->create('Magento\Catalog\Model\Product');
         $product->setId(10);
         $url = $this->_helper->{$method}($product);
         $this->assertContains($expectedFullAction, $url);
@@ -150,18 +151,12 @@ class CompareTest extends \PHPUnit_Framework_TestCase
      */
     protected function _populateCompareList()
     {
-        $productOne = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
-        $productTwo = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
+        $productOne = $this->_objectManager->create('Magento\Catalog\Model\Product');
+        $productTwo = $this->_objectManager->create('Magento\Catalog\Model\Product');
         $productOne->load(10);
         $productTwo->load(11);
         /** @var $compareList \Magento\Catalog\Model\Product\Compare\ListCompare */
-        $compareList = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product\Compare\ListCompare'
-        );
+        $compareList = $this->_objectManager->create('Magento\Catalog\Model\Product\Compare\ListCompare');
         $compareList->addProduct($productOne)->addProduct($productTwo);
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTest.php
index 8bf3211aa31..3e5f2ac1b22 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTest.php
@@ -164,6 +164,9 @@ class AbstractTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($sku, $this->_model->getAttributeById($sku->getId(), $product));
     }
 
+    /**
+     * @magentoAppIsolation enabled
+     */
     public function testIsVirtual()
     {
         $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
index 8a7b64eed19..3caa3e17b64 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
@@ -31,333 +31,193 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create
  */
 /** @var $category \Magento\Catalog\Model\Category */
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    3
-)->setName(
-    'Category 1'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/3'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    1
-)->save();
+$category->setId(3)
+    ->setName('Category 1')
+    ->setParentId(2)
+    ->setPath('1/2/3')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(1)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    4
-)->setName(
-    'Category 1.1'
-)->setParentId(
-    3
-)->setPath(
-    '1/2/3/4'
-)->setLevel(
-    3
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setIsAnchor(
-    true
-)->setPosition(
-    1
-)->save();
+$category->setId(4)
+    ->setName('Category 1.1')
+    ->setParentId(3)
+    ->setPath('1/2/3/4')
+    ->setLevel(3)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setIsAnchor(true)
+    ->setPosition(1)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    5
-)->setName(
-    'Category 1.1.1'
-)->setParentId(
-    4
-)->setPath(
-    '1/2/3/4/5'
-)->setLevel(
-    4
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    1
-)->setCustomUseParentSettings(
-    0
-)->setCustomDesign(
-    'Magento/blank'
-)->save();
+$category->setId(5)
+    ->setName('Category 1.1.1')
+    ->setParentId(4)
+    ->setPath('1/2/3/4/5')
+    ->setLevel(4)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(1)
+    ->setCustomUseParentSettings(0)
+    ->setCustomDesign('Magento/blank')
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    6
-)->setName(
-    'Category 2'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/6'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    2
-)->save();
+$category->setId(6)
+    ->setName('Category 2')
+    ->setParentId(2)
+    ->setPath('1/2/6')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(2)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    7
-)->setName(
-    'Movable'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/7'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    3
-)->save();
+$category->setId(7)
+    ->setName('Movable')
+    ->setParentId(2)
+    ->setPath('1/2/7')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(3)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    8
-)->setName(
-    'Inactive'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/8'
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    false
-)->setPosition(
-    4
-)->save();
+$category->setId(8)
+    ->setName('Inactive')
+    ->setParentId(2)
+    ->setPath('1/2/8')
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(false)
+    ->setPosition(4)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    9
-)->setName(
-    'Movable Position 1'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/9'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    5
-)->save();
+$category->setId(9)
+    ->setName('Movable Position 1')
+    ->setParentId(2)
+    ->setPath('1/2/9')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(5)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    10
-)->setName(
-    'Movable Position 2'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/10'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    6
-)->save();
+$category->setId(10)
+    ->setName('Movable Position 2')
+    ->setParentId(2)
+    ->setPath('1/2/10')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(6)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    11
-)->setName(
-    'Movable Position 3'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/11'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    7
-)->save();
+$category->setId(11)
+    ->setName('Movable Position 3')
+    ->setParentId(2)
+    ->setPath('1/2/11')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(7)
+    ->save();
 
 $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Category');
-$category->setId(
-    12
-)->setName(
-    'Category 12'
-)->setParentId(
-    2
-)->setPath(
-    '1/2/12'
-)->setLevel(
-    2
-)->setAvailableSortBy(
-    'name'
-)->setDefaultSortBy(
-    'name'
-)->setIsActive(
-    true
-)->setPosition(
-    8
-)->save();
+$category->setId(12)
+    ->setName('Category 12')
+    ->setParentId(2)
+    ->setPath('1/2/12')
+    ->setLevel(2)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setPosition(8)
+    ->save();
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    1
-)->setAttributeSetId(
-    $installer->getAttributeSetId('catalog_product', 'Default')
-)->setStoreId(
-    1
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product'
-)->setSku(
-    'simple'
-)->setPrice(
-    10
-)->setWeight(
-    18
-)->setStockData(
-    array('use_config_manage_stock' => 0)
-)->setCategoryIds(
-    array(2, 3, 4)
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->load(1);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(1)
+    ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+    ->setStoreId(1)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product')
+    ->setSku('simple')
+    ->setPrice(10)
+    ->setWeight(18)
+    ->setStockData(array('use_config_manage_stock' => 0))
+    ->setCategoryIds(array(2, 3, 4))
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
 
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    2
-)->setAttributeSetId(
-    $installer->getAttributeSetId('catalog_product', 'Default')
-)->setStoreId(
-    1
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product Two'
-)->setSku(
-    '12345' // SKU intentionally contains digits only
-)->setPrice(
-    45.67
-)->setWeight(
-    56
-)->setStockData(
-    array('use_config_manage_stock' => 0)
-)->setCategoryIds(
-    array(5)
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->load(2);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(2)
+    ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+    ->setStoreId(1)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product Two')
+    ->setSku('12345') // SKU intentionally contains digits only
+    ->setPrice(45.67)
+    ->setWeight(56)
+    ->setStockData(array('use_config_manage_stock' => 0))
+    ->setCategoryIds(array(5))
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
 
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    3
-)->setAttributeSetId(
-    $installer->getAttributeSetId('catalog_product', 'Default')
-)->setStoreId(
-    1
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product Not Visible On Frontend'
-)->setSku(
-    'simple'
-)->setPrice(
-    15
-)->setWeight(
-    2
-)->setStockData(
-    array('use_config_manage_stock' => 0)
-)->setCategoryIds(
-    array(10, 11, 12)
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->load(3);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(3)
+    ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+    ->setStoreId(1)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product Not Visible On Frontend')
+    ->setSku('simple')
+    ->setPrice(15)
+    ->setWeight(2)
+    ->setStockData(array('use_config_manage_stock' => 0))
+    ->setCategoryIds(array(10, 11, 12))
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    4
-)->setAttributeSetId(
-    $installer->getAttributeSetId('catalog_product', 'Default')
-)->setStoreId(
-    1
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product Three'
-)->setSku(
-    'simple'
-)->setPrice(
-    10
-)->setWeight(
-    18
-)->setStockData(
-    array('use_config_manage_stock' => 0)
-)->setCategoryIds(
-    array(10, 11, 12)
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->load(4);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(4)
+    ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+    ->setStoreId(1)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product Three')
+    ->setSku('simple')
+    ->setPrice(10)
+    ->setWeight(18)
+    ->setStockData(array('use_config_manage_stock' => 0))
+    ->setCategoryIds(array(10, 11, 12))
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products.php
index 2214971347d..48fe277589b 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products.php
@@ -25,126 +25,70 @@
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
 
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    10
-)->setAttributeSetId(
-    4
-)->setName(
-    'Simple Product'
-)->setSku(
-    'simple1'
-)->setIsObjectNew(
-    true
-)->setTaxClassId(
-    'none'
-)->setDescription(
-    'description'
-)->setShortDescription(
-    'short description'
-)->setOptionsContainer(
-    'container1'
-)->setMsrpDisplayActualPriceType(
-    \Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type::TYPE_IN_CART
-)->setPrice(
-    10
-)->setWeight(
-    1
-)->setMetaTitle(
-    'meta title'
-)->setMetaKeyword(
-    'meta keyword'
-)->setMetaDescription(
-    'meta description'
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->setWebsiteIds(
-    array(1)
-)->setCateroryIds(
-    array()
-)->setStockData(
-    array('use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1)
-)->save();
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(10)
+    ->setAttributeSetId(4)
+    ->setName('Simple Product')
+    ->setSku('simple1')
+    ->setIsObjectNew(true)
+    ->setTaxClassId('none')
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setOptionsContainer('container1')
+    ->setMsrpDisplayActualPriceType(\Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type::TYPE_IN_CART)
+    ->setPrice(10)
+    ->setWeight(1)
+    ->setMetaTitle('meta title')
+    ->setMetaKeyword('meta keyword')
+    ->setMetaDescription('meta description')
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setWebsiteIds(array(1))
+    ->setCateroryIds(array())
+    ->setStockData(array('use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1))
+    ->save();
 
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    11
-)->setAttributeSetId(
-    4
-)->setName(
-    'Simple Product2'
-)->setSku(
-    'simple2'
-)->setIsObjectNew()->setTaxClassId(
-    'none'
-)->setDescription(
-    'description'
-)->setShortDescription(
-    'short description'
-)->setOptionsContainer(
-    'container1'
-)->setMsrpEnabled(
-    \Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type\Enabled::MSRP_ENABLE_YES
-)->setMsrpDisplayActualPriceType(
-    \Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type::TYPE_ON_GESTURE
-)->setPrice(
-    20
-)->setWeight(
-    1
-)->setMetaTitle(
-    'meta title'
-)->setMetaKeyword(
-    'meta keyword'
-)->setMetaDescription(
-    'meta description'
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->setWebsiteIds(
-    array(1)
-)->setCateroryIds(
-    array()
-)->setStockData(
-    array('use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1)
-)->save();
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(11)
+    ->setAttributeSetId(4)
+    ->setName('Simple Product2')
+    ->setSku('simple2')
+    ->setIsObjectNew()
+    ->setTaxClassId('none')
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setOptionsContainer('container1')
+    ->setMsrpEnabled(\Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type\Enabled::MSRP_ENABLE_YES)
+    ->setMsrpDisplayActualPriceType(\Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type::TYPE_ON_GESTURE)
+    ->setPrice(20)
+    ->setWeight(1)
+    ->setMetaTitle('meta title')
+    ->setMetaKeyword('meta keyword')
+    ->setMetaDescription('meta description')
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setWebsiteIds(array(1))
+    ->setCateroryIds(array())
+    ->setStockData(array('use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1))
+    ->save();
 
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    12
-)->setAttributeSetId(
-    4
-)->setName(
-    'Simple Product 3'
-)->setSku(
-    'simple3'
-)->setIsObjectNew()->setTaxClassId(
-    'none'
-)->setDescription(
-    'description'
-)->setShortDescription(
-    'short description'
-)->setMsrpEnabled(
-    \Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type\Enabled::MSRP_ENABLE_NO
-)->setPrice(
-    30
-)->setWeight(
-    1
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED
-)->setWebsiteIds(
-    array(1)
-)->setCateroryIds(
-    array()
-)->setStockData(
-    array('use_config_manage_stock' => 1, 'qty' => 140, 'is_qty_decimal' => 0, 'is_in_stock' => 1)
-)->save();
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(12)
+    ->setAttributeSetId(4)
+    ->setName('Simple Product 3')
+    ->setSku('simple3')
+    ->setIsObjectNew()
+    ->setTaxClassId('none')
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setMsrpEnabled(\Magento\Catalog\Model\Product\Attribute\Source\Msrp\Type\Enabled::MSRP_ENABLE_NO)
+    ->setPrice(30)
+    ->setWeight(1)
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED)
+    ->setWebsiteIds(array(1))
+    ->setCateroryIds(array())
+    ->setStockData(array('use_config_manage_stock' => 1, 'qty' => 140, 'is_qty_decimal' => 0, 'is_in_stock' => 1))
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
index ab660709210..6551b02c94c 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
@@ -59,16 +59,12 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
         )
     )
     ->setDescription('Description with <b>html tag</b>')
-
     ->setMetaTitle('meta title')
     ->setMetaKeyword('meta keyword')
     ->setMetaDescription('meta description')
-
     ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
     ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
-
     ->setCategoryIds(array(2))
-
     ->setStockData(
         array(
             'use_config_manage_stock'   => 1,
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_special_price.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_special_price.php
index 99100c73f2e..3a010201344 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_special_price.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_special_price.php
@@ -24,32 +24,18 @@
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    'simple'
-)->setId(
-    1
-)->setAttributeSetId(
-    4
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product'
-)->setSku(
-    'simple'
-)->setPrice(
-    10
-)->setMetaTitle(
-    'meta title'
-)->setMetaKeyword(
-    'meta keyword'
-)->setMetaDescription(
-    'meta description'
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->setStockData(
-    array('use_config_manage_stock' => 0)
-)->setStockData()->setSpecialPrice(
-    '5.99'
-)->save();
+$product->setTypeId('simple')
+    ->setId(1)
+    ->setAttributeSetId(4)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product')
+    ->setSku('simple')
+    ->setPrice(10)
+    ->setMetaTitle('meta title')
+    ->setMetaKeyword('meta keyword')
+    ->setMetaDescription('meta description')
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setStockData(array('use_config_manage_stock' => 0))
+    ->setSpecialPrice('5.99')
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
index 368ca224cb6..af83f2260be 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
@@ -24,24 +24,14 @@
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL
-)->setId(
-    21
-)->setAttributeSetId(
-    4
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Virtual Product'
-)->setSku(
-    'virtual-product'
-)->setPrice(
-    10
-)->setTaxClassId(
-    0
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL)
+    ->setId(21)
+    ->setAttributeSetId(4)
+    ->setWebsiteIds(array(1))
+    ->setName('Virtual Product')
+    ->setSku('virtual-product')
+    ->setPrice(10)
+    ->setTaxClassId(0)
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
index 322a1717e4d..334a1b12bb8 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
@@ -51,5 +51,154 @@ $product->setTypeId(
 )->setCanSaveCustomOptions(
     true
 )->setProductOptions(
-    array(array('title' => 'test_option_code_1', 'type' => 'field', 'is_require' => true))
+    array(
+        [
+            'title' => 'test_option_code_1',
+            'type' => 'field',
+            'is_require' => true,
+            'sort_order' => 1,
+            'price' => 10.0,
+            'price_type' => 'fixed',
+            'sku' => 'sku1',
+            'max_characters' => 10
+        ],
+        [
+            'title' => 'area option',
+            'type' => 'area',
+            'is_require' => false,
+            'sort_order' => 2,
+            'price' => 20.0,
+            'price_type' => 'percent',
+            'sku' => 'sku2',
+            'max_characters' => 20
+        ],
+        [
+            'title' => 'file option',
+            'type' => 'file',
+            'is_require' => true,
+            'sort_order' => 3,
+            'price' => 30.0,
+            'price_type' => 'percent',
+            'sku' => 'sku3',
+            'file_extension' => 'jpg, png, gif',
+            'image_size_x' => 10,
+            'image_size_y' => 20
+
+        ],
+        [
+            'title' => 'drop_down option',
+            'type' => 'drop_down',
+            'is_require' => true,
+            'sort_order' => 4,
+            'values' => [
+                [
+                    'title' => 'drop_down option 1',
+                    'price' => 10,
+                    'price_type' => 'fixed',
+                    'sku' => 'drop_down option 1 sku',
+                    'sort_order' => 1,
+                ],
+                [
+                    'title' => 'drop_down option 2',
+                    'price' => 20,
+                    'price_type' => 'fixed',
+                    'sku' => 'drop_down option 2 sku',
+                    'sort_order' => 2,
+                ],
+            ],
+        ],
+        [
+            'title' => 'radio option',
+            'type' => 'radio',
+            'is_require' => true,
+            'sort_order' => 5,
+            'values' => [
+                [
+                    'title' => 'radio option 1',
+                    'price' => 10,
+                    'price_type' => 'fixed',
+                    'sku' => 'radio option 1 sku',
+                    'sort_order' => 1,
+                ],
+                [
+                    'title' => 'radio option 2',
+                    'price' => 20,
+                    'price_type' => 'fixed',
+                    'sku' => 'radio option 2 sku',
+                    'sort_order' => 2,
+                ],
+            ],
+        ],
+        [
+            'title' => 'checkbox option',
+            'type' => 'checkbox',
+            'is_require' => true,
+            'sort_order' => 6,
+            'values' => [
+                [
+                    'title' => 'checkbox option 1',
+                    'price' => 10,
+                    'price_type' => 'fixed',
+                    'sku' => 'checkbox option 1 sku',
+                    'sort_order' => 1,
+                ],
+                [
+                    'title' => 'checkbox option 2',
+                    'price' => 20,
+                    'price_type' => 'fixed',
+                    'sku' => 'checkbox option 2 sku',
+                    'sort_order' => 2,
+                ],
+            ],
+        ],
+        [
+            'title' => 'multiple option',
+            'type' => 'multiple',
+            'is_require' => true,
+            'sort_order' => 7,
+            'values' => [
+                [
+                    'title' => 'multiple option 1',
+                    'price' => 10,
+                    'price_type' => 'fixed',
+                    'sku' => 'multiple option 1 sku',
+                    'sort_order' => 1,
+                ],
+                [
+                    'title' => 'multiple option 2',
+                    'price' => 20,
+                    'price_type' => 'fixed',
+                    'sku' => 'multiple option 2 sku',
+                    'sort_order' => 2,
+                ],
+            ],
+        ],
+        [
+            'title' => 'date option',
+            'type' => 'date',
+            'price' => 80.0,
+            'price_type' => 'fixed',
+            'sku' => 'date option sku',
+            'is_require' => true,
+            'sort_order' => 8
+        ],
+        [
+            'title' => 'date_time option',
+            'type' => 'date_time',
+            'price' => 90.0,
+            'price_type' => 'fixed',
+            'is_require' => true,
+            'sort_order' => 9,
+            'sku' => 'date_time option sku'
+        ],
+        [
+            'title' => 'time option',
+            'type' => 'time',
+            'price' => 100.0,
+            'price_type' => 'fixed',
+            'is_require' => true,
+            'sku' => 'time option sku',
+            'sort_order' => 10
+        ]
+    )
 )->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options_rollback.php
new file mode 100644
index 00000000000..6ffb72acf9b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options_rollback.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->load(1);
+if ($product->getId()) {
+    $product->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php
new file mode 100644
index 00000000000..2b221f5f36f
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->setTypeId(
+    'simple'
+)->setId(
+    1
+)->setAttributeSetId(
+    4
+)->setWebsiteIds(
+    array(1)
+)->setName(
+    'Simple Product Without Custom Options'
+)->setSku(
+    'simple'
+)->setPrice(
+    10
+)->setMetaTitle(
+    'meta title'
+)->setMetaKeyword(
+    'meta keyword'
+)->setMetaDescription(
+    'meta description'
+)->setVisibility(
+    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
+)->setStatus(
+    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
+)->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options_rollback.php
new file mode 100644
index 00000000000..6ffb72acf9b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options_rollback.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->load(1);
+if ($product->getId()) {
+    $product->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
index 4d95deec498..246101344bb 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -529,7 +529,11 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         ) . "\n";
         $data = 'data://text/plain;base64,' . base64_encode($data);
 
-        $fixture = new \Magento\ImportExport\Model\Import\Source\Csv($data);
+        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $fixture = $objectManager->create(
+            'Magento\ImportExport\Model\Import\Source\Csv',
+            array('$fileOrStream' => $data)
+        );
 
         foreach (\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
             'Magento\Catalog\Model\Resource\Product\Collection'
@@ -537,7 +541,6 @@ class ProductTest extends \PHPUnit_Framework_TestCase
             $this->fail("Unexpected precondition - product exists: '{$product->getId()}'.");
         }
 
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
         $uploader = $this->getMock(
             'Magento\CatalogImportExport\Model\Import\Uploader',
             array('init'),
@@ -676,4 +679,45 @@ class ProductTest extends \PHPUnit_Framework_TestCase
             "There should not be any linked upsell SKUs. The original" . " product SKU linked does not import cleanly."
         );
     }
+
+    /**
+     * @magentoDataFixture Magento/Catalog/_files/categories.php
+     * @magentoDataFixture Magento/Core/_files/store.php
+     * @magentoDataFixture Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option.php
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php
+     */
+    public function testProductsWithMultipleStores()
+    {
+        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+        $filesystem = $objectManager->create('Magento\Framework\App\Filesystem');
+        $directory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem::ROOT_DIR);
+
+        $source = new \Magento\ImportExport\Model\Import\Source\Csv(
+            __DIR__ . '/_files/products_multiple_stores.csv',
+            $directory
+        );
+        $this->_model->setParameters(
+            array('behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product')
+        )->setSource(
+            $source
+        )->isDataValid();
+
+        $this->_model->importData();
+
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $objectManager->create('Magento\Catalog\Model\Product');
+        $id = $product->getIdBySku('Configurable 03');
+        $product->load($id);
+        $this->assertEquals('1', $product->getHasOptions());
+
+        $objectManager->get('Magento\Store\Model\StoreManagerInterface')->setCurrentStore('fixturestore');
+
+        /** @var \Magento\Catalog\Model\Product $simpleProduct */
+        $simpleProduct = $objectManager->create('Magento\Catalog\Model\Product');
+        $id = $simpleProduct->getIdBySku('Configurable 03-option_0');
+        $simpleProduct->load($id);
+        $this->assertEquals('Option Label', $simpleProduct->getAttributeText('attribute_with_option'));
+        $this->assertEquals(array(2, 4), $simpleProduct->getAvailableInCategories());
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_multiple_stores.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_multiple_stores.csv
new file mode 100644
index 00000000000..1dc4a16f741
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_multiple_stores.csv
@@ -0,0 +1,6 @@
+sku,_store,_attribute_set,_type,_category,_root_category,_product_websites,test_configurable,cost,country_of_manufacture,created_at,custom_design,custom_design_from,custom_design_to,custom_layout_update,description,gallery,gift_message_available,gift_wrapping_available,gift_wrapping_price,has_options,image,image_label,is_returnable,manufacturer,meta_description,meta_keyword,meta_title,minimal_price,msrp,msrp_display_actual_price_type,msrp_enabled,name,news_from_date,news_to_date,options_container,page_layout,price,quantity_and_stock_status,related_tgtr_position_behavior,related_tgtr_position_limit,required_options,short_description,attribute_with_option,small_image,small_image_label,special_from_date,special_price,special_to_date,status,tax_class_id,thumbnail,thumbnail_label,updated_at,upsell_tgtr_position_behavior,upsell_tgtr_position_limit,url_key,url_path,visibility,weight,qty,min_qty,use_config_min_qty,is_qty_decimal,backorders,use_config_backorders,min_sale_qty,use_config_min_sale_qty,max_sale_qty,use_config_max_sale_qty,is_in_stock,notify_stock_qty,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,_related_sku,_related_position,_crosssell_sku,_crosssell_position,_upsell_sku,_upsell_position,_associated_sku,_associated_default_qty,_associated_position,_tier_price_website,_tier_price_customer_group,_tier_price_qty,_tier_price_price,_group_price_website,_group_price_customer_group,_group_price_price,_media_attribute_id,_media_image,_media_label,_media_position,_media_is_disabled,_super_products_sku,_super_attribute_code,_super_attribute_option,_super_attribute_price_corr
+"Configurable 03-option_0",,Default,virtual,"Category 1/Category 1.1","Default Category",base,Option 1,,,"2014-06-13 07:34:02",,,,,,,,,,0,,,"Use config",,"Configurable 03 ","Configurable 03","Configurable 03",,,"Use config","Use config","Configurable 03-option_0",,,"Block after Info Column",,10.0000,"In Stock",,,0,,,,,,,,1,2,,,"2014-06-13 07:35:59",,,configurable-03-option_0,configurable-03-option_0.html,1,,99999.0000,0.0000,1,0,0,1,1.0000,1,0.0000,1,1,,1,1,1,1,0.0000,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,
+,fixturestore,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Option Label",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+"Configurable 03-option_1",,Default,virtual,"Category 1/Category 1.1","Default Category",base,Option 2,,,"2014-06-13 07:34:05",,,,,,,,,,0,,,"Use config",,"Configurable 03 ","Configurable 03","Configurable 03",,,"Use config","Use config","Configurable 03-option_1",,,"Block after Info Column",,10.0000,"In Stock",,,0,,,,,,,,1,2,,,"2014-06-13 07:34:05",,,configurable-03-option_1,configurable-03-option_1.html,1,,99999.0000,0.0000,1,0,0,1,1.0000,1,0.0000,1,1,,1,1,1,1,0.0000,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,
+"Configurable 03",,Default,configurable,"Category 1/Category 1.1","Default Category",base,,,,"2014-06-13 07:34:07",,,,,,,,,,1,,,"Use config",,"Configurable 03 ","Configurable 03","Configurable 03",,,"Use config","Use config","Configurable 03",,,"Block after Info Column",,10.0000,"In Stock",,,1,,,,,,,,1,2,,,"2014-06-13 07:36:32",,,configurable-03,configurable-03.html,4,,0.0000,0.0000,1,0,0,1,1.0000,1,0.0000,1,1,,1,1,1,1,0.0000,1,0,0,,,,,,,,,,,,,,,,,,,,,,"Configurable 03-option_0",test_configurable,Option 1,1.0000
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Configurable 03-option_1",test_configurable,Option 2,2.0000
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_downloadable_product.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_downloadable_product.php
index 728caf069f7..cfa71dcb2aa 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_downloadable_product.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_downloadable_product.php
@@ -22,7 +22,7 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-require __DIR__ . '/../../../Magento/Downloadable/_files/product.php';
+require __DIR__ . '/../../../Magento/Downloadable/_files/product_downloadable.php';
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
index 5bd46f2824f..5a529226aef 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
@@ -463,16 +463,15 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
      */
     public function testGenerateSimpleProductsWithPartialData($productsData)
     {
+        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        /** @var \Magento\CatalogInventory\Service\V1\StockItemService $stockItemService */
+        $stockItemService = $objectManager->get('Magento\CatalogInventory\Service\V1\StockItemService');
         $this->_product->setNewVariationsAttributeSetId(4);
         $generatedProducts = $this->_model->generateSimpleProducts($this->_product, $productsData);
         foreach ($generatedProducts as $productId) {
-            /** @var $product \Magento\Catalog\Model\Product */
-            $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\Catalog\Model\Product'
-            );
-            $product->load($productId);
-            $this->assertEquals('0', $product->getStockItem()->getData('manage_stock'));
-            $this->assertEquals('1', $product->getStockItem()->getData('is_in_stock'));
+            $stockItemData = $stockItemService->getStockItem($productId);
+            $this->assertEquals('0', $stockItemData->isManageStock());
+            $this->assertEquals('1', $stockItemData->getIsInStock());
         }
     }
 
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php
new file mode 100644
index 00000000000..697509c8e58
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/* Create attribute */
+/** @var $installer \Magento\Catalog\Model\Resource\Setup */
+$installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    'Magento\Catalog\Model\Resource\Setup',
+    array('resourceName' => 'catalog_setup')
+);
+/** @var $attribute \Magento\Catalog\Model\Resource\Eav\Attribute */
+$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    'Magento\Catalog\Model\Resource\Eav\Attribute'
+);
+$attribute->setData(
+    array(
+        'attribute_code' => 'test_configurable',
+        'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
+        'is_global' => 1,
+        'is_user_defined' => 1,
+        'frontend_input' => 'select',
+        'is_unique' => 0,
+        'is_required' => 1,
+        'is_configurable' => 1,
+        'is_searchable' => 0,
+        'is_visible_in_advanced_search' => 0,
+        'is_comparable' => 0,
+        'is_filterable' => 0,
+        'is_filterable_in_search' => 0,
+        'is_used_for_promo_rules' => 0,
+        'is_html_allowed_on_front' => 1,
+        'is_visible_on_front' => 0,
+        'used_in_product_listing' => 0,
+        'used_for_sort_by' => 0,
+        'frontend_label' => array('Test Configurable'),
+        'backend_type' => 'int',
+        'option' => array(
+            'value' => array('option_0' => array('Option 1'), 'option_1' => array('Option 2')),
+            'order' => array('option_0' => 1, 'option_1' => 2)
+        )
+    )
+);
+$attribute->save();
+
+/* Assign attribute to attribute set */
+$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId());
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
index 8db4d372003..7a9e71d2604 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
@@ -22,48 +22,13 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-/* Create attribute */
+require __DIR__ . '/configurable_attribute.php';
+
 /** @var $installer \Magento\Catalog\Model\Resource\Setup */
 $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
     'Magento\Catalog\Model\Resource\Setup',
     array('resourceName' => 'catalog_setup')
 );
-/** @var $attribute \Magento\Catalog\Model\Resource\Eav\Attribute */
-$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-    'Magento\Catalog\Model\Resource\Eav\Attribute'
-);
-$attribute->setData(
-    array(
-        'attribute_code' => 'test_configurable',
-        'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
-        'is_global' => 1,
-        'is_user_defined' => 1,
-        'frontend_input' => 'select',
-        'is_unique' => 0,
-        'is_required' => 1,
-        'is_configurable' => 1,
-        'is_searchable' => 0,
-        'is_visible_in_advanced_search' => 0,
-        'is_comparable' => 0,
-        'is_filterable' => 0,
-        'is_filterable_in_search' => 0,
-        'is_used_for_promo_rules' => 0,
-        'is_html_allowed_on_front' => 1,
-        'is_visible_on_front' => 0,
-        'used_in_product_listing' => 0,
-        'used_for_sort_by' => 0,
-        'frontend_label' => array('Test Configurable'),
-        'backend_type' => 'int',
-        'option' => array(
-            'value' => array('option_0' => array('Option 1'), 'option_1' => array('Option 2')),
-            'order' => array('option_0' => 1, 'option_1' => 2)
-        )
-    )
-);
-$attribute->save();
-
-/* Assign attribute to attribute set */
-$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId());
 
 /* Create simple products per each option */
 /** @var $options \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */
diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer.php
index 2d240dbee96..67d35942ac7 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer.php
@@ -23,32 +23,18 @@
  */
 $customer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Customer\Model\Customer');
 /** @var Magento\Customer\Model\Customer $customer */
-$customer->setWebsiteId(
-    1
-)->setId(
-    1
-)->setEntityTypeId(
-    1
-)->setAttributeSetId(
-    1
-)->setEmail(
-    'customer@example.com'
-)->setPassword(
-    'password'
-)->setGroupId(
-    1
-)->setStoreId(
-    1
-)->setIsActive(
-    1
-)->setFirstname(
-    'Firstname'
-)->setLastname(
-    'Lastname'
-)->setDefaultBilling(
-    1
-)->setDefaultShipping(
-    1
-);
+$customer->setWebsiteId(1)
+    ->setId(1)
+    ->setEntityTypeId(1)
+    ->setAttributeSetId(1)
+    ->setEmail('customer@example.com')
+    ->setPassword('password')
+    ->setGroupId(1)
+    ->setStoreId(1)
+    ->setIsActive(1)
+    ->setFirstname('Firstname')
+    ->setLastname('Lastname')
+    ->setDefaultBilling(1)
+    ->setDefaultShipping(1);
 $customer->isObjectNew(true);
 $customer->save();
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/ProductTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Controller/ProductTest.php
index ab80ab13ae0..becf1073dcd 100644
--- a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/Controller/ProductTest.php
@@ -30,7 +30,7 @@ namespace Magento\Downloadable\Controller;
 class ProductTest extends \Magento\TestFramework\TestCase\AbstractController
 {
     /**
-     * @magentoDataFixture Magento/Downloadable/_files/product.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
      */
     public function testViewAction()
     {
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
index 6db305ce849..2b405109d20 100644
--- a/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
@@ -42,7 +42,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Magento/Downloadable/_files/product_with_files.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
      * @magentoAppArea adminhtml
      */
     public function testDeleteTypeSpecificData()
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Downloadable/_files/product.php
rename to dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_rollback.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_rollback.php
new file mode 100644
index 00000000000..6e6a5f7085c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_rollback.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+require __DIR__ . '/../../../Magento/Catalog/_files/product_simple_rollback.php';
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_with_files.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Downloadable/_files/product_with_files.php
rename to dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files_rollback.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files_rollback.php
new file mode 100644
index 00000000000..6e6a5f7085c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files_rollback.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+require __DIR__ . '/../../../Magento/Catalog/_files/product_simple_rollback.php';
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
index f9f373c06b9..0b498eb4917 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
@@ -50,7 +50,7 @@ class CreateTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Magento/Downloadable/_files/product.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
      * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product.php
      */
     public function testInitFromOrderShippingAddressSameAsBillingWhenEmpty()
@@ -69,7 +69,7 @@ class CreateTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Magento/Downloadable/_files/product.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
      * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product.php
      * @magentoDataFixture Magento/Sales/_files/order_shipping_address_same_as_billing.php
      */
@@ -90,7 +90,7 @@ class CreateTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Magento/Downloadable/_files/product.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
      * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product.php
      * @magentoDataFixture Magento/Sales/_files/order_shipping_address_different_to_billing.php
      */
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php
index cda5374ec05..8b346afc80c 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php
@@ -28,30 +28,21 @@
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    'virtual'
-)->setId(
-    1
-)->setAttributeSetId(
-    4
-)->setName(
-    'Simple Product'
-)->setSku(
-    'simple'
-)->setPrice(
-    10
-)->setStockData(
-    array(
+$product->setTypeId('virtual')
+    ->setId(1)
+    ->setAttributeSetId(4)
+    ->setName('Simple Product')
+    ->setSku('simple')
+    ->setPrice(10)
+    ->setStockData(array(
         'use_config_manage_stock' => 1,
         'qty'                     => 100,
         'is_qty_decimal'          => 0,
         'is_in_stock'             => 1
-    )
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+    ))
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->save();
 $product->load(1);
 
 $addressData = include __DIR__ . '/address_data.php';
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php
index f8477b69b25..f8a3e8daeac 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php
@@ -46,6 +46,7 @@ class SubtotalTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
+     * @magentoAppIsolation enabled
      * @magentoDataFixture Magento/Customer/_files/customer.php
      * @magentoDataFixture Magento/Customer/_files/customer_address.php
      * @magentoDataFixture Magento/Tax/_files/tax_classes.php
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
index cd8801dbfbc..b58bd0afe7c 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
@@ -1744,6 +1744,36 @@ return array(
         'Magento\Framework\View\Asset\ModuleNotation\Resolver::convertModuleNotationToPath'
     ],
     ['getViewFile', 'Magento\Framework\View\FileSystem', 'Magento\Framework\View\Asset\File::getSourceFile()'],
+    [
+        '_unserializeValue',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::unserializeValue'
+    ],
+    [
+        '_isEncodedArrayFieldValue',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::isEncodedArrayFieldValue'
+    ],
+    [
+        '_serializeValue',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::serializeValue'
+    ],
+    [
+        '_fixQty',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::fixQty'
+    ],
+    [
+        '_encodeArrayFieldValue',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::encodeArrayFieldValue'
+    ],
+    [
+        '_decodeArrayFieldValue',
+        'Magento\CatalogInventory\Helper\Minsaleqty',
+        'Magento\CatalogInventory\Helper\Minsaleqty::decodeArrayFieldValue'
+    ],
     ['updateOrderAction', 'Magento\Paypal\Controller\Express\AbstractExpress'],
     ['updateOrder', 'Magento\Paypal\Model\Express\Checkout'],
     ['_matchBnCountryCode', 'Magento\Paypal\Model\Config'],
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php
index ea68041a59f..330062a2447 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php
@@ -339,4 +339,5 @@ return array(
     ['_inventoryModel', 'Magento\AdvancedCheckout\Model\Resource\Sku\Errors\Grid\Collection'],
     ['_productInstance', 'Magento\CatalogInventory\Model\Stock\Item'],
     ['_regionBuilder', 'Magento\Customer\Model\Address\Converter'],
+    ['_scopeConfig', 'Magento\CatalogInventory\Helper\Minsaleqty', 'scopeConfig'],
 );
diff --git a/dev/tests/unit/testsuite/Magento/Authorizenet/Model/Directpost/ObserverTest.php b/dev/tests/unit/testsuite/Magento/Authorizenet/Model/Directpost/ObserverTest.php
index 9778cc6afbd..6334978d52b 100644
--- a/dev/tests/unit/testsuite/Magento/Authorizenet/Model/Directpost/ObserverTest.php
+++ b/dev/tests/unit/testsuite/Magento/Authorizenet/Model/Directpost/ObserverTest.php
@@ -125,7 +125,7 @@ class ObserverTest extends \PHPUnit_Framework_TestCase
             $this->returnValue('encoded response')
         );
         $response->expects($this->once())->method('clearHeader')->with('Location');
-        $response->expects($this->once())->method('setBody')->with('encoded response');
+        $response->expects($this->once())->method('representJson')->with('encoded response');
         $this->model->addAdditionalFieldsToResponseFrontend($observer);
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Controller/Adminhtml/Category/WidgetTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Controller/Adminhtml/Category/WidgetTest.php
index 83151ae6df0..975711fdd96 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Controller/Adminhtml/Category/WidgetTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Controller/Adminhtml/Category/WidgetTest.php
@@ -136,7 +136,7 @@ class WidgetTest extends \PHPUnit_Framework_TestCase
         );
         $testHtml = '<div>Some test html</div>';
         $this->chooserBlockMock->expects($this->once())->method('getTreeJson')->will($this->returnValue($testHtml));
-        $this->responseMock->expects($this->once())->method('setBody')->with($this->equalTo($testHtml));
+        $this->responseMock->expects($this->once())->method('representJson')->with($this->equalTo($testHtml));
         $this->controller->categoriesJsonAction();
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php
index f2de2a7b003..11037157cb7 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php
@@ -30,58 +30,52 @@ class StockTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Catalog\Model\Product\Attribute\Backend\Stock
      */
-    protected $_model;
+    protected $model;
 
     /**
-     * @var \Magento\CatalogInventory\Model\Stock\Item
+     * @var \Magento\CatalogInventory\Service\V1\StockItemServiceInterface
      */
-    protected $_inventory;
+    protected $stockItemService;
 
     /**
      * @var \Magento\TestFramework\Helper\ObjectManager
      */
-    protected $_objectHelper;
+    protected $objectHelper;
 
     protected function setUp()
     {
-        $this->_objectHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $this->_inventory = $this->getMock(
-            'Magento\CatalogInventory\Model\Stock\Item',
-            array('getIsInStock', 'getQty', 'loadByProduct', '__wakeup'),
-            array(),
-            '',
-            false
-        );
+        $this->objectHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->stockItemService = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\StockItemService')
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $stockItemFactory = $this->getMock(
-            'Magento\CatalogInventory\Model\Stock\ItemFactory',
-            array('create'),
-            array(),
-            '',
-            false
-        );
-        $stockItemFactory->expects($this->any())->method('create')->will($this->returnValue($this->_inventory));
-        $this->_model = $this->_objectHelper->getObject(
+        $this->model = $this->objectHelper->getObject(
             'Magento\Catalog\Model\Product\Attribute\Backend\Stock',
-            array('data' => array('inventory' => $this->_inventory), 'stockItemFactory' => $stockItemFactory)
+            array('stockItemService' => $this->stockItemService)
         );
         $attribute = $this->getMock('Magento\Framework\Object', array('getAttributeCode'));
-        $attribute->expects(
-            $this->atLeastOnce()
-        )->method(
-            'getAttributeCode'
-        )->will(
-            $this->returnValue(self::ATTRIBUTE_NAME)
-        );
-        $this->_model->setAttribute($attribute);
+        $attribute->expects($this->atLeastOnce())
+            ->method('getAttributeCode')
+            ->will($this->returnValue(self::ATTRIBUTE_NAME));
+        $this->model->setAttribute($attribute);
     }
 
     public function testAfterLoad()
     {
-        $this->_inventory->expects($this->once())->method('getIsInStock')->will($this->returnValue(1));
-        $this->_inventory->expects($this->once())->method('getQty')->will($this->returnValue(5));
-        $object = new \Magento\Framework\Object();
-        $this->_model->afterLoad($object);
+        $productId = 2;
+        $stockItemDo = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItem')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockItemService->expects($this->once())
+            ->method('getStockItem')
+            ->with($productId)
+            ->will($this->returnValue($stockItemDo));
+
+        $stockItemDo->expects($this->once())->method('getIsInStock')->will($this->returnValue(1));
+        $stockItemDo->expects($this->once())->method('getQty')->will($this->returnValue(5));
+        $object = new \Magento\Framework\Object(['id' => $productId]);
+        $this->model->afterLoad($object);
         $data = $object->getData();
         $this->assertEquals(1, $data[self::ATTRIBUTE_NAME]['is_in_stock']);
         $this->assertEquals(5, $data[self::ATTRIBUTE_NAME]['qty']);
@@ -100,7 +94,7 @@ class StockTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals(2, $stockData['qty']);
         $this->assertNotEmpty($object->getData(self::ATTRIBUTE_NAME));
 
-        $this->_model->beforeSave($object);
+        $this->model->beforeSave($object);
 
         $stockData = $object->getStockData();
         $this->assertEquals(1, $stockData['is_in_stock']);
@@ -117,7 +111,7 @@ class StockTest extends \PHPUnit_Framework_TestCase
             )
         );
 
-        $this->_model->beforeSave($object);
+        $this->model->beforeSave($object);
 
         $stockData = $object->getStockData();
         $this->assertNull($stockData['qty']);
@@ -132,7 +126,7 @@ class StockTest extends \PHPUnit_Framework_TestCase
             )
         );
 
-        $this->_model->beforeSave($object);
+        $this->model->beforeSave($object);
 
         $stockData = $object->getStockData();
         $this->assertEquals(0, $stockData['qty']);
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/DefaultValidatorTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/DefaultValidatorTest.php
new file mode 100644
index 00000000000..5df12e54d03
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/DefaultValidatorTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class DefaultValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Validator\DefaultValidator
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueMock;
+
+    protected function setUp()
+    {
+        $configMock = $this->getMock('Magento\Catalog\Model\ProductOptions\ConfigInterface');
+        $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price();
+        $config = [
+            [
+                'label' => 'group label 1',
+                'types' => [
+                    [
+                        'label' => 'label 1.1',
+                        'name' => 'name 1.1',
+                        'disabled' => false
+                    ],
+                ]
+            ],
+            [
+                'label' => 'group label 2',
+                'types' => [
+                    [
+                        'label' => 'label 2.2',
+                        'name' => 'name 2.2',
+                        'disabled' => true
+                    ],
+                ]
+            ],
+        ];
+        $configMock->expects($this->once())->method('getAll')->will($this->returnValue($config));
+        $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', '__wakeup'];
+        $this->valueMock = $this->getMock('Magento\Catalog\Model\Product\Option', $methods, [], '', false);
+        $this->validator = new \Magento\Catalog\Model\Product\Option\Validator\DefaultValidator(
+            $configMock,
+            $priceConfigMock
+        );
+    }
+
+    public function testIsValidSuccess()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->assertTrue($this->validator->isValid($this->valueMock));
+        $this->assertEmpty($this->validator->getMessages());
+    }
+
+    public function testIsValidFail()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle');
+        $this->valueMock->expects($this->once())->method('getType');
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('some_new_value'));
+        $this->valueMock->expects($this->never())->method('getPrice');
+        $messages = [
+            'option required fields' => 'Missed values for option required fields',
+            'option type' => 'Invalid option type',
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+
+    public function testValidationNegativePrice()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(-12));
+
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/FileTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/FileTest.php
new file mode 100644
index 00000000000..2c9e6913719
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/FileTest.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class FileTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Validator\File
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueMock;
+
+    protected function setUp()
+    {
+        $configMock = $this->getMock('Magento\Catalog\Model\ProductOptions\ConfigInterface');
+        $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price();
+        $config = [
+            [
+                'label' => 'group label 1',
+                'types' => [
+                    [
+                        'label' => 'label 1.1',
+                        'name' => 'name 1.1',
+                        'disabled' => false
+                    ],
+                ]
+            ],
+            [
+                'label' => 'group label 2',
+                'types' => [
+                    [
+                        'label' => 'label 2.2',
+                        'name' => 'name 2.2',
+                        'disabled' => true
+                    ],
+                ]
+            ],
+        ];
+        $configMock->expects($this->once())->method('getAll')->will($this->returnValue($config));
+        $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', 'getImageSizeX', 'getImageSizeY','__wakeup'];
+        $this->valueMock = $this->getMock('Magento\Catalog\Model\Product\Option', $methods, [], '', false);
+        $this->validator = new \Magento\Catalog\Model\Product\Option\Validator\File(
+            $configMock,
+            $priceConfigMock
+        );
+    }
+
+    public function testIsValidSuccess()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getImageSizeY')->will($this->returnValue(15));
+        $this->assertEmpty($this->validator->getMessages());
+        $this->assertTrue($this->validator->isValid($this->valueMock));
+    }
+
+    public function testIsValidWithNegativeImageSize()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(-10));
+        $this->valueMock->expects($this->never())->method('getImageSizeY');
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+
+    public function testIsValidWithNegativeImageSizeY()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getImageSizeY')->will($this->returnValue(-10));
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/PoolTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/PoolTest.php
new file mode 100644
index 00000000000..cb9ece9ea16
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/PoolTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class PoolTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Validator\Pool
+     */
+    protected $pool;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $defaultValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectValidatorMock;
+
+    protected function setUp()
+    {
+        $this->defaultValidatorMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Option\Validator\DefaultValidator', [], [], '', false
+        );
+        $this->selectValidatorMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Option\Validator\Select', [], [], '', false
+        );
+        $this->pool = new \Magento\Catalog\Model\Product\Option\Validator\Pool(
+            ['default' => $this->defaultValidatorMock, 'select' => $this->selectValidatorMock]
+        );
+    }
+
+    public function testGetSelectValidator()
+    {
+        $this->assertEquals($this->selectValidatorMock, $this->pool->get('select'));
+    }
+
+    public function testGetDefaultValidator()
+    {
+        $this->assertEquals($this->defaultValidatorMock, $this->pool->get('default'));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/SelectTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/SelectTest.php
new file mode 100644
index 00000000000..c762db457bd
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/SelectTest.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class SelectTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Validator\Select
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueMock;
+
+    protected function setUp()
+    {
+        $configMock = $this->getMock('Magento\Catalog\Model\ProductOptions\ConfigInterface');
+        $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price();
+        $config = [
+            [
+                'label' => 'group label 1',
+                'types' => [
+                    [
+                        'label' => 'label 1.1',
+                        'name' => 'name 1.1',
+                        'disabled' => false
+                    ],
+                ]
+            ],
+            [
+                'label' => 'group label 2',
+                'types' => [
+                    [
+                        'label' => 'label 2.2',
+                        'name' => 'name 2.2',
+                        'disabled' => true
+                    ],
+                ]
+            ],
+        ];
+        $configMock->expects($this->once())->method('getAll')->will($this->returnValue($config));
+        $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', '__wakeup', 'getData'];
+        $this->valueMock = $this->getMock('Magento\Catalog\Model\Product\Option', $methods, [], '', false);
+        $this->validator = new \Magento\Catalog\Model\Product\Option\Validator\Select(
+            $configMock,
+            $priceConfigMock
+        );
+    }
+
+
+    /**
+     * @param array $value
+     * @dataProvider isValidSuccessDataProvider
+     */
+    public function testIsValidSuccess($value)
+    {
+        $value = [
+            'price_type' => 'fixed',
+            'price' => '10',
+            'title' => 'Some Title'
+        ];
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->never())->method('getPriceType');
+        $this->valueMock->expects($this->never())->method('getPrice');
+        $this->valueMock->expects($this->any())->method('getData')->with('values')->will($this->returnValue([$value]));
+        $this->assertTrue($this->validator->isValid($this->valueMock));
+        $this->assertEmpty($this->validator->getMessages());
+    }
+
+    public function isValidSuccessDataProvider()
+    {
+        $value = [
+            'price_type' => 'fixed',
+            'price' => '10',
+            'title' => 'Some Title'
+        ];
+
+        $valueWithoutAllData = [
+            'some_data' =>'data'
+        ];
+
+        return [
+            'all_data' => [$value],
+            'not_all_data' => [$valueWithoutAllData]
+        ];
+    }
+
+    public function testIsValidateWithInvalidOptionValues()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->never())->method('getPriceType');
+        $this->valueMock->expects($this->never())->method('getPrice');
+        $this->valueMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('values')
+            ->will($this->returnValue('invalid_data'));
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+
+    public function testIsValidateWithEmptyValues()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->never())->method('getPriceType');
+        $this->valueMock->expects($this->never())->method('getPrice');
+        $this->valueMock->expects($this->any())->method('getData')->with('values')->will($this->returnValue([]));
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+
+    /**
+     * @param string $priceType
+     * @param int $price
+     * @param string|null $title
+     * @dataProvider isValidateWithInvalidDataDataProvider
+     */
+    public function testIsValidateWithInvalidData($priceType, $price, $title)
+    {
+        $value = [
+            'price_type' => $priceType,
+            'price' => $price,
+            'title' => $title
+        ];
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->never())->method('getPriceType');
+        $this->valueMock->expects($this->never())->method('getPrice');
+        $this->valueMock->expects($this->any())->method('getData')->with('values')->will($this->returnValue([$value]));
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+
+    public function isValidateWithInvalidDataDataProvider()
+    {
+        return [
+            'invalid_price' => ['fixed', -10, 'Title'],
+            'invalid_price_type' => ['some_value', '10', 'Title'],
+            'empty_title' => ['fixed', 10, null]
+        ];
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/TextTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/TextTest.php
new file mode 100644
index 00000000000..08e277fd102
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/TextTest.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Validator;
+
+class TextTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Validator\Text
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueMock;
+
+    protected function setUp()
+    {
+        $configMock = $this->getMock('Magento\Catalog\Model\ProductOptions\ConfigInterface');
+        $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price();
+        $config = [
+            [
+                'label' => 'group label 1',
+                'types' => [
+                    [
+                        'label' => 'label 1.1',
+                        'name' => 'name 1.1',
+                        'disabled' => false
+                    ],
+                ]
+            ],
+            [
+                'label' => 'group label 2',
+                'types' => [
+                    [
+                        'label' => 'label 2.2',
+                        'name' => 'name 2.2',
+                        'disabled' => true
+                    ],
+                ]
+            ],
+        ];
+        $configMock->expects($this->once())->method('getAll')->will($this->returnValue($config));
+        $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', '__wakeup', 'getMaxCharacters'];
+        $this->valueMock = $this->getMock('Magento\Catalog\Model\Product\Option', $methods, [], '', false);
+        $this->validator = new \Magento\Catalog\Model\Product\Option\Validator\Text(
+            $configMock,
+            $priceConfigMock
+        );
+    }
+
+    public function testIsValidSuccess()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getMaxCharacters')->will($this->returnValue(10));
+        $this->assertTrue($this->validator->isValid($this->valueMock));
+        $this->assertEmpty($this->validator->getMessages());
+    }
+
+    public function testIsValidWithNegativeMaxCharacters()
+    {
+        $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title'));
+        $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1'));
+        $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed'));
+        $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10));
+        $this->valueMock->expects($this->once())->method('getMaxCharacters')->will($this->returnValue(-10));
+        $messages = [
+            'option values' => 'Invalid option value'
+        ];
+        $this->assertFalse($this->validator->isValid($this->valueMock));
+        $this->assertEquals($messages, $this->validator->getMessages());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Resource/Product/Indexer/Eav/SourceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Resource/Product/Indexer/Eav/SourceTest.php
deleted file mode 100644
index bc4c977b81d..00000000000
--- a/dev/tests/unit/testsuite/Magento/Catalog/Model/Resource/Product/Indexer/Eav/SourceTest.php
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-/**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
- */
-
-namespace Magento\Catalog\Model\Resource\Product\Indexer\Eav;
-
-use \Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
-
-class SourceTest extends \PHPUnit_Framework_TestCase
-{
-    /** @var \Magento\Catalog\Model\Resource\Product\Indexer\Eav\Source */
-    protected $source;
-
-    /** @var ObjectManagerHelper */
-    protected $objectManagerHelper;
-
-    /** @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject */
-    protected $resource;
-
-    /** @var \Magento\Eav\Model\Config|\PHPUnit_Framework_MockObject_MockObject */
-    protected $config;
-
-    /** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $managerInterface;
-
-    /** @var \Magento\Catalog\Model\Resource\Helper|\PHPUnit_Framework_MockObject_MockObject */
-    protected $helper;
-
-    protected function setUp()
-    {
-        $this->resource = $this->getMock(
-            'Magento\Framework\App\Resource',
-            ['getConnection', 'getTableName'],
-            [],
-            '',
-            false
-        );
-        $this->config = $this->getMock('Magento\Eav\Model\Config', [], [], '', false);
-        $this->managerInterface = $this->getMock('Magento\Framework\Event\ManagerInterface');
-        $this->helper = $this->getMock('Magento\Catalog\Model\Resource\Helper', [], [], '', false);
-
-        $this->objectManagerHelper = new ObjectManagerHelper($this);
-        $this->source = $this->objectManagerHelper->getObject(
-            'Magento\Catalog\Model\Resource\Product\Indexer\Eav\Source',
-            [
-                'resource' => $this->resource,
-                'eavConfig' => $this->config,
-                'eventManager' => $this->managerInterface,
-                'resourceHelper' => $this->helper
-            ]
-        );
-    }
-
-    /**
-     * Test `reindexEntity` method
-     */
-    public function testReindexEntities()
-    {
-        $query = $this->getMockBuilder('PDO_Statement')->setMethods(['fetch'])->disableOriginalConstructor()->getMock();
-        $query->expects($this->any())->method('fetch')->will($this->returnValue([]));
-
-        $select = $this->getMockBuilder('\Magento\Framework\DB\Select')->setMethods([
-                'select', 'from', 'where', 'join', 'joinLeft', 'joinInner',
-                'assemble', 'columns', 'insertFromSelect', 'query', 'deleteFromSelect'
-            ])->disableOriginalConstructor()->getMock();
-        $select->expects($this->any())->method('from')->withAnyParameters()->will($this->returnSelf());
-        $select->expects($this->any())->method('where')->will($this->returnSelf());
-        $select->expects($this->any())->method('join')->will($this->returnSelf());
-        $select->expects($this->any())->method('query')->will($this->returnValue($query));
-        $select->expects($this->any())->method('columns')->will($this->returnSelf());
-        $select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
-        $select->expects($this->any())->method('insertFromSelect')->will($this->returnSelf());
-        $select->expects($this->any())->method('deleteFromSelect')->with('catalog_product_index_eav_tmp')
-            ->will($this->returnValue($query));
-        $select->expects($this->once())->method('joinInner')
-            ->with(
-                array('d2' => 'catalog_product_entity_int'),
-                'd.entity_id = d2.entity_id AND d2.attribute_id = 96 AND d2.value = 1 AND d.store_id = 0'
-            )->will($this->returnSelf());
-
-        $adapter = $this->getMockBuilder('Magento\Framework\DB\Adapter\Pdo\Mysql')
-            ->setMethods([
-                'select', 'delete', 'beginTransaction', 'getTransactionLevel', 'fetchCol', 'query', 'quoteInto',
-                'describeTable', 'commit'
-            ])->disableOriginalConstructor()->getMock();
-        $adapter->expects($this->any())->method('select')->will($this->returnValue($select));
-        $adapter->expects($this->any())->method('getTransactionLevel')->will($this->returnValue(1));
-        $adapter->expects($this->any())->method('fetchCol')->will($this->returnValue([1]));
-        $adapter->expects($this->any())->method('query')->will($this->returnValue($query));
-        $adapter->expects($this->any())->method('describeTable')->will($this->returnValue([]));
-        $adapter->expects($this->any())->method('commit')->will($this->returnValue(null));
-
-
-        $this->resource->expects($this->any())->method('getConnection')->with('core_write')
-            ->will($this->returnValue($adapter));
-        $this->resource->expects($this->at(4))->method('getTableName')->with('catalog_product_index_eav_tmp')
-            ->will($this->returnArgument(0));
-        $this->resource->expects($this->at(8))->method('getTableName')->with('catalog_product_entity_int')
-            ->will($this->returnArgument(0));
-
-
-        $attribute = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute')->disableOriginalConstructor()
-            ->setMethods(['getId', '__sleep', '__wakeup', 'getBackend', 'getTable', 'isScopeGlobal'])->getMock();
-        $attribute->expects($this->once())->method('getId')->will($this->returnValue(96));
-        $attribute->expects($this->any())->method('getBackend')->will($this->returnSelf());
-        $attribute->expects($this->any())->method('getTable')->will($this->returnValue('some_table'));
-        $attribute->expects($this->any())->method('isScopeGlobal')->will($this->returnValue(true));
-        $this->config->expects($this->any())->method('getAttribute')->will($this->returnValue($attribute));
-
-        $this->source->reindexEntities([1]);
-    }
-}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/UrlTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/UrlTest.php
index 664200410d1..332aac74feb 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Model/UrlTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/UrlTest.php
@@ -30,15 +30,179 @@ class UrlTest extends \PHPUnit_Framework_TestCase
      */
     protected $_model;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_resourceModel;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_urlFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_storeModel;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_productModel;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_categoryModel;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_categoryFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_categoryHelper;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_rewriteModel;
+
     /**
      * @var \Magento\TestFramework\Helper\ObjectManager
      */
     protected $_objectManager;
 
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     protected function setUp()
     {
+        $this->_resourceModel = $this->getMock(
+            '\Magento\Catalog\Model\Resource\Url',
+            array(
+                '__wakeup',
+                'getStores',
+                'clearStoreInvalidRewrites',
+                'getProductsByStore',
+                'prepareRewrites',
+                'getCategories',
+                'getCategory',
+                'getCategoryModel',
+                'loadCategoryChilds',
+                'checkRequestPaths',
+                'saveRewrite',
+                'clearCategoryProduct',
+                'getCategoryParentPath',
+                'findFinalTargetPath',
+                'deleteRewriteRecord',
+                'saveCategoryAttribute',
+                'getProductsByCategory',
+                'deleteCategoryProductStoreRewrites'
+            ),
+            array(),
+            '',
+            false
+        );
+        $this->_urlFactory = $this->getMock(
+            '\Magento\Catalog\Model\Resource\UrlFactory',
+            array(
+                'create',
+                'formatUrlKey',
+                'getUrlPath'
+            )
+        );
+        $this->_storeModel = $this->getMock(
+            '\Magento\Store\Model\Store',
+            array(
+                '__wakeup',
+                'getId',
+                'getRootCategoryId'
+            ),
+            array(),
+            '',
+            false
+        );
+        $this->_productModel = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            array(
+                '__wakeup',
+                'getCategoryIds',
+                'getId',
+                'getResource',
+                'getUrlPath'
+            ),
+            array(),
+            '',
+            false
+        );
+        $this->_categoryModel = $this->getMock(
+            'Magento\Catalog\Model\Category',
+            array(
+                '__wakeup',
+                'getId',
+                'getStoreId',
+                'getChilds',
+                'getAllChilds',
+                'formatUrlKey',
+                'getUrlKey',
+                'getCategoryUrlPath',
+                'getName'
+            ),
+            array(),
+            '',
+            false
+        );
+        $this->_categoryFactory = $this->getMock('\Magento\Catalog\Model\CategoryFactory');
+        $this->_categoryHelper = $this->getMock(
+            'Magento\Catalog\Helper\Category',
+            array(
+                'getCategoryUrlPath',
+                'getCategoryUrlSuffix'
+            ),
+            array(),
+            '',
+            false
+        );
+        $this->_rewriteModel = $this->getMock(
+            'Magento\UrlRewrite\Model\UrlRewrite',
+            array(
+                '__wakeup',
+                'getRequestPath'
+            ),
+            array(),
+            '',
+            false
+        );
+
         $this->_objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $this->_model = $this->_objectManager->getObject('Magento\Catalog\Model\Url');
+        $this->_model = $this->_objectManager->getObject(
+            'Magento\Catalog\Model\Url',
+            array(
+                'urlFactory' => $this->_urlFactory,
+                'catalogCategoryFactory' => $this->_categoryFactory,
+                'catalogCategory' => $this->_categoryHelper
+            )
+        );
+
+        $this->_urlFactory->expects($this->any())->method('create')
+            ->will($this->returnValue($this->_resourceModel));
+        $this->_resourceModel->expects($this->any())->method('getCategory')
+            ->will($this->returnValue($this->_categoryModel));
+        $this->_resourceModel->expects($this->any())->method('loadCategoryChilds')
+            ->will($this->returnValue($this->_categoryModel));
+        $this->_resourceModel->expects($this->any())->method('saveRewrite')
+            ->will($this->returnSelf());
+        $this->_categoryModel->expects($this->any())->method('getId')
+            ->will($this->returnValue(1));
+        $this->_categoryModel->expects($this->any())->method('getStoreId')
+            ->will($this->returnValue(1));
+        $this->_categoryModel->expects($this->any())->method('getChilds')
+            ->will($this->returnSelf());
+        $this->_storeModel->expects($this->any())->method('getId')
+            ->will($this->returnValue(1));
     }
 
     public function testGenerateUniqueIdPath()
@@ -48,4 +212,102 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $this->assertContains('_', $path);
         $this->assertNotEquals($path, $this->_model->generateUniqueIdPath());
     }
+
+    public function testRefreshRewrites()
+    {
+        $rewrite = array('category/1' => $this->_rewriteModel);
+        $validatedPath = 'validated_path.html';
+
+        $this->_urlFactory->expects($this->any())->method('formatUrlKey')
+            ->will($this->returnValue('url_formatted'));
+        $this->_urlFactory->expects($this->any())->method('getUrlPath')
+            ->will($this->returnValue($validatedPath));
+        $this->_resourceModel->expects($this->any())->method('prepareRewrites')
+            ->will($this->returnValue($rewrite));
+        $this->_resourceModel->expects($this->at(0))->method('getStores')
+            ->will($this->returnValue(array($this->_storeModel)));
+        $this->_resourceModel->expects($this->any())->method('getStores')
+            ->will($this->returnValue($this->_storeModel));
+        $this->_resourceModel->expects($this->once())->method('clearStoreInvalidRewrites')
+            ->will($this->returnSelf());
+        $this->_resourceModel->expects($this->at(14))->method('getProductsByStore')
+            ->will($this->returnValue(null));
+        $this->_resourceModel->expects($this->any())->method('getProductsByStore')
+            ->will($this->returnValue(array($this->_productModel)));
+        $this->_resourceModel->expects($this->any())->method('getCategories')
+            ->will($this->returnValue(array($this->_categoryModel)));
+        $this->_resourceModel->expects($this->once())->method('checkRequestPaths')
+            ->will($this->returnValue($validatedPath));
+        $this->_resourceModel->expects($this->once())->method('clearCategoryProduct')
+            ->will($this->returnSelf());
+        $this->_productModel->expects($this->any())->method('getCategoryIds')
+            ->will($this->returnValue(array(1)));
+        $this->_productModel->expects($this->any())->method('getId')
+            ->will($this->returnValue(1));
+        $this->_productModel->expects($this->any())->method('getResource')
+            ->will($this->returnValue($this->_resourceModel));
+        $this->_productModel->expects($this->once())->method('getUrlPath')
+            ->will($this->returnValue($validatedPath));
+        $this->_storeModel->expects($this->any())->method('getRootCategoryId')
+            ->will($this->returnValue(1));
+
+        $this->_model->refreshRewrites();
+    }
+
+    /**
+     * @param string $targetPathExecute
+     * @param bool $changeRequestPath
+     *
+     * @dataProvider refreshcategoryRewriteDataProvider
+     */
+    public function testRefreshCategoryRewrite($targetPathExecute, $changeRequestPath)
+    {
+        $categoryId = 1;
+        $rewrite = array('category/1' => $this->_rewriteModel);
+
+        $this->_resourceModel->expects($this->once())->method('prepareRewrites')
+            ->will($this->returnValue($rewrite));
+        $this->_resourceModel->expects($this->at(0))->method('getStores')
+            ->will($this->returnValue(array($this->_storeModel)));
+        $this->_resourceModel->expects($this->once())->method('getStores')
+            ->will($this->returnValue($this->_storeModel));
+        $this->_resourceModel->expects($this->any())->method('getCategoryModel')
+            ->will($this->returnValue($this->_categoryModel));
+        $this->_resourceModel->expects($this->once())->method('getCategoryParentPath')
+            ->will($this->returnValue('parent_path'));
+        $this->_resourceModel->expects($this->any())->method('deleteRewriteRecord')
+            ->will($this->returnSelf());
+        $this->_resourceModel->expects($this->any())->method('saveCategoryAttribute')
+            ->will($this->returnSelf());
+        $this->_resourceModel->expects($this->any())->method('getProductsByCategory')
+            ->will($this->returnValue(null));
+        $this->_resourceModel->expects($this->any())->method('deleteCategoryProductStoreRewrites')
+            ->will($this->returnSelf());
+        $this->_resourceModel->expects($this->$targetPathExecute())->method('findFinalTargetPath')
+            ->will($this->returnValue('category/1'));
+        $this->_categoryModel->expects($this->any())->method('getAllChilds')
+            ->will($this->returnValue(array($this->_categoryModel)));
+        $this->_categoryModel->expects($this->any())->method('formatUrlKey')
+            ->will($this->returnValue('url_formatted'));
+        $this->_categoryModel->expects($this->any())->method('getUrlKey')
+            ->will($this->returnValue('url_key'));
+        $this->_categoryModel->expects($this->any())->method('getCategoryUrlPath')
+            ->will($this->returnValue('category_parent_path'));
+        $this->_categoryHelper->expects($this->once())->method('getCategoryUrlPath')
+            ->will($this->returnValue('category_parent_path'));
+        $this->_categoryHelper->expects($this->once())->method('getCategoryUrlSuffix')
+            ->will($this->returnValue('suffics'));
+        $this->_rewriteModel->expects($this->once())->method('getRequestPath')
+            ->will($this->returnValue('category_parent_pathurl_formatted-1suffics'));
+
+        $this->_model->refreshCategoryRewrite($categoryId, '', true, $changeRequestPath);
+    }
+
+    public function refreshcategoryRewriteDataProvider()
+    {
+        return array(
+            array('once', true),
+            array('never', false)
+        );
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/ConverterTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/ConverterTest.php
new file mode 100644
index 00000000000..13ae317e89b
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/ConverterTest.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option;
+
+class ConverterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Converter
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $metadataConverterMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+
+    protected function setUp()
+    {
+        $this->metadataConverterMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface'
+        );
+        $this->optionMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false
+        );
+
+        $this->service = new Converter($this->metadataConverterMock);
+    }
+
+    public function testConvert()
+    {
+        $this->optionMock->expects($this->any())->method('getOptionId')->will($this->returnValue('123456'));
+        $this->optionMock->expects($this->any())->method('getTitle')->will($this->returnValue('Some Title'));
+        $this->optionMock->expects($this->any())->method('getType')->will($this->returnValue('Type'));
+        $this->optionMock->expects($this->any())->method('getSortOrder')->will($this->returnValue('12'));
+        $this->optionMock->expects($this->any())->method('getIsRequire')->will($this->returnValue(true));
+        $options = [
+            'option_id' => '123456',
+            'title' => 'Some Title',
+            'type' => 'Type',
+            'sort_order' => '12',
+            'is_require' => true
+        ];
+        $this->metadataConverterMock
+            ->expects($this->once())
+            ->method('convert')
+            ->with($this->optionMock)
+            ->will($this->returnValue($options));
+        $this->assertEquals($options, $this->service->convert($this->optionMock));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/CompositeTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/CompositeTest.php
new file mode 100644
index 00000000000..c9a8371352d
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/CompositeTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface;
+
+class CompositeTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Composite
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $converterMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $converterSelectMock;
+
+    protected function setUp()
+    {
+        $this->converterMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ConverterInterface'
+        );
+        $this->converterSelectMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->model = new Composite(['default' => $this->converterMock, 'select' => $this->converterSelectMock]);
+    }
+
+    public function testConverterWithSelectType()
+    {
+        $this->optionMock =
+            $this->getMock(
+                '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option',
+                [],
+                [],
+                '',
+                false
+            );
+        $this->optionMock->expects($this->once())->method('getType')->will($this->returnValue('select'));
+        $this->converterSelectMock
+            ->expects($this
+            ->once())
+            ->method('convert')
+            ->with($this->optionMock)
+            ->will($this->returnValue('Expected Result'));
+        $this->assertEquals('Expected Result', $this->model->convert($this->optionMock));
+    }
+
+    public function testConverterWithDefaultType()
+    {
+        $this->optionMock =
+            $this->getMock(
+                '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option',
+                [],
+                [],
+                '',
+                false
+            );
+        $this->optionMock->expects($this->once())->method('getType')->will($this->returnValue('other'));
+        $this->converterMock
+            ->expects($this
+            ->once())
+            ->method('convert')
+            ->with($this->optionMock)
+            ->will($this->returnValue('Expected Result'));
+        $this->assertEquals('Expected Result', $this->model->convert($this->optionMock));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverterTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverterTest.php
new file mode 100644
index 00000000000..5bd3a254a69
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverterTest.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class DefaultConverterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var DefaultConverter
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMetadata;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeValueMock;
+
+    protected function setUp()
+    {
+        $this->optionMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->attributeValueMock = $this->getMock(
+            '\Magento\Framework\Service\Data\Eav\AttributeValue',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->model = new DefaultConverter();
+    }
+
+    public function testConverter()
+    {
+        $this->optionMetadata = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->optionMock
+            ->expects($this->once())
+            ->method('getMetadata')
+            ->will($this->returnValue(array($this->optionMetadata)));
+        $this->optionMetadata->expects($this->once())->method('getPrice')->will($this->returnValue(100.12));
+        $this->optionMetadata->expects($this->once())->method('getPriceType')->will($this->returnValue('USD'));
+        $this->optionMetadata->expects($this->once())->method('getSku')->will($this->returnValue('product_sku'));
+        $this->optionMetadata
+            ->expects($this->once())
+            ->method('getCustomAttributes')
+            ->will($this->returnValue(array($this->attributeValueMock)));
+        $this->attributeValueMock
+            ->expects($this->once())
+            ->method('getAttributeCode')
+            ->will($this->returnValue('attribute'));
+        $this->attributeValueMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->will($this->returnValue('value'));
+        $expectedOutput = array(
+            Metadata::PRICE => 100.12,
+            Metadata::PRICE_TYPE => 'USD',
+            Metadata::SKU => 'product_sku',
+            'attribute' => 'value'
+        );
+        $this->assertEquals($expectedOutput, $this->model->convert($this->optionMock));
+    }
+
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/SelectTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/SelectTest.php
new file mode 100644
index 00000000000..40a25343f17
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/SelectTest.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class SelectTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Select
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMetadataMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeValueMock;
+
+    protected function setUp()
+    {
+        $this->optionMock =
+            $this->getMock('\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false);
+        $this->optionMetadataMock =
+            $this->getMock('\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata', [], [], '', false);
+        $this->attributeValueMock =
+            $this->getMock('\Magento\Framework\Service\Data\Eav\AttributeValue', [], [], '', false);
+        $this->model = new Select();
+    }
+
+    public function testConverter()
+    {
+        $this->optionMock
+            ->expects($this->any())
+            ->method('getMetadata')
+            ->will($this->returnValue(array('select' => $this->optionMetadataMock)));
+        $this->optionMetadataMock->expects($this->any())->method('getPrice')->will($this->returnValue(99.99));
+        $this->optionMetadataMock->expects($this->any())->method('getPriceType')->will($this->returnValue('USD'));
+        $this->optionMetadataMock->expects($this->any())->method('getSku')->will($this->returnValue('product_sku'));
+        $this->optionMetadataMock
+            ->expects($this->any())
+            ->method('getOptionTypeId')
+            ->will($this->returnValue('value option_type_id'));
+        $this->optionMetadataMock
+            ->expects($this->any())
+            ->method('getCustomAttributes')
+            ->will($this->returnValue(array($this->attributeValueMock)));
+        $this->attributeValueMock
+            ->expects($this->once())
+            ->method('getAttributeCode')
+            ->will($this->returnValue('attribute_code'));
+        $this->attributeValueMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->will($this->returnValue('attribute_value'));
+        $expectedValues= array(
+            'values' => array(
+                '0' => array(
+                    Metadata::PRICE => 99.99,
+                    Metadata::PRICE_TYPE => 'USD',
+                    Metadata::SKU => 'product_sku',
+                    'attribute_code' => 'attribute_value'
+                )
+        ));
+        $this->assertEquals($expectedValues, $this->model->convert($this->optionMock));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReaderTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReaderTest.php
new file mode 100644
index 00000000000..dfa5c16c973
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReaderTest.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class DefaultReaderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    /**
+     * @var DefaultReader
+     */
+    protected $service;
+
+    protected function setUp()
+    {
+        $this->valueBuilderMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\MetadataBuilder', [], [], '', false
+        );
+        $this->optionMock = $this->getMock(
+            '\Magento\Catalog\Model\Product\Option', ['getPrice', 'getPriceType', 'getSku', '__wakeup'], [], '', false
+        );
+        $this->service = new DefaultReader($this->valueBuilderMock);
+    }
+
+    public function testRead()
+    {
+        $this->optionMock->expects($this->once())->method('getPrice')->will($this->returnValue('10'));
+        $this->optionMock->expects($this->once())->method('getPriceType')->will($this->returnValue('USD'));
+        $this->optionMock->expects($this->once())->method('getSku')->will($this->returnValue('product_sku'));
+        $fields = [
+            Metadata::PRICE => '10',
+            Metadata::PRICE_TYPE => 'USD' ,
+            Metadata::SKU => 'product_sku'
+        ];
+        $this->valueBuilderMock->expects($this->once())
+            ->method('populateWithArray')
+            ->with($fields)
+            ->will($this->returnValue($this->valueBuilderMock));
+        $this->valueBuilderMock->expects($this->once())->method('create')->will($this->returnValue('Expected value'));
+        $this->assertEquals(array('Expected value'), $this->service->read($this->optionMock));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/SelectTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/SelectTest.php
new file mode 100644
index 00000000000..e03e065c519
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/SelectTest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader;
+
+use \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class SelectTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Select
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $valueBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    protected function setUp()
+    {
+        $this->valueBuilderMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\MetadataBuilder', [], [], '', false
+        );
+        $this->optionMock = $this->getMock(
+            '\Magento\Catalog\Model\Product\Option', [], [], '', false
+        );
+        $this->service = new Select($this->valueBuilderMock);
+    }
+
+    public function testRead()
+    {
+        $valueMock = $this->getMock(
+            '\Magento\Catalog\Model\Product\Option',
+            ['getPrice', 'getPriceType', 'getSku', 'getTitle', 'getSortOrder', 'getId', '__wakeup'],
+            [],
+            '',
+            false
+        );
+        $this->optionMock->expects($this->any())->method('getValues')->will($this->returnValue(array($valueMock)));
+        $valueMock->expects($this->once())->method('getPrice')->will($this->returnValue('35'));
+        $valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('USD'));
+        $valueMock->expects($this->once())->method('getSku')->will($this->returnValue('product_sku'));
+        $valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('Some Title'));
+        $valueMock->expects($this->once())->method('getSortOrder')->will($this->returnValue('0'));
+        $valueMock->expects($this->once())->method('getId')->will($this->returnValue('12345678'));
+        $fields = [
+            Metadata::PRICE => '35',
+            Metadata::PRICE_TYPE => 'USD' ,
+            Metadata::SKU => 'product_sku',
+            Metadata::TITLE => 'Some Title',
+            Metadata::SORT_ORDER => '0',
+            Metadata::OPTION_TYPE_ID => '12345678'
+        ];
+        $this->valueBuilderMock
+            ->expects($this->any())->method('populateWithArray')
+            ->with($fields)
+            ->will($this->returnValue($this->valueBuilderMock));
+        $this->valueBuilderMock->expects($this->once())->method('create')->will($this->returnValue($fields));
+        $this->assertEquals(array($fields), $this->service->read($this->optionMock));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderTest.php
new file mode 100644
index 00000000000..5b3d0eb68e2
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderTest.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+use Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata;
+
+class ReaderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader
+     */
+    protected $reader;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $defaultReaderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectReaderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    protected function setUp()
+    {
+        $this->defaultReaderMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface');
+        $this->selectReaderMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface');
+        $this->optionMock =
+            $this->getMock('Magento\Catalog\Model\Product\Option', ['getType', '__wakeup'], [], '', false);
+        $this->reader = new \Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader(
+            [
+                'default' => $this->defaultReaderMock,
+                'select' => $this->selectReaderMock
+            ]
+        );
+    }
+
+    public function testReadOptionWithTypeText()
+    {
+        $this->optionMock->expects($this->once())->method('getType')->will($this->returnValue('text'));
+        $this->defaultReaderMock->expects($this->once())->method('read')->with($this->optionMock);
+        $this->reader->read($this->optionMock);
+    }
+
+    public function testReadOptionWithTypeSelect()
+    {
+        $this->optionMock->expects($this->once())->method('getType')->will($this->returnValue('select'));
+        $this->selectReaderMock->expects($this->once())->method('read')->with($this->optionMock);
+        $this->reader->read($this->optionMock);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceTest.php
new file mode 100644
index 00000000000..49fcb063236
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceTest.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+class ReadServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ReadService
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionTypeBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMetadataReaderMock;
+
+    protected function setUp()
+    {
+        $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
+
+        $this->configMock = $this->getMock('Magento\Catalog\Model\ProductOptions\ConfigInterface');
+        $this->optionTypeBuilderMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionTypeBuilder',
+            [],
+            [],
+            '',
+            false
+        );
+
+        $this->productRepositoryMock = $this->getMock('Magento\Catalog\Model\ProductRepository', [], [], '', false);
+
+        $this->optionBuilderMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionBuilder', [], [], '', false);
+        $this->optionMetadataReaderMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface');
+        $this->service = $helper->getObject(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\ReadService',
+            [
+                'productOptionConfig' => $this->configMock,
+                'optionTypeBuilder' => $this->optionTypeBuilderMock,
+                'optionBuilder' => $this->optionBuilderMock,
+                'productRepository' => $this->productRepositoryMock,
+                'optionMetadataReader' => $this->optionMetadataReaderMock
+            ]
+        );
+    }
+
+    public function testGetTypes()
+    {
+        $config = [
+            [
+                'label' => 'group label 1',
+                'types' => [
+                    [
+                        'label' => 'label 1.1',
+                        'name' => 'name 1.1',
+                        'disabled' => false
+                    ],
+                ]
+            ],
+            [
+                'label' => 'group label 2',
+                'types' => [
+                    [
+                        'label' => 'label 2.2',
+                        'name' => 'name 2.2',
+                        'disabled' => true
+                    ],
+                ]
+            ],
+        ];
+
+        $this->configMock->expects($this->once())->method('getAll')->will($this->returnValue($config));
+
+        $expectedConfig = [
+            'label' => 'label 1.1',
+            'code' => 'name 1.1',
+            'group' => 'group label 1'
+        ];
+
+        $object = $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionType', [], [], '', false);
+        $this->optionTypeBuilderMock->expects($this->once())
+            ->method('populateWithArray')
+            ->with($expectedConfig)
+            ->will($this->returnSelf());
+
+        $this->optionTypeBuilderMock->expects($this->once())->method('create')->will($this->returnValue($object));
+
+        $this->assertEquals([$object], $this->service->getTypes());
+    }
+
+    public function testGetList()
+    {
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
+        $this->productRepositoryMock
+            ->expects($this->once())
+            ->method('get')
+            ->with('product_sku')
+            ->will($this->returnValue($productMock));
+        $value = [
+            'price_type' => 'fixed',
+            'sku' => 'sku1',
+            'max_characters' => 10
+        ];
+        $options[] = [
+            Data\Option::OPTION_ID => 10,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+            Data\Option::METADATA => $value
+        ];
+        $methods = array('getId', 'getTitle', 'getType', 'getIsRequire', 'getSortOrder', '__wakeup');
+        $optionMock = $this->getMock('\Magento\Catalog\Model\Product\Option', $methods, [], '', false);
+        $optionData = $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false);
+        $productMock
+            ->expects($this->once())
+            ->method('getOptions')
+            ->will($this->returnValue(array($optionMock)));
+        $optionMock->expects($this->once())->method('getId')->will($this->returnValue(10));
+        $optionMock->expects($this->once())->method('getTitle')->will($this->returnValue('Some title'));
+        $optionMock->expects($this->once())->method('getType')->will($this->returnValue('text'));
+        $optionMock->expects($this->once())->method('getIsRequire')->will($this->returnValue(true));
+        $optionMock->expects($this->once())->method('getSortOrder')->will($this->returnValue(10));
+        $this->optionMetadataReaderMock
+            ->expects($this->once())
+            ->method('read')
+            ->with($optionMock)
+            ->will($this->returnValue($value));
+        $this->optionBuilderMock
+            ->expects($this->once())
+            ->method('populateWithArray')
+            ->with($options[0])
+            ->will($this->returnSelf());
+        $this->optionBuilderMock->expects($this->once())->method('create')->will($this->returnValue($optionData));
+
+        $this->assertEquals(array($optionData), $this->service->getList('product_sku'));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceTest.php
new file mode 100644
index 00000000000..9527f570afb
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceTest.php
@@ -0,0 +1,402 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\CustomOptions;
+
+class WriteServiceTest extends \PHPUnit_Framework_TestCase
+{
+
+    const PRODUCT_SKU = 'simple';
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionTypeBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionConverterMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $factoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMetadataReaderMock;
+
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\CustomOptions\WriteService
+     */
+    protected $writeService;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionMock;
+
+    protected function setUp()
+    {
+        $this->optionTypeBuilderMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader',
+            [],
+            [],
+            '',
+            false
+        );
+
+        $this->repositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository',
+            [],
+            [],
+            '',
+            false
+        );
+        $methods = [
+            'getOptions',
+            'getOptionById',
+            'setProductOptions',
+            'setHasOptions',
+            'save',
+            'load',
+            'reset',
+            'getId',
+            '__wakeup',
+            'setCanSaveCustomOptions'
+        ];
+        $this->productMock = $this->getMock('Magento\Catalog\Model\Product', $methods, [], '', false);
+
+        $this->optionConverterMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Converter', [], [], '', false);
+
+        $this->repositoryMock
+            ->expects($this->once())
+            ->method('get')
+            ->with(self::PRODUCT_SKU)
+            ->will($this->returnValue($this->productMock));
+
+        $this->optionBuilderMock =
+            $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\OptionBuilder', [], [], '', false);
+
+        $this->optionMetadataReaderMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\ReaderInterface'
+        );
+
+        $this->factoryMock = $this->getMock(
+            '\Magento\Catalog\Model\Product\OptionFactory', ['create'], [], '', false, false
+        );
+
+        $this->optionMock = $this->getMock(
+            '\Magento\Catalog\Model\Product\Option',
+            ['__sleep', '__wakeup', 'getId', 'getTitle', 'getType', 'delete', 'getIsRequire', 'getSortOrder', 'load'],
+            [],
+            '',
+            false,
+            false
+        );
+
+        $this->factoryMock->expects($this->any())->method('create')->will($this->returnValue($this->optionMock));
+
+        $this->writeService = new \Magento\Catalog\Service\V1\Product\CustomOptions\WriteService(
+            $this->optionBuilderMock,
+            $this->optionConverterMock,
+            $this->repositoryMock,
+            $this->optionMetadataReaderMock,
+            $this->factoryMock
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage No such entity with optionId = 10
+     */
+    public function testRemoveFromProductWithoutOptions()
+    {
+        $this->optionMock->expects($this->once())->method('load')->with(10);
+        $this->productMock->expects($this->once())->method('getOptions')->will($this->returnValue(array()));
+        $this->productMock->expects($this->never())->method('getOptionById');
+        $this->writeService->remove(self::PRODUCT_SKU, 10);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage No such entity with optionId = 10
+     */
+    public function testRemoveNotExistingOption()
+    {
+        $options[1] = [
+            Data\Option::OPTION_ID => 10,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+        ];
+        $this->productMock->expects($this->once())->method('getOptions')->will($this->returnValue($options));
+        $this->optionMock->expects($this->never())->method('delete');
+        $this->writeService->remove(self::PRODUCT_SKU, 10);
+    }
+
+    public function testSuccessRemove()
+    {
+        $this->optionMock->expects($this->once())->method('load')->with(10);
+        $this->optionMock->expects($this->any())->method('getId')->will($this->returnValue(10));
+
+        $this->productMock
+            ->expects($this->once())
+            ->method('getOptions')
+            ->will($this->returnValue([10 => $this->optionMock]));
+
+        $this->optionMock->expects($this->once())->method('delete');
+        $this->productMock->expects($this->once())->method('setHasOptions')->with(false);
+        $this->productMock->expects($this->once())->method('save');
+
+        $this->assertTrue($this->writeService->remove(self::PRODUCT_SKU, 10));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testCanNotRemove()
+    {
+        $this->optionMock->expects($this->once())->method('load')->with(10);
+        $this->optionMock->expects($this->any())->method('getId')->will($this->returnValue(10));
+
+        $this->productMock
+            ->expects($this->once())
+            ->method('getOptions')
+            ->will($this->returnValue([10 => $this->optionMock]));
+
+        $this->optionMock->expects($this->once())->method('delete');
+        $this->productMock->expects($this->once())->method('setHasOptions')->with(false);
+        $this->productMock->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
+        $this->writeService->remove(self::PRODUCT_SKU, 10);
+    }
+
+    public function testRemoveMetadata()
+    {
+        $optionId = 231;
+        $optionDataMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option',
+            ['getValues'],
+            [],
+            '',
+            false
+        );
+
+        $optionData = [
+            'option_id' => $optionId,
+            'values' => [
+                ['option_type_id' => 1],
+                ['option_type_id' => 2],
+            ],
+        ];
+        $updatedData = $optionData;
+        $updatedData['values'][] = ['option_type_id' => 939, 'is_delete' => 1];
+
+        $metaDataMock1 = $this->getMock('\Magento\Catalog\Model\Product\Option\Value', [], [], '', false);
+        $metaDataMock2 = $this->getMock('\Magento\Catalog\Model\Product\Option\Value', [], [], '', false);
+        $metaDataMock3 = $this->getMock('\Magento\Catalog\Model\Product\Option\Value', [], [], '', false);
+        $map1 = [
+            ['option_type_id', null, 1],
+            ['', null, ['option_type_id' => 1]],
+        ];
+        $map2 = [
+            ['option_type_id', null, 2],
+            ['', null, ['option_type_id' => 2]],
+        ];
+        $map3 = [
+            ['option_type_id', null, 939],
+            ['', null, ['option_type_id' => 939, 'is_delete' => 1]],
+        ];
+
+        $originalValues = [$metaDataMock1, $metaDataMock2, $metaDataMock3];
+
+
+        $this->optionConverterMock->expects($this->once())
+            ->method('convert')
+            ->with($optionDataMock)
+            ->will($this->returnValue($optionData));
+        $this->productMock->expects($this->exactly(2))
+            ->method('getOptionById')
+            ->will($this->returnValue($optionDataMock));
+        $optionDataMock->expects($this->once())->method('getValues')->will($this->returnValue($originalValues));
+
+        // preparation for markValuesForRemoval()
+        $metaDataMock1->expects($this->any())->method('getData')->will($this->returnValueMap($map1));
+        $metaDataMock2->expects($this->any())->method('getData')->will($this->returnValueMap($map2));
+        $metaDataMock3->expects($this->any())->method('getData')->will($this->returnValueMap($map3));
+        $metaDataMock3->expects($this->once())->method('setData')->with('is_delete', 1);
+
+        // update()
+        $this->productMock->expects($this->once())->method('setCanSaveCustomOptions')->with(true);
+        $this->productMock->expects($this->once())->method('setProductOptions')->with([$updatedData]);
+        $this->productMock->expects($this->once())->method('save');
+
+        $this->assertTrue($this->writeService->update(self::PRODUCT_SKU, $optionId, $optionDataMock));
+    }
+
+    public function testAdd()
+    {
+        $optionData = $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false);
+        $convertedOptions =  [
+            Data\Option::OPTION_ID => null,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+            'price_type' => 'fixed',
+            'sku' => 'sku1',
+            'max_characters' => 10
+        ];
+        $this->optionConverterMock
+            ->expects($this->once())
+            ->method('convert')
+            ->with($optionData)
+            ->will($this->returnValue($convertedOptions));
+
+        $existingOptions = [1 => null, 2 => null];
+        $currentOptions = [1 => null, 2 => null, 10 => $this->optionMock];
+
+        $this->productMock->expects($this->at(2))
+            ->method('getOptions')->will($this->returnValue($existingOptions));
+        $this->productMock->expects($this->at(7))
+            ->method('getOptions')->will($this->returnValue($currentOptions));
+
+        $this->productMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->productMock->expects($this->once())->method('reset');
+        $this->productMock->expects($this->once())->method('load')->with(1);
+
+        $this->productMock->expects($this->once())->method('setCanSaveCustomOptions')->with(true);
+        $this->productMock->expects($this->once())->method('setProductOptions')->with([$convertedOptions]);
+        $this->productMock->expects($this->once())->method('save');
+
+        $this->optionMock->expects($this->once())->method('getId')->will($this->returnValue(10));
+        $this->optionMock->expects($this->once())->method('getTitle')->will($this->returnValue('Some title'));
+        $this->optionMock->expects($this->once())->method('getType')->will($this->returnValue('text'));
+        $this->optionMock->expects($this->once())->method('getIsRequire')->will($this->returnValue(true));
+        $this->optionMock->expects($this->once())->method('getSortOrder')->will($this->returnValue(10));
+
+        $this->optionMetadataReaderMock->expects($this->once())->method('read')->will($this->returnValue('some value'));
+
+        $expectedData = [
+            Data\Option::OPTION_ID => 10,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+            'metadata' => 'some value'
+        ];
+
+        $this->optionBuilderMock->expects($this->once())
+            ->method('populateWithArray')->with($expectedData)->will($this->returnSelf());
+        $this->optionBuilderMock->expects($this->once())->method('create')->will($this->returnValue($optionData));
+
+        $this->assertEquals($optionData, $this->writeService->add(self::PRODUCT_SKU, $optionData));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testAddWithException()
+    {
+        $optionData = $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false);
+        $convertedOptions =  [
+            Data\Option::OPTION_ID => null,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+            'price_type' => 'fixed',
+            'sku' => 'sku1',
+            'max_characters' => 10
+        ];
+        $this->optionConverterMock
+            ->expects($this->once())
+            ->method('convert')
+            ->with($optionData)
+            ->will($this->returnValue($convertedOptions));
+
+        $this->productMock->expects($this->once())->method('setCanSaveCustomOptions')->with(true);
+        $this->productMock->expects($this->once())->method('setProductOptions')->with([$convertedOptions]);
+        $this->productMock->expects($this->once())->method('save');
+
+        $existingOptions = [1 => null, 2 => null];
+        $currentOptions = [1 => null, 2 => null];
+
+        $this->productMock->expects($this->at(2))
+            ->method('getOptions')->will($this->returnValue($existingOptions));
+        $this->productMock->expects($this->at(7))
+            ->method('getOptions')->will($this->returnValue($currentOptions));
+
+        $this->productMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->productMock->expects($this->once())->method('reset');
+        $this->productMock->expects($this->once())->method('load')->with(1);
+        $this->writeService->add(self::PRODUCT_SKU, $optionData);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testAddWithExceptionDuringSave()
+    {
+        $optionData = $this->getMock('Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option', [], [], '', false);
+        $convertedOptions =  [
+            Data\Option::OPTION_ID => 10,
+            Data\Option::TITLE => 'Some title',
+            Data\Option::TYPE => 'text',
+            Data\Option::IS_REQUIRE => true,
+            Data\Option::SORT_ORDER => 10,
+            'price_type' => 'fixed',
+            'sku' => 'sku1',
+            'max_characters' => 10
+        ];
+        $this->optionConverterMock
+            ->expects($this->once())
+            ->method('convert')
+            ->with($optionData)
+            ->will($this->returnValue($convertedOptions));
+
+        $this->productMock->expects($this->once())->method('setCanSaveCustomOptions')->with(true);
+        $this->productMock->expects($this->once())->method('setProductOptions')->with([$convertedOptions]);
+        $this->productMock->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
+        $this->writeService->add(self::PRODUCT_SKU, $optionData);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/QtyincrementsTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/QtyincrementsTest.php
index c84beb18cda..a54aca81fad 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/QtyincrementsTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/QtyincrementsTest.php
@@ -39,7 +39,7 @@ class QtyincrementsTest extends \PHPUnit_Framework_TestCase
     protected $registryMock;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $stockItemService;
 
@@ -47,7 +47,13 @@ class QtyincrementsTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
         $this->registryMock = $this->getMock('Magento\Framework\Registry', [], [], '', false);
-        $this->stockItemService = $this->getMock('Magento\CatalogInventory\Service\V1\StockItem', [], [], '', false);
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
 
         $this->block = $objectManager->getObject(
             'Magento\CatalogInventory\Block\Qtyincrements',
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/Stockqty/DefaultStockqtyTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/Stockqty/DefaultStockqtyTest.php
index 2a54673367f..64c482a5b10 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/Stockqty/DefaultStockqtyTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Block/Stockqty/DefaultStockqtyTest.php
@@ -39,7 +39,7 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
     protected $registryMock;
 
     /**
-     * @var \Magento\CatalogInventory\Service\V1\StockItem|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $stockItemService;
 
@@ -47,7 +47,13 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
         $this->registryMock = $this->getMock('Magento\Framework\Registry', array(), array(), '', false);
-        $this->stockItemService = $this->getMock('Magento\CatalogInventory\Service\V1\StockItem', [], [], '', false);
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
 
         $this->block = $objectManager->getObject(
             'Magento\CatalogInventory\Block\Stockqty\DefaultStockqty',
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/DataTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/DataTest.php
new file mode 100644
index 00000000000..61568042a51
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/DataTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\CatalogInventory\Helper;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Class DataTest
+ */
+class DataTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\CatalogInventory\Helper\Data */
+    protected $data;
+
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    /** @var \Magento\Framework\App\Helper\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $contextMock;
+
+    /** @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $scopeConfigMock;
+
+    protected function setUp()
+    {
+        $this->contextMock = $this->getMock('Magento\Framework\App\Helper\Context', [], [], '', false);
+        $this->scopeConfigMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->data = $this->objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Helper\Data',
+            [
+                'context' => $this->contextMock,
+                'scopeConfig' => $this->scopeConfigMock
+            ]
+        );
+    }
+
+    public function testGetConfigItemOptions()
+    {
+        $configOptions = [
+            'min_qty',
+            'backorders',
+            'min_sale_qty',
+            'max_sale_qty',
+            'notify_stock_qty',
+            'manage_stock',
+            'enable_qty_increments',
+            'qty_increments',
+            'is_decimal_divided'
+        ];
+        $this->assertSame($configOptions, $this->data->getConfigItemOptions());
+    }
+
+    public function testIsShowOutOfStock()
+    {
+        $this->scopeConfigMock->expects($this->once())
+            ->method('isSetFlag')
+            ->with(
+                $this->equalTo(Data::XML_PATH_SHOW_OUT_OF_STOCK),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+            )
+            ->will($this->returnValue(true));
+        $this->assertTrue($this->data->isShowOutOfStock());
+    }
+
+    public function testIsAutoReturnEnabled()
+    {
+        $this->scopeConfigMock->expects($this->once())
+            ->method('isSetFlag')
+            ->with(
+                $this->equalTo(Data::XML_PATH_ITEM_AUTO_RETURN),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+            )
+            ->will($this->returnValue(true));
+        $this->assertTrue($this->data->isAutoReturnEnabled());
+    }
+
+    public function testIsDisplayProductStockStatus()
+    {
+        $this->scopeConfigMock->expects($this->once())
+            ->method('isSetFlag')
+            ->with(
+                $this->equalTo(Data::XML_PATH_DISPLAY_PRODUCT_STOCK_STATUS),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+            )
+            ->will($this->returnValue(true));
+        $this->assertTrue($this->data->isDisplayProductStockStatus());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/MinsaleqtyTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/MinsaleqtyTest.php
new file mode 100644
index 00000000000..967e1ab70d1
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/MinsaleqtyTest.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\CatalogInventory\Helper;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Class MinsaleqtyTest
+ */
+class MinsaleqtyTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\CatalogInventory\Helper\Minsaleqty */
+    protected $minsaleqty;
+
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    /** @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $scopeConfigMock;
+
+    /** @var \Magento\Framework\Math\Random|\PHPUnit_Framework_MockObject_MockObject */
+    protected $randomMock;
+
+    protected function setUp()
+    {
+        $this->scopeConfigMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $this->randomMock = $this->getMock('Magento\Framework\Math\Random');
+        $this->randomMock->expects($this->any())
+            ->method('getUniqueHash')
+            ->with($this->equalTo('_'))
+            ->will($this->returnValue('unique_hash'));
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->minsaleqty = $this->objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Helper\Minsaleqty',
+            [
+                'scopeConfig' => $this->scopeConfigMock,
+                'mathRandom' => $this->randomMock
+            ]
+        );
+    }
+
+    /**
+     * @param int $customerGroupId
+     * @param int|null $store
+     * @param float $minSaleQty
+     * @param float|null $result
+     * @dataProvider getConfigValueDataProvider
+     */
+    public function testGetConfigValue($customerGroupId, $store, $minSaleQty, $result)
+    {
+        $this->scopeConfigMock->expects($this->once())
+            ->method('getValue')
+            ->with(
+                $this->equalTo(\Magento\CatalogInventory\Model\Stock\Item::XML_PATH_MIN_SALE_QTY),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE),
+                $this->equalTo($store)
+            )
+            ->will($this->returnValue($minSaleQty));
+        $this->assertSame($result, $this->minsaleqty->getConfigValue($customerGroupId, $store));
+    }
+
+    /**
+     * @return array
+     */
+    public function getConfigValueDataProvider()
+    {
+        return [
+            [1, 2, '20', 20.],
+            [0, null, '', null],
+            [3, null, '', null],
+            [2, 1, 'a:2:{i:1;s:4:"20.5";i:2;s:4:"34.2";}', 34.2],
+            [1, 44, 'a:2:{i:1;s:4:"20.5";i:2;s:4:"34.2";}', 20.5],
+            [5, 4, 'a:1:{i:0;a:2:{s:17:"customer_group_id";i:5;s:12:"min_sale_qty";d:40.10000000000000;}}', 40.1],
+            [5, 4, 'a:1:{i:0;a:2:{s:17:"customer_group_id";i:32000;s:12:"min_sale_qty";d:2.5;}}', 2.5],
+        ];
+    }
+
+    /**
+     * @param string|array $value
+     * @param array $result
+     * @dataProvider makeArrayFieldValueDataProvider
+     */
+    public function testMakeArrayFieldValue($value, $result)
+    {
+        $this->assertSame($result, $this->minsaleqty->makeArrayFieldValue($value));
+    }
+
+    /**
+     * @return array
+     */
+    public function makeArrayFieldValueDataProvider()
+    {
+        return [
+            ['', []],
+            ['20', ['unique_hash' => ['customer_group_id' => 32000, 'min_sale_qty' => 20.]]],
+            [
+                'a:1:{i:0;a:2:{s:17:"customer_group_id";i:32000;s:12:"min_sale_qty";d:2.5;}} ',
+                [['customer_group_id' => 32000, 'min_sale_qty' => 2.5]]
+            ],
+        ];
+    }
+
+    /**
+     * @param string|array $value
+     * @param string $result
+     * @dataProvider makeStorableArrayFieldValueDataProvider
+     */
+    public function testMakeStorableArrayFieldValue($value, $result)
+    {
+        $this->assertSame($result, $this->minsaleqty->makeStorableArrayFieldValue($value));
+    }
+
+    /**
+     * @return array
+     */
+    public function makeStorableArrayFieldValueDataProvider()
+    {
+        return [
+            [false, ''],
+            ['', ''],
+            ['22', '22'],
+            [[], 'a:0:{}'],
+            [
+                ['customer_group_id' => 32000, 'min_sale_qty' => 2.5],
+                'a:2:{s:17:"customer_group_id";d:32000;s:12:"min_sale_qty";d:2.5;}'
+            ],
+            [
+                [['customer_group_id' => 32000, 'min_sale_qty' => 2.5]],
+                '2.5'
+            ],
+            [
+                [['customer_group_id' => 2, 'min_sale_qty' => 2.5]],
+                'a:1:{i:2;d:2.5;}'
+            ],
+            [
+                [['min_sale_qty' => 2.5]],
+                'a:1:{i:0;d:1;}'
+            ],
+        ];
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/ObserverTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/ObserverTest.php
new file mode 100644
index 00000000000..02cbeeaaa1b
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/ObserverTest.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Model;
+
+/**
+ * Class ObserverTest
+ */
+class ObserverTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Observer
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\ItemRegistry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemRegistry;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\Status|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockStatus;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\StockFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockFactory;
+
+    /**
+     * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eventObserver;
+
+    /**
+     * @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $event;
+
+    protected function setUp()
+    {
+        $this->stockItemRegistry = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\ItemRegistry')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockStatus = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Status')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockFactory = $this->getMockBuilder('Magento\CatalogInventory\Model\StockFactory')
+            ->setMethods(['create'])
+            ->getMock();
+
+        $objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Model\Observer',
+            [
+                'stockItemRegistry' => $this->stockItemRegistry,
+                'stockStatus' => $this->stockStatus,
+                'stockFactory' => $this->stockFactory
+            ]
+        );
+
+        $this->event = $this->getMockBuilder('Magento\Framework\Event')
+            ->disableOriginalConstructor()
+            ->setMethods(['getProduct', 'getCollection'])
+            ->getMock();
+
+        $this->eventObserver = $this->getMockBuilder('Magento\Framework\Event\Observer')
+            ->disableOriginalConstructor()
+            ->setMethods(['getEvent'])
+            ->getMock();
+        $this->eventObserver->expects($this->atLeastOnce())
+            ->method('getEvent')
+            ->will($this->returnValue($this->event));
+    }
+
+    public function testAddInventoryData()
+    {
+        $productId = 4;
+        $stockId = 6;
+        $stockStatus = true;
+
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->setMethods(['getId', 'getStockStatus', '__wakeup'])
+            ->getMock();
+        $product->expects($this->once())
+            ->method('getId')
+            ->will($this->returnValue($productId));
+        $product->expects($this->once())
+            ->method('getStockStatus')
+            ->will($this->returnValue($stockStatus));
+
+        $this->event->expects($this->once())
+            ->method('getProduct')
+            ->will($this->returnValue($product));
+
+        $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $stockItem->expects($this->once())
+            ->method('getStockId')
+            ->will($this->returnValue($stockId));
+
+        $this->stockItemRegistry->expects($this->once())
+            ->method('retrieve')
+            ->with($productId)
+            ->will($this->returnValue($stockItem));
+
+        $this->stockStatus->expects($this->once())
+            ->method('assignProduct')
+            ->with($product, $stockId, $stockStatus)
+            ->will($this->returnSelf());
+
+        $this->assertEquals($this->model, $this->model->addInventoryData($this->eventObserver));
+    }
+
+    public function testAddStockStatusToCollection()
+    {
+        $requireStockItems = false;
+
+        $productCollection = $this->getMockBuilder('Magento\Catalog\Model\Resource\Product\Collection')
+            ->disableOriginalConstructor()
+            ->setMethods(['hasFlag'])
+            ->getMock();
+        $this->event->expects($this->once())
+            ->method('getCollection')
+            ->will($this->returnValue($productCollection));
+
+        $productCollection->expects($this->once())
+            ->method('hasFlag')
+            ->with('require_stock_items')
+            ->will($this->returnValue($requireStockItems));
+
+        $this->stockStatus->expects($this->once())
+            ->method('addStockStatusToProducts')
+            ->with($productCollection)
+            ->will($this->returnSelf());
+
+        $this->assertEquals($this->model, $this->model->addStockStatusToCollection($this->eventObserver));
+    }
+
+    public function testAddStockStatusToCollectionRequireStockItems()
+    {
+        $requireStockItems = true;
+
+        $productCollection = $this->getMockBuilder('Magento\Catalog\Model\Resource\Product\Collection')
+            ->disableOriginalConstructor()
+            ->setMethods(['hasFlag'])
+            ->getMock();
+        $this->event->expects($this->once())
+            ->method('getCollection')
+            ->will($this->returnValue($productCollection));
+
+        $productCollection->expects($this->once())
+            ->method('hasFlag')
+            ->with('require_stock_items')
+            ->will($this->returnValue($requireStockItems));
+
+        $stock = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockFactory->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue($stock));
+
+        $stock->expects($this->once())
+            ->method('addItemsToProducts')
+            ->with($productCollection)
+            ->will($this->returnSelf());
+
+        $this->assertEquals($this->model, $this->model->addStockStatusToCollection($this->eventObserver));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventoryTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventoryTest.php
index 92badefbf51..89707d8beb7 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventoryTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Product/CopyConstructor/CatalogInventoryTest.php
@@ -28,50 +28,78 @@ class CatalogInventoryTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\CatalogInventory\Model\Product\CopyConstructor\CatalogInventory
      */
-    protected $_model;
+    protected $model;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_productMock;
+    protected $productMock;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_duplicateMock;
+    protected $duplicateMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\CatalogInventory\Service\V1\Data\StockItem|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_stockItemMock;
+    protected $stockItemDoMock;
+
+    /**
+     * @var \Magento\TestFramework\Helper\ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemServiceMock;
 
     protected function setUp()
     {
-        $this->_model = new \Magento\CatalogInventory\Model\Product\CopyConstructor\CatalogInventory();
-
-        $this->_productMock = $this->getMock(
+        $this->productMock = $this->getMock(
             '\Magento\Catalog\Model\Product',
-            array('__wakeup', 'getStockItem'),
+            array('__wakeup'),
             array(),
             '',
             false
         );
 
-        $this->_duplicateMock = $this->getMock(
+        $this->duplicateMock = $this->getMock(
             '\Magento\Catalog\Model\Product',
-            array('setStockData', 'unsStockItem', '__wakeup'),
+            array('setStockData', '__wakeup'),
             array(),
             '',
             false
         );
 
-        $this->_stockItemMock = $this->getMock(
-            'Magento\CatalogInventory\Model\Stock\Item',
-            array(),
-            array(),
+        $this->stockItemDoMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\Data\StockItem',
+            [
+                'getStockId',
+                'isUseConfigEnableQtyInc',
+                'isEnableQtyIncrements',
+                'isUseConfigQtyIncrements',
+                'getQtyIncrements'
+            ],
+            [],
+            '',
+            false
+        );
+
+        $this->stockItemServiceMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            ['getStockItem'],
+            [],
             '',
             false
         );
+
+        $this->objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $this->objectManager->getObject(
+            'Magento\CatalogInventory\Model\Product\CopyConstructor\CatalogInventory',
+            ['stockItemService' => $this->stockItemServiceMock]
+        );
     }
 
     public function testBuildWithoutCurrentProductStockItem()
@@ -83,12 +111,14 @@ class CatalogInventoryTest extends \PHPUnit_Framework_TestCase
             'use_config_backorders' => 1,
             'use_config_notify_stock_qty' => 1
         );
-        $this->_duplicateMock->expects($this->once())->method('unsStockItem');
-        $this->_productMock->expects($this->once())->method('getStockItem')->will($this->returnValue(null));
+        $this->stockItemDoMock->expects($this->any())->method('getStockId')->will($this->returnValue(false));
 
-        $this->_duplicateMock->expects($this->once())->method('setStockData')->with($expectedData);
+        $this->stockItemServiceMock->expects($this->once())
+            ->method('getStockItem')
+            ->will($this->returnValue($this->stockItemDoMock));
 
-        $this->_model->build($this->_productMock, $this->_duplicateMock);
+        $this->duplicateMock->expects($this->once())->method('setStockData')->with($expectedData);
+        $this->model->build($this->productMock, $this->duplicateMock);
     }
 
     public function testBuildWithCurrentProductStockItem()
@@ -104,19 +134,26 @@ class CatalogInventoryTest extends \PHPUnit_Framework_TestCase
             'use_config_qty_increments' => 'use_config_qty_increments',
             'qty_increments' => 'qty_increments'
         );
-        $this->_duplicateMock->expects($this->once())->method('unsStockItem');
-        $this->_productMock->expects(
-            $this->once()
-        )->method(
-            'getStockItem'
-        )->will(
-            $this->returnValue($this->_stockItemMock)
-        );
+        $this->stockItemServiceMock->expects($this->once())
+            ->method('getStockItem')
+            ->will($this->returnValue($this->stockItemDoMock));
 
-        $this->_stockItemMock->expects($this->any())->method('getData')->will($this->returnArgument(0));
+        $this->stockItemDoMock->expects($this->any())->method('getStockId')->will($this->returnValue(50));
 
-        $this->_duplicateMock->expects($this->once())->method('setStockData')->with($expectedData);
+        $this->stockItemDoMock->expects($this->any())
+            ->method('isUseConfigEnableQtyInc')
+            ->will($this->returnValue('use_config_enable_qty_inc'));
+        $this->stockItemDoMock->expects($this->any())
+            ->method('isEnableQtyIncrements')
+            ->will($this->returnValue('enable_qty_increments'));
+        $this->stockItemDoMock->expects($this->any())
+            ->method('isUseConfigQtyIncrements')
+            ->will($this->returnValue('use_config_qty_increments'));
+        $this->stockItemDoMock->expects($this->any())
+            ->method('getQtyIncrements')
+            ->will($this->returnValue('qty_increments'));
 
-        $this->_model->build($this->_productMock, $this->_duplicateMock);
+        $this->duplicateMock->expects($this->once())->method('setStockData')->with($expectedData);
+        $this->model->build($this->productMock, $this->duplicateMock);
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php
index e3cdd5ccd77..149a5d8aba7 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php
@@ -60,6 +60,16 @@ class OptionTest extends \PHPUnit_Framework_TestCase
      */
     protected $resultMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemRegistryMock;
+
+    /**
+     * @var \Magento\TestFramework\Helper\ObjectManager
+     */
+    protected $objectManager;
+
     protected function setUp()
     {
         $optionMethods = array(
@@ -86,7 +96,8 @@ class OptionTest extends \PHPUnit_Framework_TestCase
             'setSuppressCheckQtyIncrements',
             'checkQuoteItemQty',
             '__wakeup',
-            'unsIsChildItem'
+            'unsIsChildItem',
+            'getId',
         );
         $this->stockItemMock = $this->getMock(
             'Magento\CatalogInventory\Model\Stock\Item',
@@ -95,7 +106,7 @@ class OptionTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $productMethods = array('getStockItem', 'getId', '__wakeup');
+        $productMethods = array('getId', '__wakeup');
         $this->productMock = $this->getMock('Magento\Catalog\Model\Product', $productMethods, array(), '', false);
         $this->qtyItemListMock = $this->getMock(
             'Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\QuoteItemQtyList',
@@ -113,8 +124,22 @@ class OptionTest extends \PHPUnit_Framework_TestCase
             '__wakeup'
         );
         $this->resultMock = $this->getMock('Magento\Framework\Object', $resultMethods, array(), '', false);
-        $this->validator = new \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option(
-            $this->qtyItemListMock
+
+        $this->stockItemRegistryMock = $this->getMock(
+            'Magento\CatalogInventory\Model\Stock\ItemRegistry',
+            ['retrieve', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->validator = $this->objectManager->getObject(
+            'Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option',
+            [
+                'quoteItemQtyList' => $this->qtyItemListMock,
+                'stockItemRegistry' => $this->stockItemRegistryMock,
+            ]
         );
     }
 
@@ -127,18 +152,18 @@ class OptionTest extends \PHPUnit_Framework_TestCase
         $this->optionMock->expects($this->once())->method('getValue')->will($this->returnValue($optionValue));
         $this->quoteMock->expects($this->exactly(2))->method('getQtyToAdd')->will($this->returnValue($qtyToAdd));
         $this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
-        //stock item verification
-        $this->productMock->expects(
-            $this->once()
-        )->method(
-            'getStockItem'
-        )->will(
-            $this->returnValue($this->stockItemMock)
-        );
+
         $this->stockItemMock->expects($this->once())->method('setIsChildItem')->with(true);
         $this->stockItemMock->expects($this->once())->method('setSuppressCheckQtyIncrements')->with(true);
-        $this->productMock->expects($this->once())->method('getId')->will($this->returnValue('product_id'));
-        $this->quoteMock->expects($this->once())->method('getId')->will($this->returnValue('quote_item_id'));
+        $this->stockItemMock->expects($this->once())->method('getId')->will($this->returnValue(true));
+
+        $this->stockItemRegistryMock
+            ->expects($this->once())
+            ->method('retrieve')
+            ->will($this->returnValue($this->stockItemMock));
+
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id'));
+        $this->quoteMock->expects($this->any())->method('getId')->will($this->returnValue('quote_item_id'));
         $this->quoteMock->expects($this->once())->method('getQuoteId')->will($this->returnValue('quote_id'));
         $this->qtyItemListMock->expects(
             $this->once()
@@ -200,17 +225,18 @@ class OptionTest extends \PHPUnit_Framework_TestCase
         $this->optionMock->expects($this->once())->method('getValue')->will($this->returnValue($optionValue));
         $this->quoteMock->expects($this->once())->method('getQtyToAdd')->will($this->returnValue(false));
         $this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
-        $this->productMock->expects(
-            $this->once()
-        )->method(
-            'getStockItem'
-        )->will(
-            $this->returnValue($this->stockItemMock)
-        );
+
         $this->stockItemMock->expects($this->once())->method('setIsChildItem')->with(true);
         $this->stockItemMock->expects($this->once())->method('setSuppressCheckQtyIncrements')->with(true);
-        $this->productMock->expects($this->once())->method('getId')->will($this->returnValue('product_id'));
-        $this->quoteMock->expects($this->once())->method('getId')->will($this->returnValue('quote_item_id'));
+        $this->stockItemMock->expects($this->once())->method('getId')->will($this->returnValue(true));
+
+        $this->stockItemRegistryMock
+            ->expects($this->once())
+            ->method('retrieve')
+            ->will($this->returnValue($this->stockItemMock));
+
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id'));
+        $this->quoteMock->expects($this->any())->method('getId')->will($this->returnValue('quote_item_id'));
         $this->quoteMock->expects($this->once())->method('getQuoteId')->will($this->returnValue('quote_id'));
         $this->qtyItemListMock->expects(
             $this->once()
@@ -257,8 +283,15 @@ class OptionTest extends \PHPUnit_Framework_TestCase
         $qty = 10;
         $this->optionMock->expects($this->once())->method('getValue')->will($this->returnValue($optionValue));
         $this->quoteMock->expects($this->once())->method('getQtyToAdd')->will($this->returnValue(false));
-        $this->optionMock->expects($this->once())->method('getProduct')->will($this->returnValue($this->productMock));
-        $this->productMock->expects($this->once())->method('getStockItem')->will($this->returnValue(10));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue('product_id'));
+        $this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
+        $this->stockItemMock->expects($this->once())->method('getId')->will($this->returnValue(false));
+
+        $this->stockItemRegistryMock
+            ->expects($this->once())
+            ->method('retrieve')
+            ->will($this->returnValue($this->stockItemMock));
+
         $this->validator->initialize($this->optionMock, $this->quoteMock, $qty);
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Resource/Stock/Status/CollectionTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Resource/Stock/Status/CollectionTest.php
new file mode 100644
index 00000000000..176bb0cc7eb
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Resource/Stock/Status/CollectionTest.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\CatalogInventory\Model\Resource\Stock\Status;
+
+/**
+ * Test for \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection
+ */
+class CollectionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resource;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $connection;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $select;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection
+     */
+    protected $model;
+
+    protected function setUp()
+    {
+        $this->select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
+        $this->connection = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+        $this->connection->expects($this->atLeastOnce())->method('select')->will($this->returnValue($this->select));
+        $this->connection->expects($this->atLeastOnce())->method('quoteIdentifier')->will($this->returnArgument(0));
+        $this->resource = $this->getMock('Magento\CatalogInventory\Model\Resource\Stock\Status', [], [], '', false);
+        $this->resource->expects($this->any())->method('getReadConnection')
+            ->will($this->returnValue($this->connection));
+
+        $objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Model\Resource\Stock\Status\Collection',
+            [
+                'resource' => $this->resource,
+            ]
+        );
+    }
+
+    /**
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::__construct
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::_construct
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::addWebsiteFilter
+     */
+    public function testAddingWebsiteFilter()
+    {
+        $website = $this->getMock('Magento\Store\Model\Website', ['getWebsiteId', '__wakeup'], [], '', false);
+        $website->expects($this->atLeastOnce())->method('getWebsiteId')->will($this->returnValue(1));
+        $this->connection->expects($this->atLeastOnce())->method('prepareSqlCondition')->with('website_id', 1)
+            ->will($this->returnValue('condition_string'));
+        $this->select->expects($this->atLeastOnce())->method('where')
+            ->with('condition_string', $this->anything(), $this->anything());
+        $this->model->addWebsiteFilter($website);
+    }
+
+    /**
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::__construct
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::_construct
+     * @covers \Magento\CatalogInventory\Model\Resource\Stock\Status\Collection::addQtyFilter
+     */
+    public function testAddingQtyFilter()
+    {
+        $qty = 3;
+        $this->connection->expects($this->atLeastOnce())
+            ->method('prepareSqlCondition')
+            ->with('main_table.qty', ['lteq' => $qty])
+            ->will($this->returnValue('condition_string'));
+        $this->select->expects($this->atLeastOnce())->method('where')
+            ->with('condition_string', $this->anything(), $this->anything());
+        $this->model->addQtyFilter($qty);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Stock/ItemTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Stock/ItemTest.php
index 1a209a447ce..7f60919b7a2 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Stock/ItemTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Stock/ItemTest.php
@@ -65,6 +65,9 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
     protected $storeManager;
 
+    /** @var \Magento\CatalogInventory\Model\Stock\ItemRegistry|\PHPUnit_Framework_MockObject_MockObject */
+    protected $stockItemRegistry;
+
     protected function setUp()
     {
         $this->resource = $this->getMock(
@@ -109,6 +112,14 @@ class ItemTest extends \PHPUnit_Framework_TestCase
         $this->scopeConfig = $this->getMock('Magento\Framework\App\Config', [], [], '', false);
         $this->storeManager = $this->getMock('Magento\Store\Model\StoreManagerInterface', [], [], '', false);
 
+        $this->stockItemRegistry = $this->getMock(
+            '\Magento\CatalogInventory\Model\Stock\ItemRegistry',
+            ['retrieve', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
         $this->objectManagerHelper = new ObjectManagerHelper($this);
         $this->item = $this->objectManagerHelper->getObject(
             'Magento\CatalogInventory\Model\Stock\Item',
@@ -119,7 +130,8 @@ class ItemTest extends \PHPUnit_Framework_TestCase
                 'scopeConfig' => $this->scopeConfig,
                 'storeManager' => $this->storeManager,
                 'productFactory' => $productFactory,
-                'resource' => $this->resource
+                'resource' => $this->resource,
+                'stockItemRegistry' => $this->stockItemRegistry
             ]
         );
     }
@@ -194,8 +206,8 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     protected function prepareNotCompositeProductMock()
     {
         $productGroup = [
-            [$this->getGroupProductMock(), $this->getGroupProductMock(), $this->getGroupProductMock()],
-            [$this->getGroupProductMock(), $this->getGroupProductMock()],
+            [$this->getGroupProductMock(0), $this->getGroupProductMock(1), $this->getGroupProductMock(2)],
+            [$this->getGroupProductMock(3), $this->getGroupProductMock(4)],
         ];
 
         $typeInstance = $this->getMock(
@@ -216,26 +228,26 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
+     * @param int $at
      * @return \PHPUnit_Framework_MockObject_MockObject
      */
-    protected function getGroupProductMock()
+    protected function getGroupProductMock($at)
     {
         $product = $this->getMock(
             'Magento\Catalog\Model\Product',
-            ['hasStockItem', 'getStockItem', 'getStockQty', '__wakeup'],
+            ['getStockQty', '__wakeup'],
             [],
             '',
             false
         );
-        $product->expects($this->once())
-            ->method('hasStockItem')
-            ->will($this->returnValue(true));
-        $product->expects($this->once())
-            ->method('getStockItem')
-            ->will($this->returnSelf());
         $product->expects($this->once())
             ->method('getStockQty')
             ->will($this->returnValue(2));
+
+        $this->stockItemRegistry->expects($this->at($at))
+            ->method('retrieve')
+            ->will($this->returnValue($product));
+
         return $product;
     }
 
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/StockTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/StockTest.php
new file mode 100644
index 00000000000..20b00923a81
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/StockTest.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\CatalogInventory\Model;
+
+use Magento\CatalogInventory\Model\Resource\Stock\Item\CollectionFactory;
+
+/**
+ * Class StockTest
+ */
+class StockTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Stock
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\Status|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockStatus;
+
+    /**
+     * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $collectionFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productFactory;
+
+    protected function setUp()
+    {
+        $this->collectionFactory = $this
+            ->getMockBuilder('Magento\CatalogInventory\Model\Resource\Stock\Item\CollectionFactory')
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockStatus = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Status')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockItemService = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\StockItemService')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockItemFactory = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\ItemFactory')
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->productFactory = $this->getMockBuilder('Magento\Catalog\Model\ProductFactory')
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Model\Stock',
+            [
+                'stockStatus'       => $this->stockStatus,
+                'collectionFactory' => $this->collectionFactory,
+                'stockItemService'  => $this->stockItemService,
+                'stockItemFactory'  => $this->stockItemFactory,
+                'productFactory'    => $this->productFactory
+            ]
+        );
+    }
+
+    public function testAddItemsToProducts()
+    {
+        $storeId = 3;
+        $productOneId = 1;
+        $productOneStatus = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK;
+        $productTwoId = 2;
+        $productThreeId = 3;
+
+        $stockItemProductId = $productOneId;
+        $stockItemStockId = \Magento\CatalogInventory\Model\Stock::DEFAULT_STOCK_ID;
+
+        $productCollection = $this->getMockBuilder('Magento\Catalog\Model\Resource\Product\Collection')
+            ->disableOriginalConstructor()
+            ->setMethods(['getStoreId', 'getIterator'])
+            ->getMock();
+
+        $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $stockItem->expects($this->atLeastOnce())
+            ->method('getProductId')
+            ->will($this->returnValue($stockItemProductId));
+        $stockItem->expects($this->atLeastOnce())
+            ->method('getStockId')
+            ->will($this->returnValue($stockItemStockId));
+
+        $itemCollection = $this->getMockBuilder('Magento\CatalogInventory\Model\Resource\Stock\Item\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $itemCollection->expects($this->atLeastOnce())
+            ->method('addStockFilter')
+            ->with(Stock::DEFAULT_STOCK_ID)
+            ->will($this->returnSelf());
+        $itemCollection->expects($this->atLeastOnce())
+            ->method('addProductsFilter')
+            ->with($productCollection)
+            ->will($this->returnSelf());
+        $itemCollection->expects($this->atLeastOnce())
+            ->method('joinStockStatus')
+            ->with($storeId)
+            ->will($this->returnSelf());
+        $itemCollection->expects($this->atLeastOnce())
+            ->method('load')
+            ->will($this->returnValue([$stockItem]));
+
+        $this->collectionFactory->expects($this->atLeastOnce())
+            ->method('create')
+            ->will($this->returnValue($itemCollection));
+
+
+        $productOne = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->setMethods(['getId', 'getStockStatus', '__wakeup'])
+            ->getMock();
+        $productOne->expects($this->atLeastOnce())
+            ->method('getId')
+            ->will($this->returnValue($productOneId));
+        $productOne->expects($this->atLeastOnce())
+            ->method('getStockStatus')
+            ->will($this->returnValue($productOneStatus));
+        $productTwo = $this->getMockBuilder('Magento\Catalog\Model\Product')->disableOriginalConstructor()->getMock();
+        $productTwo->expects($this->atLeastOnce())->method('getId')->will($this->returnValue($productTwoId));
+        $productThree = $this->getMockBuilder('Magento\Catalog\Model\Product')->disableOriginalConstructor()->getMock();
+        $productThree->expects($this->atLeastOnce())->method('getId')->will($this->returnValue($productThreeId));
+
+        $productCollection->expects($this->atLeastOnce())->method('getStoreId')->will($this->returnValue($storeId));
+        $productCollection->expects($this->any())
+            ->method('getIterator')
+            ->will($this->returnValue(new \ArrayIterator([$productOne, $productTwo, $productThree])));
+
+
+        $this->stockStatus->expects($this->once())
+            ->method('assignProduct')
+            ->with($productOne, $stockItemStockId, $productOneStatus);
+
+        $this->assertEquals($this->model, $this->model->addItemsToProducts($productCollection));
+    }
+
+    /**
+     * @covers \Magento\CatalogInventory\Model\Stock::getProductType
+     */
+    public function testGettingProductType()
+    {
+        $productId = 1;
+        $qty = 1;
+        $productType = 'simple';
+
+        $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $stockItem->expects($this->atLeastOnce())->method('loadByProduct')->with($productId)->will($this->returnSelf());
+        $stockItem->expects($this->any())->method('getId')->will($this->returnValue(1));
+
+        $this->stockItemFactory->expects($this->atLeastOnce())->method('create')->will($this->returnValue($stockItem));
+
+        $product = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
+        $product->expects($this->atLeastOnce())->method('load')->with($productId);
+        $product->expects($this->atLeastOnce())->method('getTypeId')->will($this->returnValue($productType));
+        $this->productFactory->expects($this->atLeastOnce())->method('create')->will($this->returnValue($product));
+
+        $this->stockItemService->expects($this->once())->method('isQty')->with($productType);
+        $this->model->backItemQty($productId, $qty);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemServiceTest.php
similarity index 51%
rename from dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemTest.php
rename to dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemServiceTest.php
index 4e50dc52e00..61357b0d515 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockItemServiceTest.php
@@ -29,10 +29,10 @@ use Magento\Catalog\Model\ProductTypes\ConfigInterface;
 /**
  * Class StockItemTest
  */
-class StockItemTest extends \PHPUnit_Framework_TestCase
+class StockItemServiceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var StockItem
+     * @var StockItemService
      */
     protected $model;
 
@@ -51,6 +51,11 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
      */
     protected $stockItemBuilder;
 
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\ProductLoader|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productLoader;
+
     protected function setUp()
     {
         $this->stockItemRegistry = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\ItemRegistry')
@@ -61,11 +66,24 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->stockItemBuilder = $this->getMockBuilder(
-            'Magento\CatalogInventory\Service\V1\Data\StockItemBuilder'
-        )->disableOriginalConstructor()->getMock();
+        $this->stockItemBuilder = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItemBuilder')
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $this->model = new StockItem($this->stockItemRegistry, $this->config, $this->stockItemBuilder);
+        $this->productLoader = $this->getMockBuilder('Magento\Catalog\Service\V1\Product\ProductLoader')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [
+                'stockItemRegistry' => $this->stockItemRegistry,
+                'config' => $this->config,
+                'stockItemBuilder' => $this->stockItemBuilder,
+                'productLoader' => $this->productLoader
+            ]
+        );
     }
 
     public function testGetStockItem()
@@ -108,7 +126,7 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $stockItemDo = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItem')
             ->disableOriginalConstructor()
             ->getMock();
-        $stockItemDo->expects($this->once())
+        $stockItemDo->expects($this->any())
             ->method('getProductId')
             ->will($this->returnValue($productId));
         $stockItemDo->expects($this->once())
@@ -129,59 +147,12 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
             ->with($productId)
             ->will($this->returnValue($stockItemModel));
 
-        $this->assertEquals($this->model, $this->model->saveStockItem($stockItemDo));
-    }
-
-    public function testSubtractQty()
-    {
-        $productId = 123;
-        $qty = 1.5;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('subtractQty')
-            ->with($qty);
-
-        $this->assertEquals($this->model, $this->model->subtractQty($productId, $qty));
-    }
-
-    public function testCanSubtractQty()
-    {
-        $productId = 23;
-        $result = false;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('canSubtractQty')
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->canSubtractQty($productId));
-    }
-
-    public function testAddQty()
-    {
-        $productId = 143;
-        $qty = 3.5;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('addQty')
-            ->with($qty);
-
-        $this->assertEquals($this->model, $this->model->addQty($productId, $qty));
-    }
-
-    public function testGetMinQty()
-    {
-        $productId = 53;
-        $result = 3;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('getMinQty')
-            ->will($this->returnValue($result));
+        $this->stockItemRegistry->expects($this->once())
+            ->method('erase')
+            ->with($productId)
+            ->will($this->returnValue($stockItemModel));
 
-        $this->assertEquals($result, $this->model->getMinQty($productId));
+        $this->assertEquals($this->model, $this->model->saveStockItem($stockItemDo));
     }
 
     public function testGetMinSaleQty()
@@ -210,19 +181,6 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->model->getMaxSaleQty($productId));
     }
 
-    public function testGetNotifyStockQty()
-    {
-        $productId = 12;
-        $result = 15.3;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('getNotifyStockQty')
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->getNotifyStockQty($productId));
-    }
-
     public function testEnableQtyIncrements()
     {
         $productId = 48;
@@ -249,19 +207,6 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->model->getQtyIncrements($productId));
     }
 
-    public function testGetBackorders()
-    {
-        $productId = 34;
-        $result = 2;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('getBackorders')
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->getBackorders($productId));
-    }
-
     public function testGetManageStock()
     {
         $productId = 32;
@@ -275,34 +220,6 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->model->getManageStock($productId));
     }
 
-    public function testGetCanBackInStock()
-    {
-        $productId = 59;
-        $result = false;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('getCanBackInStock')
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->getCanBackInStock($productId));
-    }
-
-    public function testCheckQty()
-    {
-        $productId = 143;
-        $qty = 3.5;
-        $result = false;
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('checkQty')
-            ->with($qty)
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->checkQty($productId, $qty));
-    }
-
     public function testSuggestQty()
     {
         $productId = 143;
@@ -391,21 +308,6 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->model->getStockQty($productId));
     }
 
-    public function testCheckQtyIncrements()
-    {
-        $productId = 86;
-        $qty = 6;
-        $result = $this->getMock('Magento\Framework\Object');
-
-        $stockItemModel = $this->getStockItemModel($productId);
-        $stockItemModel->expects($this->once())
-            ->method('checkQtyIncrements')
-            ->with($qty)
-            ->will($this->returnValue($result));
-
-        $this->assertEquals($result, $this->model->checkQtyIncrements($productId, $qty));
-    }
-
     public function testIsQty()
     {
         $configAll = [
@@ -443,6 +345,243 @@ class StockItemTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($resultFalse, $this->model->getIsQtyTypeIds(false));
     }
 
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @param [] $stockItemData
+     * @dataProvider getStockItemBySkuDataProvider
+     */
+    public function testGetStockItemBySku($productSku, $productId, $stockItemData)
+    {
+        // 1. Get mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var \Magento\CatalogInventory\Model\Stock\Item|\PHPUnit_Framework_MockObject_MockObject $stockItem */
+        $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var Data\StockItem|\PHPUnit_Framework_MockObject_MockObject $stockItemDataObject */
+        $stockItemDataObject = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItem')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $stockItem->expects($this->any())->method('getData')->will($this->returnValue($stockItemData));
+
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+
+        $this->stockItemRegistry->expects($this->any())->method('retrieve')->will($this->returnValueMap([
+            [$productId, $stockItem]
+        ]));
+
+        $this->stockItemBuilder->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($stockItemDataObject));
+
+        // 3. Set expectations
+        $this->stockItemBuilder->expects($this->any())->method('populateWithArray')->with($stockItemData);
+
+        // 4. Run tested method
+        $result = $this->model->getStockItemBySku($productSku);
+
+        // 5. Compare actual result with expected result
+        $this->assertEquals($stockItemDataObject, $result);
+    }
+
+    /**
+     * @return array
+     */
+    public function getStockItemBySkuDataProvider()
+    {
+        return [
+            ['sku1', 1, ['stock_item_id' => 123]],
+            ['sku1', 1, []],
+        ];
+    }
+
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @dataProvider getStockItemBySkuWithExceptionDataProvider
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testGetStockItemBySkuWithException($productSku, $productId)
+    {
+        // 1. Get mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+
+        // 3. Run tested method
+        $this->model->getStockItemBySku($productSku);
+    }
+
+    /**
+     * @return array
+     */
+    public function getStockItemBySkuWithExceptionDataProvider()
+    {
+        return [
+            ['sku1', null],
+            ['sku1', false],
+            ['sku1', 0],
+        ];
+    }
+
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @param array $stockItemData
+     * @param array $stockItemDetailsDoData
+     * @param array $dataToSave
+     * @param int $savedStockItemId
+     * @dataProvider saveStockItemBySkuDataProvider
+     */
+    public function testSaveStockItemBySku(
+        $productSku,
+        $productId,
+        $stockItemData,
+        $stockItemDetailsDoData,
+        $dataToSave,
+        $savedStockItemId
+    ) {
+        // 1. Create mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var \Magento\CatalogInventory\Model\Stock\Item|\PHPUnit_Framework_MockObject_MockObject $stockItem */
+        $stockItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var Data\StockItem|\PHPUnit_Framework_MockObject_MockObject $stockItemDataObject */
+        $stockItemDataObject = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItem')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var Data\StockItem|\PHPUnit_Framework_MockObject_MockObject $stockItemDataObjectMerged */
+        $stockItemDataObjectMerged = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItem')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var Data\StockItemDetails|\PHPUnit_Framework_MockObject_MockObject $stockItemDetailsDo */
+        $stockItemDetailsDo = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItemDetails')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+
+        $stockItem->expects($this->any())->method('getData')->will($this->returnValue($stockItemData));
+        $stockItem->expects($this->any())->method('save')->will($this->returnSelf());
+        $stockItem->expects($this->any())->method('getId')->will($this->returnValue($savedStockItemId));
+
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+
+        $this->stockItemRegistry->expects($this->any())->method('retrieve')->will($this->returnValueMap([
+            [$productId, $stockItem]
+        ]));
+
+        $this->stockItemBuilder->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($stockItemDataObject));
+
+        $stockItemDetailsDo->expects($this->any())
+            ->method('__toArray')
+            ->will($this->returnValue($stockItemDetailsDoData));
+
+        $this->stockItemBuilder->expects($this->any())
+            ->method('mergeDataObjectWithArray')
+            ->will($this->returnValue($stockItemDataObjectMerged));
+
+        $stockItemDataObjectMerged->expects($this->any())
+            ->method('__toArray')
+            ->will($this->returnValue($dataToSave));
+
+        // 3. Set expectations
+        $stockItem->expects($this->any())->method('setData')->with($dataToSave)->will($this->returnSelf());
+        $this->stockItemBuilder->expects($this->any())
+            ->method('populateWithArray')
+            ->with($stockItemData)
+            ->will($this->returnSelf());
+
+        // 4. Run tested method
+        $result = $this->model->saveStockItemBySku($productSku, $stockItemDetailsDo);
+
+        // 5. Compare actual result with expected result
+        $this->assertEquals($savedStockItemId, $result);
+    }
+
+    /**
+     * @return array
+     */
+    public function saveStockItemBySkuDataProvider()
+    {
+        return [
+            ['sku1', 1, ['key1' => 'value1'], ['key2' => 'value2'], ['key3' => 'value3'], 123],
+            ['sku1', 1, [], [], [], 123],
+        ];
+    }
+
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @dataProvider saveStockItemBySkuWithExceptionDataProvider
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testSaveStockItemBySkuWithException($productSku, $productId)
+    {
+        // 1. Get mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /** @var Data\StockItemDetails|\PHPUnit_Framework_MockObject_MockObject $stockItemDetailsDo */
+        $stockItemDetailsDo = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockItemDetails')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+
+        // 3. Run tested method
+        $this->model->saveStockItemBySku($productSku, $stockItemDetailsDo);
+    }
+
+    /**
+     * @return array
+     */
+    public function saveStockItemBySkuWithExceptionDataProvider()
+    {
+        return [
+            ['sku1', null],
+            ['sku1', false],
+            ['sku1', 0],
+        ];
+    }
+
     /**
      * @param int $productId
      * @return \PHPUnit_Framework_MockObject_MockObject
diff --git a/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockStatusServiceTest.php b/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockStatusServiceTest.php
index 456c4e007ab..99144a42208 100644
--- a/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockStatusServiceTest.php
+++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Service/V1/StockStatusServiceTest.php
@@ -23,48 +23,337 @@
  */
 namespace Magento\CatalogInventory\Service\V1;
 
-use Magento\CatalogInventory\Model\Stock\Status;
-
 /**
  * Test for Magento\CatalogInventory\Service\V1\StockStatusService
  */
 class StockStatusServiceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @param int[] $productIds
+     * @var StockStatusService
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Stock\Status|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockStatus;
+
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\ProductLoader|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productLoader;
+
+    /**
+     * @var \Magento\Store\Model\Resolver\Website|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $scopeResolver;
+
+    /**
+     * @var Data\StockStatusBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockStatusBuilder;
+
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $lowStockResultBuilder;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $itemsFactory;
+
+    protected function setUp()
+    {
+        $this->stockStatus = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Status')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->productLoader = $this->getMockBuilder('Magento\Catalog\Service\V1\Product\ProductLoader')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->scopeResolver = $this->getMockBuilder('Magento\Store\Model\Resolver\Website')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockStatusBuilder = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockStatusBuilder')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockItemService = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\StockItemService')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->lowStockResultBuilder = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\Data\LowStockResultBuilder',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->itemsFactory = $this->getMock(
+            'Magento\CatalogInventory\Model\Resource\Stock\Status\CollectionFactory',
+            ['create'],
+            [],
+            '',
+            false
+        );
+
+        $objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            'Magento\CatalogInventory\Service\V1\StockStatusService',
+            [
+                'stockStatus' => $this->stockStatus,
+                'productLoader' => $this->productLoader,
+                'scopeResolver' => $this->scopeResolver,
+                'stockStatusBuilder' => $this->stockStatusBuilder,
+                'stockItemService' => $this->stockItemService,
+                'itemsFactory' => $this->itemsFactory,
+                'lowStockResultBuilder' => $this->lowStockResultBuilder
+            ]
+        );
+    }
+
+    /**
+     * @param int $productId
      * @param int $websiteId
      * @param int $stockId
-     * @param [] $expectedResult
+     * @param mixed $expectedResult
      * @dataProvider getProductStockStatusDataProvider
      */
-    public function testGetProductStockStatus($productIds, $websiteId, $stockId, $expectedResult)
+    public function testGetProductStockStatus($productId, $websiteId, $stockId, $expectedResult)
+    {
+        $this->stockStatus->expects($this->once())
+            ->method('getProductStockStatus')
+            ->with([$productId], $websiteId, $stockId)
+            ->will($this->returnValue([$productId => 'expected_result']));
+
+        $result = $this->model->getProductStockStatus($productId, $websiteId, $stockId);
+
+        $this->assertEquals($expectedResult, $result);
+    }
+
+    /**
+     * @return array
+     */
+    public function getProductStockStatusDataProvider()
+    {
+        $productId = 1;
+        return [
+            [$productId, 3, 4, 'expected_result'],
+        ];
+    }
+
+    public function testAssignProduct()
     {
-        // 1 Create mocks
-        $stockStatus = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Status')
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')->disableOriginalConstructor()->getMock();
+        $stockId = 1;
+        $stockStatus = false;
+
+        $this->stockStatus->expects($this->once())
+            ->method('assignProduct')
+            ->with($product, $stockId, $stockStatus)
+            ->will($this->returnSelf());
+
+        $this->assertEquals($this->model, $this->model->assignProduct($product, $stockId, $stockStatus));
+    }
+
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @param int $websiteId
+     * @param array $productStockStatusArray
+     * @param int $stockQty
+     * @param array $array
+     * @dataProvider getProductStockStatusBySkuDataProvider
+     */
+    public function testGetProductStockStatusBySku(
+        $productSku,
+        $productId,
+        $websiteId,
+        $productStockStatusArray,
+        $stockQty,
+        $array
+    ) {
+        // 1. Create mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
             ->disableOriginalConstructor()
             ->getMock();
-        $model = new StockStatusService($stockStatus);
 
-        // 2. Set expectations
-        $stockStatus->expects($this->once())
+        /** @var \Magento\Framework\App\ScopeInterface|\PHPUnit_Framework_MockObject_MockObject $scope */
+        $scope = $this->getMockBuilder('Magento\Framework\App\ScopeInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        /**
+         * @var \Magento\CatalogInventory\Service\V1\Data\StockStatus|\PHPUnit_Framework_MockObject_MockObject $scope
+         */
+        $stockStatusDataObject = $this->getMockBuilder('Magento\CatalogInventory\Service\V1\Data\StockStatus')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $this->scopeResolver->expects($this->any())->method('getScope')->will($this->returnValue($scope));
+        $scope->expects($this->any())->method('getId')->will($this->returnValue($websiteId));
+        $this->stockStatusBuilder->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($stockStatusDataObject));
+
+        // 3. Set expectations
+        $this->stockStatus->expects($this->any())
             ->method('getProductStockStatus')
-            ->with($productIds, $websiteId, $stockId)
-            ->will($this->returnValue($expectedResult));
+            ->with([$productId], $websiteId)
+            ->will($this->returnValue($productStockStatusArray));
 
-        // 3. Run tested method
-        $result = $model->getProductStockStatus($productIds, $websiteId, $stockId);
+        $this->stockItemService->expects($this->any())
+            ->method('getStockQty')
+            ->will($this->returnValueMap([[$productId, $stockQty]]));
+
+        $this->stockStatusBuilder->expects($this->any())->method('populateWithArray')->with($array);
+
+        // 4. Run tested method
+        $result = $this->model->getProductStockStatusBySku($productSku);
 
         // 5. Compare actual result with expected result
-        $this->assertEquals($expectedResult, $result);
+        $this->assertEquals($stockStatusDataObject, $result);
     }
 
     /**
      * @return array
      */
-    public function getProductStockStatusDataProvider()
+    public function getProductStockStatusBySkuDataProvider()
+    {
+        $productId = 123;
+
+        $productStatusInStock = true;
+        $fullStockQty = 456;
+
+        $productStatusOutOfStock = false;
+        $emptyStockQty = 0;
+        return [
+            [
+                'sku1',
+                $productId,
+                1,
+                [$productId => $productStatusInStock],
+                $fullStockQty,
+                [
+                    Data\StockStatus::STOCK_STATUS => $productStatusInStock,
+                    Data\StockStatus::STOCK_QTY => $fullStockQty
+                ]
+            ],
+            [
+                'sku1',
+                $productId,
+                1,
+                [$productId => $productStatusOutOfStock],
+                $emptyStockQty,
+                [
+                    Data\StockStatus::STOCK_STATUS => $productStatusOutOfStock,
+                    Data\StockStatus::STOCK_QTY => $emptyStockQty
+                ]
+            ],
+        ];
+    }
+
+    /**
+     * @param string $productSku
+     * @param int $productId
+     * @dataProvider getProductStockWithExceptionStatusBySkuDataProvider
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testGetProductStockWithExceptionStatusBySku($productSku, $productId)
+    {
+        // 1. Create mocks
+        /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // 2. Set fixtures
+        $this->productLoader->expects($this->any())->method('load')->will($this->returnValueMap([
+            [$productSku, $product]
+        ]));
+        $product->expects($this->any())->method('getId')->will($this->returnValue($productId));
+
+        // 3. Run tested method
+        $this->model->getProductStockStatusBySku($productSku);
+    }
+
+    /**
+     * @return array
+     */
+    public function getProductStockWithExceptionStatusBySkuDataProvider()
     {
         return [
-            [[1,2], 3, 4, []],
+            ['sku1', null],
+            ['sku1', false],
+            ['sku1', 0],
+        ];
+    }
+
+    /**
+     * @covers \Magento\CatalogInventory\Service\V1\StockStatusService::getLowStockItems
+     */
+    public function testGetterOfLowStockItems()
+    {
+        $websiteId = 1;
+        $criteriaData = [
+            'qty'          => 1,
+            'current_page' => 1,
+            'page_size'    => 10
         ];
+        $scope = $this->getMockBuilder('Magento\Store\Model\Website')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $scope->expects($this->any())->method('getId')->will($this->returnValue($websiteId));
+        $this->scopeResolver->expects($this->any())->method('getScope')->will($this->returnValue($scope));
+
+        $builder = $this->getMockBuilder('Magento\Framework\Service\Data\AbstractObjectBuilder')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $builder->expects($this->any())->method('getData')->will($this->returnValue($criteriaData));
+
+        $statusItem = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Status')
+            ->setMethods(['__wakeup', 'getSku'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $statusItem->expects($this->any())->method('getSku')->will($this->returnValue('test_sku'));
+
+        $collection = $this->getMockBuilder('Magento\CatalogInventory\Model\Resource\Stock\Status\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $collection->expects($this->any())->method('getSize')->will($this->returnValue(1));
+        $collection->expects($this->any())->method('getIterator')
+            ->will($this->returnValue(new \ArrayIterator([$statusItem])));
+        $this->itemsFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+
+        /** @var \Magento\Framework\Service\Data\AbstractObjectBuilder $builder */
+        $lowStockCriteria = new Data\LowStockCriteria($builder);
+
+        // Expected results
+        $collection->expects($this->atLeastOnce())->method('addWebsiteFilter')->with($scope);
+        $collection->expects($this->atLeastOnce())->method('addQtyFilter')->with($criteriaData['qty']);
+        $collection->expects($this->atLeastOnce())->method('setCurPage')->with($criteriaData['current_page']);
+        $collection->expects($this->atLeastOnce())->method('setPageSize')->with($criteriaData['page_size']);
+
+        $this->lowStockResultBuilder->expects($this->atLeastOnce())->method('setSearchCriteria')
+            ->with($lowStockCriteria);
+        $this->lowStockResultBuilder->expects($this->atLeastOnce())->method('setTotalCount')->with(1);
+        $this->lowStockResultBuilder->expects($this->atLeastOnce())->method('setItems')->with(['test_sku']);
+
+        // Run tested method
+        $this->model->getLowStockItems($lowStockCriteria);
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Checkout/Model/CartTest.php b/dev/tests/unit/testsuite/Magento/Checkout/Model/CartTest.php
index aa7e63f09d0..e1c795c886e 100644
--- a/dev/tests/unit/testsuite/Magento/Checkout/Model/CartTest.php
+++ b/dev/tests/unit/testsuite/Magento/Checkout/Model/CartTest.php
@@ -40,13 +40,19 @@ class CartTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Checkout\Model\Session|\PHPUnit_Framework_MockObject_MockObject */
     protected $checkoutSessionMock;
 
-    /** @var \Magento\CatalogInventory\Service\V1\StockItem|\PHPUnit_Framework_MockObject_MockObject */
+    /** @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject */
     protected $stockItemMock;
 
     protected function setUp()
     {
         $this->checkoutSessionMock = $this->getMock('Magento\Checkout\Model\Session', [], [], '', false);
-        $this->stockItemMock = $this->getMock('Magento\CatalogInventory\Service\V1\StockItem', [], [], '', false);
+        $this->stockItemMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
 
         $this->objectManagerHelper = new ObjectManagerHelper($this);
         $this->cart = $this->objectManagerHelper->getObject(
diff --git a/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributesTest.php b/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributesTest.php
index f32303c1d8f..3170cf72a6e 100644
--- a/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributesTest.php
+++ b/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Attribute/SuggestConfigurableAttributesTest.php
@@ -104,7 +104,7 @@ class SuggestConfigurableAttributesTest extends \PHPUnit_Framework_TestCase
         )->will(
             $this->returnValue('body')
         );
-        $this->responseMock->expects($this->once())->method('setBody')->with('body');
+        $this->responseMock->expects($this->once())->method('representJson')->with('body');
         $this->suggestAttributes->indexAction();
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProductTest.php b/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProductTest.php
index c137b2a823b..012af56733e 100644
--- a/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProductTest.php
+++ b/dev/tests/unit/testsuite/Magento/ConfigurableProduct/Model/Quote/Item/QuantityValidator/Initializer/Option/Plugin/ConfigurableProductTest.php
@@ -27,9 +27,9 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @param array $data
-     * @dataProvider beforeInitializeDataProvider
+     * @dataProvider aroundGetStockItemDataProvider
      */
-    public function testBeforeInitialize(array $data)
+    public function testAroundGetStockItem(array $data)
     {
         $subjectMock = $this->getMock(
             'Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option',
@@ -53,29 +53,22 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
         $stockItemMock->expects($this->$matcherMethod())
             ->method('setProductName');
 
-        $productMock = $this->getMock(
-            'Magento\Catalog\Model\Product', array('getStockItem', '__wakeup'), array(), '', false
-        );
-        $productMock->expects($this->once())
-            ->method('getStockItem')
-            ->will($this->returnValue($stockItemMock));
-
         $optionMock = $this->getMock(
             'Magento\Sales\Model\Quote\Item\Option', array('getProduct', '__wakeup'), array(), '', false
         );
-        $optionMock->expects($this->once())
-            ->method('getProduct')
-            ->will($this->returnValue($productMock));
 
-        $model = new ConfigurableProduct;
-        $model->beforeInitialize($subjectMock, $optionMock, $quoteItemMock, 0);
+        $proceed = function () use ($stockItemMock) {
+            return $stockItemMock;
+        };
 
+        $model = new ConfigurableProduct;
+        $model->aroundGetStockItem($subjectMock, $proceed, $optionMock, $quoteItemMock, 0);
     }
 
     /**
      * @return array
      */
-    public function beforeInitializeDataProvider()
+    public function aroundGetStockItemDataProvider()
     {
         return array(
             array(
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/Data/FileContentValidatorTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/Data/FileContentValidatorTest.php
new file mode 100644
index 00000000000..9ca32b1c4b1
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/Data/FileContentValidatorTest.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\Data;
+
+class FileContentValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FileContentValidator
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fileContentMock;
+
+    protected function setUp()
+    {
+        $this->validator = new FileContentValidator();
+        $this->fileContentMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+    }
+
+    public function testIsValid()
+    {
+        $this->fileContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode('test content')
+        ));
+        $this->fileContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+
+        $this->assertTrue($this->validator->isValid($this->fileContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Provided content must be valid base64 encoded data.
+     */
+    public function testIsValidThrowsExceptionIfProvidedContentIsNotBase64Encoded()
+    {
+        $this->fileContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            'not_a_base64_encoded_content'
+        ));
+        $this->fileContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+        $this->assertTrue($this->validator->isValid($this->fileContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Provided file name contains forbidden characters.
+     * @dataProvider getInvalidNames
+     * @param string $fileName
+     */
+    public function testIsValidThrowsExceptionIfProvidedImageNameContainsForbiddenCharacters($fileName)
+    {
+        $this->fileContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode('test content')
+        ));
+        $this->fileContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            $fileName
+        ));
+        $this->assertTrue($this->validator->isValid($this->fileContentMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidNames()
+    {
+        return array(
+            array('test\test'),
+            array('test/test'),
+            array('test:test'),
+            array('test"test'),
+            array('test*test'),
+            array('test;test'),
+            array('test?test'),
+            array('test{test'),
+            array('test}test'),
+            array('test|test'),
+            array('test(test'),
+            array('test)test'),
+            array('test<test'),
+            array('test>test'),
+        );
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidatorTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidatorTest.php
new file mode 100644
index 00000000000..db4f20fbd72
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidatorTest.php
@@ -0,0 +1,261 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink\Data;
+
+class DownloadableLinkContentValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var DownloadableLinkContentValidator
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fileValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $urlValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkFileMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $sampleFileMock;
+
+    protected function setUp()
+    {
+        $this->fileValidatorMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContentValidator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->urlValidatorMock = $this->getMock(
+            '\Magento\Framework\Url\Validator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->linkFileMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->sampleFileMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->validator = new DownloadableLinkContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
+    }
+
+    public function testIsValid()
+    {
+        $linkContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+        );
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $contentMock = $this->getLinkContentMock($linkContentData);
+        $this->assertTrue($this->validator->isValid($contentMock));
+    }
+
+    /**
+     * @param string|int|float $sortOrder
+     * @dataProvider getInvalidSortOrder
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Sort order must be a positive integer.
+     */
+    public function testIsValidThrowsExceptionIfSortOrderIsInvalid($sortOrder)
+    {
+        $linkContentData = array(
+            'title' => 'Title',
+            'sort_order' => $sortOrder,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+        );
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $contentMock = $this->getLinkContentMock($linkContentData);
+        $this->validator->isValid($contentMock);
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidSortOrder()
+    {
+        return array(
+            array(-1),
+            array('string'),
+            array(1.1),
+        );
+    }
+
+    /**
+     * @param string|int|float $price
+     * @dataProvider getInvalidPrice
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Link price must have numeric positive value.
+     */
+    public function testIsValidThrowsExceptionIfPriceIsInvalid($price)
+    {
+        $linkContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => $price,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+        );
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $contentMock = $this->getLinkContentMock($linkContentData);
+        $this->validator->isValid($contentMock);
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidPrice()
+    {
+        return array(
+            array(-1),
+            array('string'),
+        );
+    }
+
+    /**
+     * @param string|int|float $numberOfDownloads
+     * @dataProvider getInvalidNumberOfDownloads
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Number of downloads must be a positive integer.
+     */
+    public function testIsValidThrowsExceptionIfNumberOfDownloadsIsInvalid($numberOfDownloads)
+    {
+        $linkContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => 10.5,
+            'shareable' => true,
+            'number_of_downloads' => $numberOfDownloads,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+        );
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $contentMock = $this->getLinkContentMock($linkContentData);
+        $this->validator->isValid($contentMock);
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidNumberOfDownloads()
+    {
+        return array(
+            array(-1),
+            array(2.71828),
+            array('string'),
+        );
+    }
+
+    /**
+     * @param array $linkContentData
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getLinkContentMock(array $linkContentData)
+    {
+        $contentMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
+            $linkContentData['title']
+        ));
+        $contentMock->expects($this->any())->method('getPrice')->will($this->returnValue(
+            $linkContentData['price']
+        ));
+        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $linkContentData['sort_order']
+        ));
+        $contentMock->expects($this->any())->method('isShareable')->will($this->returnValue(
+            $linkContentData['shareable']
+        ));
+        $contentMock->expects($this->any())->method('getNumberOfDownloads')->will($this->returnValue(
+            $linkContentData['number_of_downloads']
+        ));
+        $contentMock->expects($this->any())->method('getLinkType')->will($this->returnValue(
+            $linkContentData['link_type']
+        ));
+        $contentMock->expects($this->any())->method('getLinkFile')->will($this->returnValue(
+            $this->linkFileMock
+        ));
+        if (isset($linkContentData['link_url'])) {
+            $contentMock->expects($this->any())->method('getLinkUrl')->will($this->returnValue(
+                $linkContentData['link_url']
+            ));
+        }
+        if (isset($linkContentData['sample_url'])) {
+            $contentMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
+                $linkContentData['sample_url']
+            ));
+        }
+        if (isset($linkContentData['sample_type'])) {
+            $contentMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
+                $linkContentData['sample_type']
+            ));
+        }
+        $contentMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
+            $this->sampleFileMock
+        ));
+        return $contentMock;
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php
new file mode 100644
index 00000000000..97020571853
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php
@@ -0,0 +1,302 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+use Magento\TestFramework\Helper\ObjectManager;
+
+class ReadServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\TestFramework\Helper\ObjectManager
+     */
+    protected $objectHelper;
+
+    /**
+     * @var \Magento\Downloadable\Service\V1\DownloadableLink\ReadService
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productTypeMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    protected function setUp()
+    {
+        $this->objectHelper = new ObjectManager($this);
+
+        $this->repositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository', [], [], '', false);
+        $this->productTypeMock = $this->getMock('\Magento\Downloadable\Model\Product\Type', [], [], '', false);
+
+        $linkBuilder = $this->objectHelper->getObject(
+            'Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkInfoBuilder'
+        );
+
+        $sampleBuilder = $this->objectHelper->getObject(
+            'Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableSampleInfoBuilder'
+        );
+
+        $resourceBuilder = $this->objectHelper->getObject(
+            '\Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableResourceInfoBuilder'
+        );
+        $this->service = $this->objectHelper->getObject(
+            '\Magento\Downloadable\Service\V1\DownloadableLink\ReadService',
+            [
+                'productRepository' => $this->repositoryMock,
+                'downloadableType' => $this->productTypeMock,
+                'linkBuilder' => $linkBuilder,
+                'sampleBuilder' => $sampleBuilder,
+                'resourceBuilder' => $resourceBuilder,
+            ]
+        );
+
+        $this->productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false);
+    }
+
+    /**
+     * @dataProvider getLinksProvider
+     */
+    public function testGetLinks($inputData, $inputFileData, $expectationData)
+    {
+        $productSku = 'downloadable_sku';
+
+        $this->repositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->will($this->returnValue($this->productMock));
+
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            [
+                'getId', 'getStoreTitle', 'getTitle', 'getPrice', 'getNumberOfDownloads',
+                'getSortOrder', 'getIsShareable', 'getData', '__wakeup'
+            ],
+            [],
+            '',
+            false
+        );
+
+        $this->productTypeMock->expects($this->once())
+            ->method('getLinks')
+            ->with($this->productMock)
+            ->will($this->returnValue([$linkMock]));
+
+        $this->setLinkAssertions($linkMock, $inputData, $inputFileData);
+
+        $links = $this->service->getLinks($productSku);
+        $this->assertEquals(1, count($links));
+        $this->assertEquals($expectationData, reset($links)->__toArray());
+    }
+
+    /**
+     * @dataProvider getSamplesProvider
+     */
+    public function testGetSamples($inputData, $inputFileData, $expectationData)
+    {
+        $productSku = 'downloadable_sku';
+
+        $this->repositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->will($this->returnValue($this->productMock));
+
+        $sampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            [
+                'getId', 'getStoreTitle', 'getTitle',
+                'getSortOrder', 'getData', '__wakeup'
+            ],
+            [],
+            '',
+            false
+        );
+
+        $this->productTypeMock->expects($this->once())
+            ->method('getSamples')
+            ->with($this->productMock)
+            ->will($this->returnValue([$sampleMock]));
+
+        $this->setSampleAssertions($sampleMock, $inputData, $inputFileData);
+
+        $samples = $this->service->getSamples($productSku);
+        $this->assertEquals(1, count($samples));
+        $this->assertEquals($expectationData, reset($samples)->__toArray());
+    }
+
+    protected function setLinkAssertions($resource, $inputData, $fileData)
+    {
+        $resource->expects($this->once())->method('getId')->will($this->returnValue($inputData['id']));
+        $resource->expects($this->once())->method('getStoreTitle')
+            ->will($this->returnValue($inputData['store_title']));
+        $resource->expects($this->once())->method('getTitle')
+            ->will($this->returnValue($inputData['title']));
+        $resource->expects($this->any())->method('getPrice')
+            ->will($this->returnValue($inputData['price']));
+        $resource->expects($this->once())->method('getNumberOfDownloads')
+            ->will($this->returnValue($inputData['number_of_downloads']));
+        $resource->expects($this->once())->method('getSortOrder')
+            ->will($this->returnValue($inputData['sort_order']));
+        $resource->expects($this->once())->method('getIsShareable')
+            ->will($this->returnValue($inputData['is_shareable']));
+        $resource->expects($this->any())->method('getData')->will($this->returnValueMap($fileData));
+
+    }
+
+    protected function setSampleAssertions($resource, $inputData, $fileData)
+    {
+        $resource->expects($this->once())->method('getId')->will($this->returnValue($inputData['id']));
+        $resource->expects($this->once())->method('getStoreTitle')
+            ->will($this->returnValue($inputData['store_title']));
+        $resource->expects($this->once())->method('getTitle')
+            ->will($this->returnValue($inputData['title']));
+        $resource->expects($this->once())->method('getSortOrder')
+            ->will($this->returnValue($inputData['sort_order']));
+        $resource->expects($this->any())->method('getData')->will($this->returnValueMap($fileData));
+
+    }
+
+    public function getLinksProvider()
+    {
+        $linkData = [
+            'id' => 324,
+            'store_title' => 'rock melody',
+            'title' => 'just melody',
+            'price' => 23,
+            'number_of_downloads' => 3,
+            'sort_order' => 21,
+            'is_shareable' => 2,
+        ];
+
+        $linkDataGlobalTitle = $linkData;
+        $linkDataGlobalTitle['store_title'] = null;
+        $linkDataGlobalTitle['title'] = 'global title';
+
+        $linkFileData = [
+            ['link_type', null, 'url'],
+            ['link_url', null, 'http://link.url'],
+            ['link_file', null, ''],
+            ['sample_type', null, 'file'],
+            ['sample_url', null, ''],
+            ['sample_file', null, '/r/o/rock.melody.ogg'],
+        ];
+
+        $linkUrl = [
+            'type' => 'url',
+            'url' => 'http://link.url',
+            'file' => '',
+        ];
+
+        $sampleFile = [
+            'type' => 'file',
+            'url' => '',
+            'file' => '/r/o/rock.melody.ogg',
+        ];
+
+        $linkExpectation = [
+            'id' => $linkData['id'],
+            'title' => $linkData['store_title'],
+            'price' => $linkData['price'],
+            'number_of_downloads' => $linkData['number_of_downloads'],
+            'sort_order' => $linkData['sort_order'],
+            'shareable' => $linkData['is_shareable'],
+            'link_resource' => $linkUrl,
+            'sample_resource' => $sampleFile,
+        ];
+
+        $linkExpectationGlobalTitle = $linkExpectation;
+        $linkExpectationGlobalTitle['title'] = 'global title';
+
+        return [
+            'linksWithStoreTitle' => [
+                $linkData,
+                $linkFileData,
+                $linkExpectation
+            ],
+            'linksWithGlobalTitle' => [
+                $linkDataGlobalTitle,
+                $linkFileData,
+                $linkExpectationGlobalTitle
+            ],
+        ];
+    }
+
+    public function getSamplesProvider()
+    {
+        $sampleData = [
+            'id' => 324,
+            'store_title' => 'rock melody sample',
+            'title' => 'just melody sample',
+            'sort_order' => 21,
+        ];
+
+        $sampleDataGlobalTitle = $sampleData;
+        $sampleDataGlobalTitle['store_title'] = null;
+        $sampleDataGlobalTitle['title'] = 'sample global title';
+
+        $sampleFileData = [
+            ['sample_type', null, 'file'],
+            ['sample_url', null, ''],
+            ['sample_file', null, '/r/o/rock.melody.ogg'],
+        ];
+
+        $sampleFile = [
+            'type' => 'file',
+            'url' => '',
+            'file' => '/r/o/rock.melody.ogg',
+        ];
+
+        $sampleExpectation = [
+            'id' => $sampleData['id'],
+            'title' => $sampleData['store_title'],
+            'sort_order' => $sampleData['sort_order'],
+            'sample_resource' => $sampleFile,
+        ];
+
+        $linkExpectationGlobalTitle = $sampleExpectation;
+        $linkExpectationGlobalTitle['title'] = 'sample global title';
+
+        return [
+            'samplesWithStoreTitle' => [
+                $sampleData,
+                $sampleFileData,
+                $sampleExpectation
+            ],
+            'samplesWithGlobalTitle' => [
+                $sampleDataGlobalTitle,
+                $sampleFileData,
+                $linkExpectationGlobalTitle
+            ],
+        ];
+    }
+}
\ No newline at end of file
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php
new file mode 100644
index 00000000000..0cd7cb1ac1d
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php
@@ -0,0 +1,347 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableLink;
+
+class WriteServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $contentValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $contentUploaderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $jsonEncoderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var WriteService
+     */
+    protected $service;
+
+    protected function setUp()
+    {
+        $this->repositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository', array(), array(), '', false);
+        $this->contentValidatorMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContentValidator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->contentUploaderMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContentUploaderInterface'
+        );
+        $this->jsonEncoderMock = $this->getMock(
+            '\Magento\Framework\Json\EncoderInterface'
+        );
+        $this->linkFactoryMock = $this->getMock(
+            '\Magento\Downloadable\Model\LinkFactory',
+            array('create'),
+            array(),
+            '',
+            false
+        );
+        $this->productMock = $this->getMock(
+            '\Magento\Catalog\Model\Product',
+            array('__wakeup', 'getTypeId', 'setDownloadableData', 'save', 'getId', 'getStoreId', 'getStore',
+                'getWebsiteIds'),
+            array(),
+            '',
+            false
+        );
+        $this->service = new WriteService(
+            $this->repositoryMock,
+            $this->contentValidatorMock,
+            $this->contentUploaderMock,
+            $this->jsonEncoderMock,
+            $this->linkFactoryMock
+        );
+    }
+
+    /**
+     * @param array $linkContentData
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getLinkContentMock(array $linkContentData)
+    {
+        $contentMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableLink\Data\DownloadableLinkContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $contentMock->expects($this->any())->method('getPrice')->will($this->returnValue(
+            $linkContentData['price']
+        ));
+        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
+            $linkContentData['title']
+        ));
+        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $linkContentData['sort_order']
+        ));
+        $contentMock->expects($this->any())->method('getNumberOfDownloads')->will($this->returnValue(
+            $linkContentData['number_of_downloads']
+        ));
+        $contentMock->expects($this->any())->method('isShareable')->will($this->returnValue(
+            $linkContentData['shareable']
+        ));
+        if (isset($linkContentData['link_type'])) {
+            $contentMock->expects($this->any())->method('getLinkType')->will($this->returnValue(
+                $linkContentData['link_type']
+            ));
+        }
+        if (isset($linkContentData['link_url'])) {
+            $contentMock->expects($this->any())->method('getLinkUrl')->will($this->returnValue(
+                $linkContentData['link_url']
+            ));
+        }
+        return $contentMock;
+    }
+
+    public function testCreate()
+    {
+        $productSku = 'simple';
+        $linkContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'url',
+            'link_url' => 'http://example.com/'
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
+        $linkContentMock = $this->getLinkContentMock($linkContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+            ->will($this->returnValue(true));
+
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with(array(
+            'link' => array(
+                array(
+                    'link_id' => 0,
+                    'is_delete' => 0,
+                    'type' => $linkContentData['link_type'],
+                    'sort_order' => $linkContentData['sort_order'],
+                    'title' => $linkContentData['title'],
+                    'price' => $linkContentData['price'],
+                    'number_of_downloads' => $linkContentData['number_of_downloads'],
+                    'is_shareable' => $linkContentData['shareable'],
+                    'link_url' => $linkContentData['link_url'],
+                ),
+            ),
+        ));
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->create($productSku, $linkContentMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Link title cannot be empty.
+     */
+    public function testCreateThrowsExceptionIfTitleIsEmpty()
+    {
+        $productSku = 'simple';
+        $linkContentData = array(
+            'title' => '',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'number_of_downloads' => 100,
+            'shareable' => true,
+            'link_type' => 'url',
+            'link_url' => 'http://example.com/'
+        );
+
+        $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $linkContentMock = $this->getLinkContentMock($linkContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+            ->will($this->returnValue(true));
+
+        $this->productMock->expects($this->never())->method('save');
+
+        $this->service->create($productSku, $linkContentMock);
+
+    }
+
+    public function testUpdate()
+    {
+        $websiteId = 1;
+        $linkId = 1;
+        $productSku = 'simple';
+        $productId = 1;
+        $linkContentData = array(
+            'title' => 'Updated Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $storeMock = $this->getMock('\Magento\Store\Model\Store', array(), array(), '', false);
+        $storeMock->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId));
+        $this->productMock->expects($this->any())->method('getStore')->will($this->returnValue($storeMock));
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            array('__wakeup', 'setTitle', 'setPrice', 'setSortOrder', 'setIsShareable', 'setNumberOfDownloads', 'getId',
+                'setProductId', 'setStoreId', 'setWebsiteId', 'setProductWebsiteIds', 'load', 'save', 'getProductId'),
+            array(),
+            '',
+            false
+        );
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
+        $linkContentMock = $this->getLinkContentMock($linkContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+            ->will($this->returnValue(true));
+
+        $linkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $linkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setTitle')->with($linkContentData['title'])
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setSortOrder')->with($linkContentData['sort_order'])
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setPrice')->with($linkContentData['price'])
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setIsShareable')->with($linkContentData['shareable'])
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setNumberOfDownloads')->with($linkContentData['number_of_downloads'])
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setProductId')->with($productId)
+            ->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setStoreId')->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setWebsiteId')->with($websiteId)->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('setProductWebsiteIds')->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('save')->will($this->returnSelf());
+
+        $this->assertTrue($this->service->update($productSku, $linkId, $linkContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Link title cannot be empty.
+     */
+    public function testUpdateThrowsExceptionIfTitleIsEmptyAndScopeIsGlobal()
+    {
+        $linkId = 1;
+        $productSku = 'simple';
+        $productId = 1;
+        $linkContentData = array(
+            'title' => '',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'number_of_downloads' => 100,
+            'shareable' => true,
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            array('__wakeup', 'getId', 'load', 'save', 'getProductId'),
+            array(),
+            '',
+            false
+        );
+        $linkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $linkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
+        $linkContentMock = $this->getLinkContentMock($linkContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+            ->will($this->returnValue(true));
+
+        $linkMock->expects($this->never())->method('save');
+
+        $this->service->update($productSku, $linkId, $linkContentMock, true);
+    }
+
+    public function testDelete()
+    {
+        $linkId = 1;
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
+        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+        $linkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $linkMock->expects($this->once())->method('delete');
+
+        $this->assertTrue($this->service->delete($linkId));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage There is no downloadable link with provided ID.
+     */
+    public function testDeleteThrowsExceptionIfLinkIdIsNotValid()
+    {
+        $linkId = 1;
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
+        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+        $linkMock->expects($this->once())->method('getId');
+        $linkMock->expects($this->never())->method('delete');
+
+        $this->service->delete($linkId);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidatorTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidatorTest.php
new file mode 100644
index 00000000000..76fab606d97
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidatorTest.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample\Data;
+
+class DownloadableSampleContentValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var DownloadableSampleContentValidator
+     */
+    protected $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fileValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $urlValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkFileMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $sampleFileMock;
+
+    protected function setUp()
+    {
+        $this->fileValidatorMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContentValidator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->urlValidatorMock = $this->getMock(
+            '\Magento\Framework\Url\Validator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->sampleFileMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->validator = new DownloadableSampleContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
+    }
+
+    public function testIsValid()
+    {
+        $sampleContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'sample_type' => 'file',
+        );
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $contentMock = $this->getSampleContentMock($sampleContentData);
+        $this->assertTrue($this->validator->isValid($contentMock));
+    }
+
+    /**
+     * @param string|int|float $sortOrder
+     * @dataProvider getInvalidSortOrder
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Sort order must be a positive integer.
+     */
+    public function testIsValidThrowsExceptionIfSortOrderIsInvalid($sortOrder)
+    {
+        $sampleContentData = array(
+            'title' => 'Title',
+            'sort_order' => $sortOrder,
+            'sample_type' => 'file',
+        );
+        $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
+        $this->validator->isValid($this->getSampleContentMock($sampleContentData));
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidSortOrder()
+    {
+        return array(
+            array(-1),
+            array(1.1),
+            array('string'),
+        );
+    }
+
+    /**
+     * @param array $sampleContentData
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getSampleContentMock(array $sampleContentData)
+    {
+        $contentMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
+            $sampleContentData['title']
+        ));
+
+        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $sampleContentData['sort_order']
+        ));
+        $contentMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
+            $sampleContentData['sample_type']
+        ));
+        if (isset($sampleContentData['sample_url'])) {
+            $contentMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
+                $sampleContentData['sample_url']
+            ));
+        }
+        $contentMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
+            $this->sampleFileMock
+        ));
+        return $contentMock;
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php
new file mode 100644
index 00000000000..17c4a9b4f7a
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php
@@ -0,0 +1,313 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     {license_sample}
+ */
+namespace Magento\Downloadable\Service\V1\DownloadableSample;
+
+class WriteServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $contentValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $contentUploaderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $jsonEncoderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $sampleFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var WriteService
+     */
+    protected $service;
+
+    protected function setUp()
+    {
+        $this->productMock = $this->getMock(
+            '\Magento\Catalog\Model\Product',
+            array('__wakeup', 'getTypeId', 'setDownloadableData', 'save', 'getId', 'getStoreId'),
+            array(),
+            '',
+            false
+        );
+        $this->repositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository', array(), array(), '', false);
+        $this->contentValidatorMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContentValidator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->contentUploaderMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\Data\FileContentUploaderInterface'
+        );
+        $this->jsonEncoderMock = $this->getMock(
+            '\Magento\Framework\Json\EncoderInterface'
+        );
+        $this->sampleFactoryMock = $this->getMock(
+            '\Magento\Downloadable\Model\SampleFactory',
+            array('create'),
+            array(),
+            '',
+            false
+        );
+
+        $this->service = new WriteService(
+            $this->repositoryMock,
+            $this->contentValidatorMock,
+            $this->contentUploaderMock,
+            $this->jsonEncoderMock,
+            $this->sampleFactoryMock
+        );
+    }
+
+    /**
+     * @param array $sampleContentData
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getSampleContentMock(array $sampleContentData)
+    {
+        $contentMock = $this->getMock(
+            '\Magento\Downloadable\Service\V1\DownloadableSample\Data\DownloadableSampleContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+
+        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
+            $sampleContentData['title']
+        ));
+        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $sampleContentData['sort_order']
+        ));
+
+        if (isset($sampleContentData['sample_type'])) {
+            $contentMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
+                $sampleContentData['sample_type']
+            ));
+        }
+        if (isset($sampleContentData['sample_url'])) {
+            $contentMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
+                $sampleContentData['sample_url']
+            ));
+        }
+        return $contentMock;
+    }
+
+    public function testCreate()
+    {
+        $productSku = 'simple';
+        $sampleContentData = array(
+            'title' => 'Title',
+            'sort_order' => 1,
+            'sample_type' => 'url',
+            'sample_url' => 'http://example.com/'
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
+        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+            ->will($this->returnValue(true));
+
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with(array(
+            'sample' => array(
+                array(
+                    'sample_id' => 0,
+                    'is_delete' => 0,
+                    'type' => $sampleContentData['sample_type'],
+                    'sort_order' => $sampleContentData['sort_order'],
+                    'title' => $sampleContentData['title'],
+                    'sample_url' => $sampleContentData['sample_url'],
+                ),
+            ),
+        ));
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->create($productSku, $sampleContentMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Sample title cannot be empty.
+     */
+    public function testCreateThrowsExceptionIfTitleIsEmpty()
+    {
+        $productSku = 'simple';
+        $sampleContentData = array(
+            'title' => '',
+            'sort_order' => 1,
+            'sample_type' => 'url',
+            'sample_url' => 'http://example.com/'
+        );
+
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
+        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+            ->will($this->returnValue(true));
+
+        $this->productMock->expects($this->never())->method('save');
+
+        $this->service->create($productSku, $sampleContentMock);
+
+    }
+
+    public function testUpdate()
+    {
+        $sampleId = 1;
+        $productId = 1;
+        $productSku = 'simple';
+        $sampleContentData = array(
+            'title' => 'Updated Title',
+            'sort_order' => 1,
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $sampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            array('__wakeup', 'setTitle', 'setSortOrder', 'getId', 'setProductId', 'setStoreId',
+                'load', 'save', 'getProductId'),
+            array(),
+            '',
+            false
+        );
+        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
+        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+            ->will($this->returnValue(true));
+
+        $sampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $sampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('setTitle')->with($sampleContentData['title'])
+            ->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('setSortOrder')->with($sampleContentData['sort_order'])
+            ->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('setProductId')->with($productId)
+            ->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('setStoreId')->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('save')->will($this->returnSelf());
+
+        $this->assertTrue($this->service->update($productSku, $sampleId, $sampleContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Sample title cannot be empty.
+     */
+    public function testUpdateThrowsExceptionIfTitleIsEmptyAndScopeIsGlobal()
+    {
+        $sampleId = 1;
+        $productSku = 'simple';
+        $productId = 1;
+        $sampleContentData = array(
+            'title' => '',
+            'sort_order' => 1,
+        );
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $sampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            array('__wakeup', 'getId', 'load', 'save', 'getProductId'),
+            array(),
+            '',
+            false
+        );
+        $sampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+        $sampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
+        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+            ->will($this->returnValue(true));
+
+        $sampleMock->expects($this->never())->method('save');
+
+        $this->service->update($productSku, $sampleId, $sampleContentMock, true);
+    }
+
+    public function testDelete()
+    {
+        $sampleId = 1;
+        $sampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
+        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+        $sampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $sampleMock->expects($this->once())->method('delete');
+
+        $this->assertTrue($this->service->delete($sampleId));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage There is no downloadable sample with provided ID.
+     */
+    public function testDeleteThrowsExceptionIfSampleIdIsNotValid()
+    {
+        $sampleId = 1;
+        $sampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
+        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+        $sampleMock->expects($this->once())->method('getId');
+        $sampleMock->expects($this->never())->method('delete');
+
+        $this->service->delete($sampleId);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Framework/App/Response/HttpTest.php b/dev/tests/unit/testsuite/Magento/Framework/App/Response/HttpTest.php
index 5ca1d4a1286..b258cb23cc4 100644
--- a/dev/tests/unit/testsuite/Magento/Framework/App/Response/HttpTest.php
+++ b/dev/tests/unit/testsuite/Magento/Framework/App/Response/HttpTest.php
@@ -159,4 +159,15 @@ class HttpTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($cacheControl, $this->_model->getHeader('Cache-Control')['value']);
         $this->assertEquals($expires, $this->_model->getHeader('Expires')['value']);
     }
+
+    /**
+     * Test setting body in JSON format
+     */
+    public function testRepresentJson()
+    {
+        $this->_model->setHeader('Content-Type', 'text/javascript');
+        $this->_model->representJson('json_string');
+        $this->assertEquals('application/json', $this->_model->getHeader('Content-Type')['value']);
+        $this->assertEquals('json_string', $this->_model->getBody('default'));
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/Attribute/ContentTest.php b/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/Attribute/ContentTest.php
new file mode 100644
index 00000000000..ff0cf157981
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/Attribute/ContentTest.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\GoogleShopping\Model\Attribute;
+
+class ContentTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @dataProvider convertAttributeDataProvider
+     * @param int|null $attributeId
+     * @param string $description
+     * @param string $mapValue
+     */
+    public function testConvertAttribute($attributeId, $description, $mapValue)
+    {
+        $product = $this->getMock(
+            '\Magento\Catalog\Model\Product',
+            array('getDescription', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+        $product->expects($this->any())->method('getDescription')->will($this->returnValue($description));
+
+        $defaultFrontend = $this->getMock(
+            'Magento\Eav\Model\Entity\Attribute\Frontend\DefaultFrontend',
+            array('getValue'),
+            array(),
+            '',
+            false
+        );
+        $defaultFrontend->expects($this->any())
+            ->method('getValue')
+            ->with($product)
+            ->will($this->returnValue($mapValue));
+
+        $attribute = $this->getMock(
+            '\Magento\Catalog\Model\Entity\Attribute',
+            array('getFrontend', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+        $attribute->expects($this->any())->method('getFrontend')->will($this->returnValue($defaultFrontend));
+
+        $productHelper = $this->getMock(
+            '\Magento\GoogleShopping\Helper\Product',
+            array('getProductAttribute'),
+            array(),
+            '',
+            false
+        );
+        $productHelper->expects($this->any())
+            ->method('getProductAttribute')
+            ->with($product, $attributeId)
+            ->will($this->returnValue($attribute));
+
+
+        $gsData = $this->getMock(
+            '\Magento\GoogleShopping\Helper\Data',
+            array('cleanAtomAttribute'),
+            array(),
+            '',
+            false
+        );
+        $gsData->expects($this->once())
+            ->method('cleanAtomAttribute')
+            ->with($mapValue)
+            ->will($this->returnValue($mapValue));
+
+        $model = (new \Magento\TestFramework\Helper\ObjectManager($this))
+            ->getObject(
+                '\Magento\GoogleShopping\Model\Attribute\Content',
+                array('gsProduct' => $productHelper, 'gsData' => $gsData)
+            );
+
+        $service = $this->getMock('Zend_Gdata_App', array('newContent', 'setText'), array(), '', false);
+        $service->expects($this->once())->method('newContent')->will($this->returnSelf());
+        $service->expects($this->once())->method('setText')->with($mapValue)->will($this->returnValue($mapValue));
+
+        $entry = $this->getMock(
+            '\Magento\Framework\Gdata\Gshopping\Entry',
+            array('getService', 'setContent'),
+            array(),
+            '',
+            false
+        );
+        $entry->expects($this->once())->method('getService')->will($this->returnValue($service));
+        $entry->expects($this->once())->method('setContent')->with($mapValue);
+
+        $groupAttributeDescription = $this->getMock(
+            '\Magento\GoogleShopping\Model\Attribute\DefaultAttribute',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $model->setGroupAttributeDescription($groupAttributeDescription);
+        $model->setAttributeId($attributeId);
+
+        $this->assertEquals($entry, $model->convertAttribute($product, $entry));
+    }
+
+    /**
+     * @return array
+     */
+    public function convertAttributeDataProvider()
+    {
+        return array(
+            array(1, 'description', 'short description'),
+            array(null, 'description', 'description'),
+        );
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Integration/Controller/Adminhtml/IntegrationTest.php b/dev/tests/unit/testsuite/Magento/Integration/Controller/Adminhtml/IntegrationTest.php
index 9bb9fe60207..33bcd4f14ab 100644
--- a/dev/tests/unit/testsuite/Magento/Integration/Controller/Adminhtml/IntegrationTest.php
+++ b/dev/tests/unit/testsuite/Magento/Integration/Controller/Adminhtml/IntegrationTest.php
@@ -808,7 +808,7 @@ HANDLE;
         $this->_viewMock->expects($this->once())->method('renderLayout');
 
         $this->_responseMock->expects($this->once())->method('getBody');
-        $this->_responseMock->expects($this->once())->method('setBody');
+        $this->_responseMock->expects($this->once())->method('representJson');
 
         $controller->tokensExchangeAction();
     }
diff --git a/dev/tests/unit/testsuite/Magento/Rule/Model/Condition/CombineTest.php b/dev/tests/unit/testsuite/Magento/Rule/Model/Condition/CombineTest.php
new file mode 100644
index 00000000000..4fa1edea8b0
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Rule/Model/Condition/CombineTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Rule\Model\Condition;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+
+class CombineTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\Rule\Model\Condition\Combine */
+    protected $_combine;
+
+    /** @var ObjectManagerHelper */
+    protected $_objectManagerHelper;
+
+    /** @var \Magento\Rule\Model\Condition\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $_contextMock;
+
+    protected function setUp()
+    {
+        $this->_objectManagerHelper = new ObjectManagerHelper($this);
+        $this->_combine = $this->_objectManagerHelper->getObject('Magento\Rule\Model\Condition\Combine');
+    }
+
+    /**
+     * @covers \Magento\Rule\Model\Condition\AbstractCondition::getValueName
+     * @dataProvider optionValuesData
+     * @param string|array $value
+     * @param string $expectingData
+     */
+    public function testGetValueName($value, $expectingData)
+    {
+        $this->_combine->setValueOption(array('option_key' => 'option_value'))->setValue($value);
+        $this->assertEquals($expectingData, $this->_combine->getValueName());
+    }
+
+    public function optionValuesData()
+    {
+        return array(
+            array('option_key', 'option_value'),
+            array('option_value', 'option_value'),
+            array(array('option_key'), 'option_value'),
+            array('', '...'),
+        );
+    }
+
+}
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Items/AbstractItemsTest.php b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Items/AbstractItemsTest.php
index f6441b8fe12..aa7edc862ad 100644
--- a/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Items/AbstractItemsTest.php
+++ b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Items/AbstractItemsTest.php
@@ -23,8 +23,18 @@
  */
 namespace Magento\Sales\Block\Adminhtml\Items;
 
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+
 class AbstractItemsTest extends \PHPUnit_Framework_TestCase
 {
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    protected function setUp()
+    {
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+    }
+
     public function testGetItemRenderer()
     {
         $layout = $this->getMock(
@@ -34,44 +44,27 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $layout->expects(
-            $this->any()
-        )->method(
-            'getChildName'
-        )->with(
-            null,
-            'some-type'
-        )->will(
-            $this->returnValue('column_block-name')
-        );
-        $layout->expects(
-            $this->any()
-        )->method(
-            'getGroupChildNames'
-        )->with(
-            null,
-            'column'
-        )->will(
-            $this->returnValue(array('column_block-name'))
-        );
+        $layout->expects($this->any())
+            ->method('getChildName')
+            ->with(null, 'some-type')
+            ->will($this->returnValue('column_block-name'));
+        $layout->expects($this->any())
+            ->method('getGroupChildNames')
+            ->with(null, 'column')
+            ->will($this->returnValue(array('column_block-name')));
 
-        $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
         /** @var \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer $renderer */
-        $renderer = $helper->getObject('Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer');
+        $renderer = $this->objectManagerHelper
+            ->getObject('Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer');
         $renderer->setLayout($layout);
 
-        $layout->expects(
-            $this->any()
-        )->method(
-            'getBlock'
-        )->with(
-            'column_block-name'
-        )->will(
-            $this->returnValue($renderer)
-        );
+        $layout->expects($this->any())
+            ->method('getBlock')
+            ->with('column_block-name')
+            ->will($this->returnValue($renderer));
 
         /** @var \Magento\Sales\Block\Adminhtml\Items\AbstractItems $block */
-        $block = $helper->getObject('Magento\Sales\Block\Adminhtml\Items\AbstractItems');
+        $block = $this->objectManagerHelper->getObject('Magento\Sales\Block\Adminhtml\Items\AbstractItems');
         $block->setLayout($layout);
 
         $this->assertSame($renderer, $block->getItemRenderer('some-type'));
@@ -92,32 +85,20 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $layout->expects(
-            $this->at(0)
-        )->method(
-            'getChildName'
-        )->with(
-            null,
-            'some-type'
-        )->will(
-            $this->returnValue('some-block-name')
-        );
-        $layout->expects(
-            $this->at(1)
-        )->method(
-            'getBlock'
-        )->with(
-            'some-block-name'
-        )->will(
-            $this->returnValue($renderer)
-        );
+        $layout->expects($this->at(0))
+            ->method('getChildName')
+            ->with(null, 'some-type')
+            ->will($this->returnValue('some-block-name'));
+        $layout->expects($this->at(1))
+            ->method('getBlock')
+            ->with('some-block-name')
+            ->will($this->returnValue($renderer));
 
         /** @var $block \Magento\Sales\Block\Adminhtml\Items\AbstractItems */
-        $objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $block = $objectManager->getObject(
+        $block = $this->objectManagerHelper->getObject(
             'Magento\Sales\Block\Adminhtml\Items\AbstractItems',
             array(
-                'context' => $objectManager->getObject(
+                'context' => $this->objectManagerHelper->getObject(
                     'Magento\Backend\Block\Template\Context',
                     array('layout' => $layout)
                 )
@@ -126,4 +107,174 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
 
         $block->getItemRenderer('some-type');
     }
+
+    /**
+     * @param bool $canReturnToStock
+     * @param array $itemConfig
+     * @param bool $result
+     * @dataProvider canReturnItemToStockDataProvider
+     */
+    public function testCanReturnItemToStock($canReturnToStock, $itemConfig, $result)
+    {
+        $isItem = $itemConfig['is_item'];
+        $productId = isset($itemConfig['product_id']) ? $itemConfig['product_id'] : null;
+        $manageStock = isset($itemConfig['manage_stock']) ? $itemConfig['manage_stock'] : null;
+        $item = null;
+
+        if ($isItem) {
+            $item = $this->getMock(
+                'Magento\Sales\Model\Order\Creditmemo\Item',
+                ['hasCanReturnToStock', 'getOrderItem', 'setCanReturnToStock', 'getCanReturnToStock', '__wakeup'],
+                [],
+                '',
+                false
+            );
+            $dependencies = $this->prepareServiceMockDependency(
+                $item,
+                $canReturnToStock,
+                $productId,
+                $manageStock,
+                $itemConfig
+            );
+        } else {
+            $dependencies = $this->prepareScopeConfigMockDependency($canReturnToStock);
+
+        }
+
+        /** @var $block \Magento\Sales\Block\Adminhtml\Items\AbstractItems */
+        $block = $this->objectManagerHelper->getObject(
+            'Magento\Sales\Block\Adminhtml\Items\AbstractItems',
+            $dependencies
+        );
+        $this->assertSame($result, $block->canReturnItemToStock($item));
+    }
+
+    /**
+     * @param bool $canReturnToStock
+     * @return array
+     */
+    protected function prepareScopeConfigMockDependency($canReturnToStock)
+    {
+        $dependencies = [];
+        $scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $scopeConfig->expects($this->once())
+            ->method('getValue')
+            ->with(
+                $this->equalTo(\Magento\CatalogInventory\Model\Stock\Item::XML_PATH_CAN_SUBTRACT),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+            )
+            ->will($this->returnValue($canReturnToStock));
+
+        $dependencies['context'] = $this->objectManagerHelper->getObject(
+            'Magento\Backend\Block\Template\Context',
+            array('scopeConfig' => $scopeConfig)
+        );
+        return $dependencies;
+    }
+
+    /**
+     * @param \PHPUnit_Framework_MockObject_MockObject $item
+     * @param bool $canReturnToStock
+     * @param int|null $productId
+     * @param bool $manageStock
+     * @param array $itemConfig
+     * @return array
+     */
+    protected function prepareServiceMockDependency($item, $canReturnToStock, $productId, $manageStock, $itemConfig)
+    {
+        $dependencies = [];
+        $item->expects($this->once())
+            ->method('hasCanReturnToStock')
+            ->will($this->returnValue($itemConfig['has_can_return_to_stock']));
+        if (!$itemConfig['has_can_return_to_stock']) {
+            $orderItem = $this->getMock(
+                'Magento\Sales\Model\Order\Item',
+                ['getProductId', '__wakeup'],
+                [],
+                '',
+                false
+            );
+            $orderItem->expects($this->once())
+                ->method('getProductId')
+                ->will($this->returnValue($productId));
+            $item->expects($this->once())
+                ->method('getOrderItem')
+                ->will($this->returnValue($orderItem));
+            if ($productId) {
+                $stockItemService = $this->getMock(
+                    'Magento\CatalogInventory\Service\V1\StockItemService',
+                    [],
+                    [],
+                    '',
+                    false
+                );
+                $stockItemService->expects($this->once())
+                    ->method('getManageStock')
+                    ->with($this->equalTo($productId))
+                    ->will($this->returnValue($manageStock));
+                $dependencies['stockItemService'] = $stockItemService;
+            }
+            if ($productId && $manageStock) {
+                $canReturn = true;
+            } else {
+                $canReturn = false;
+            }
+            $item->expects($this->once())
+                ->method('setCanReturnToStock')
+                ->with($this->equalTo($canReturn))
+                ->will($this->returnSelf());
+        }
+        $item->expects($this->once())
+            ->method('getCanReturnToStock')
+            ->will($this->returnValue($canReturnToStock));
+
+        return $dependencies;
+    }
+
+    /**
+     * @return array
+     */
+    public function canReturnItemToStockDataProvider()
+    {
+        return [
+            [true, ['is_item' => null], true],
+            [false, ['is_item' => null], false],
+            [
+                true,
+                [
+                    'is_item' => true,
+                    'has_can_return_to_stock' => true
+                ],
+                true
+            ],
+            [
+                false,
+                [
+                    'is_item' => true,
+                    'has_can_return_to_stock' => true
+                ],
+                false
+            ],
+            [
+                false,
+                [
+                    'is_item' => true,
+                    'has_can_return_to_stock' => false,
+                    'product_id' => 2,
+                    'manage_stock' => false
+                ],
+                false
+            ],
+            [
+                true,
+                [
+                    'is_item' => true,
+                    'has_can_return_to_stock' => false,
+                    'product_id' => 2,
+                    'manage_stock' => true
+                ],
+                true
+            ],
+        ];
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Items/GridTest.php b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Items/GridTest.php
index 357f1771f05..b72f46f2562 100644
--- a/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Items/GridTest.php
+++ b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Items/GridTest.php
@@ -28,64 +28,56 @@ class GridTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Block\Adminhtml\Order\Create\Items\Grid
      */
-    protected $_block;
+    protected $block;
+
+    /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\CatalogInventory\Service\V1\StockItemService */
+    protected $stockItemService;
 
     /**
      * Initialize required data
      */
     protected function setUp()
     {
-        $orderCreateMock = $this->getMock(
-            'Magento\Sales\Model\AdminOrder\Create',
-            array('__wakeup'),
-            array(),
-            '',
-            false
-        );
-
+        $orderCreateMock = $this->getMock('Magento\Sales\Model\AdminOrder\Create', ['__wakeup'], [], '', false);
         $taxData = $this->getMockBuilder('Magento\Tax\Helper\Data')->disableOriginalConstructor()->getMock();
-
         $coreData = $this->getMockBuilder('Magento\Core\Helper\Data')->disableOriginalConstructor()->getMock();
-
-        $sessionMock = $this->getMockBuilder(
-            'Magento\Backend\Model\Session\Quote'
-        )->disableOriginalConstructor()->setMethods(
-            array('getQuote', '__wakeup')
-        )->getMock();
-
-        $quoteMock = $this->getMockBuilder(
-            'Magento\Sales\Model\Quote'
-        )->disableOriginalConstructor()->setMethods(
-            array('getStore', '__wakeup')
-        )->getMock();
-
-        $storeMock = $this->getMockBuilder(
-            'Magento\Store\Model\Store'
-        )->disableOriginalConstructor()->setMethods(
-            array('__wakeup', 'convertPrice')
-        )->getMock();
+        $sessionMock = $this->getMockBuilder('Magento\Backend\Model\Session\Quote')
+            ->disableOriginalConstructor()
+            ->setMethods(array('getQuote', '__wakeup'))
+            ->getMock();
+
+        $quoteMock = $this->getMockBuilder('Magento\Sales\Model\Quote')
+            ->disableOriginalConstructor()
+            ->setMethods(array('getStore', '__wakeup'))
+            ->getMock();
+
+        $storeMock = $this->getMockBuilder('Magento\Store\Model\Store')
+            ->disableOriginalConstructor()
+            ->setMethods(array('__wakeup', 'convertPrice'))
+            ->getMock();
         $storeMock->expects($this->any())->method('convertPrice')->will($this->returnArgument(0));
-
         $quoteMock->expects($this->any())->method('getStore')->will($this->returnValue($storeMock));
-
         $sessionMock->expects($this->any())->method('getQuote')->will($this->returnValue($quoteMock));
+        $wishlistFactoryMock = $this->getMockBuilder('Magento\Wishlist\Model\WishlistFactory')
+            ->setMethods(array('methods', '__wakeup'))
+            ->getMock();
 
-        $wishlistFactoryMock = $this->getMockBuilder(
-            'Magento\Wishlist\Model\WishlistFactory'
-        )->setMethods(
-            array('methods', '__wakeup')
-        )->getMock();
-
-        $giftMessageSave = $this->getMockBuilder(
-            'Magento\Giftmessage\Model\Save'
-        )->setMethods(
-            array('__wakeup')
-        )->disableOriginalConstructor()->getMock();
+        $giftMessageSave = $this->getMockBuilder('Magento\Giftmessage\Model\Save')
+            ->setMethods(array('__wakeup'))
+            ->disableOriginalConstructor()
+            ->getMock();
 
         $taxConfig = $this->getMockBuilder('Magento\Tax\Model\Config')->disableOriginalConstructor()->getMock();
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
 
         $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $this->_block = $helper->getObject(
+        $this->block = $helper->getObject(
             'Magento\Sales\Block\Adminhtml\Order\Create\Items\Grid',
             array(
                 'wishlistFactory' => $wishlistFactoryMock,
@@ -94,7 +86,8 @@ class GridTest extends \PHPUnit_Framework_TestCase
                 'taxData' => $taxData,
                 'sessionQuote' => $sessionMock,
                 'orderCreate' => $orderCreateMock,
-                'coreData' => $coreData
+                'coreData' => $coreData,
+                'stockItemService' => $this->stockItemService
             )
         );
     }
@@ -107,9 +100,8 @@ class GridTest extends \PHPUnit_Framework_TestCase
      */
     public function testTierPriceInfo($itemData, $expectedMessage, $productType)
     {
-        $itemMock = $this->_prepareItem($itemData, $productType);
-        $result = $this->_block->getTierHtml($itemMock);
-
+        $itemMock = $this->prepareItem($itemData, $productType);
+        $result = $this->block->getTierHtml($itemMock);
         $this->assertEquals($expectedMessage, $result);
     }
 
@@ -128,7 +120,7 @@ class GridTest extends \PHPUnit_Framework_TestCase
             ),
             array(
                 array(array('price' => 100, 'price_qty' => 1), array('price' => 200, 'price_qty' => 2)),
-                '1 with 100% discount each<br/>2 with 200% discount each',
+                '1 with 100% discount each<br />2 with 200% discount each',
                 \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE
             ),
             array(
@@ -138,7 +130,7 @@ class GridTest extends \PHPUnit_Framework_TestCase
             ),
             array(
                 array(array('price' => 50, 'price_qty' => 2), array('price' => 150, 'price_qty' => 3)),
-                '2 for 50<br/>3 for 150',
+                '2 for 50<br />3 for 150',
                 \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
             ),
             array(0, '', \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
@@ -150,13 +142,12 @@ class GridTest extends \PHPUnit_Framework_TestCase
      * @param string $productType
      * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Model\Quote\Item
      */
-    protected function _prepareItem($tierPrices, $productType)
+    protected function prepareItem($tierPrices, $productType)
     {
-        $product = $this->getMockBuilder(
-            'Magento\Catalog\Model\Product'
-        )->disableOriginalConstructor()->setMethods(
-            array('getTierPrice', '__wakeup')
-        )->getMock();
+        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->setMethods(array('getTierPrice', '__wakeup'))
+            ->getMock();
         $product->expects($this->once())->method('getTierPrice')->will($this->returnValue($tierPrices));
         $item = $this->getMock(
             'Magento\Sales\Model\Quote\Item',
@@ -177,30 +168,28 @@ class GridTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetItems()
     {
-        $layoutMock = $this->getMock('\Magento\Framework\View\LayoutInterface');
-        $blockMock = $this->getMock(
-            '\Magento\Framework\View\Element\AbstractBlock',
-            array('getItems'), array(), '', false
-        );
-
+        $productId = 8;
+        $itemQty = 23;
+        $layoutMock = $this->getMock('Magento\Framework\View\LayoutInterface');
+        $blockMock = $this->getMock('Magento\Framework\View\Element\AbstractBlock', ['getItems'], [], '', false);
 
         $itemMock = $this->getMock(
-            '\Magento\Sales\Model\Quote\Item',
-            array('getProduct', 'setHasError', 'setQty', 'getQty', '__sleep', '__wakeup'), array(), '', false
+            'Magento\Sales\Model\Quote\Item',
+            array('getProduct', 'setHasError', 'setQty', 'getQty', '__sleep', '__wakeup'),
+            array(),
+            '',
+            false
         );
         $productMock = $this->getMock(
-            '\Magento\Catalog\Model\Product',
-            array('getStockItem', 'getStatus', '__sleep', '__wakeup'), array(), '', false
-        );
-        $stockItemMock = $this->getMock(
-            '\Magento\CatalogInventory\Model\Stock\Item',
-            array(), array(), '', false
-        );
-        $checkMock = $this->getMock(
-            '\Magento\Framework\Object',
-            array('getMessage', 'getHasError'), array(), '', false
+            'Magento\Catalog\Model\Product',
+            array('getStockItem', 'getID', '__sleep', '__wakeup'),
+            array(),
+            '',
+            false
         );
 
+        $checkMock = $this->getMock('Magento\Framework\Object', ['getMessage', 'getHasError'], [], '', false);
+
         $layoutMock->expects($this->once())->method('getParentName')->will($this->returnValue('parentBlock'));
         $layoutMock->expects($this->once())->method('getBlock')->with('parentBlock')
             ->will($this->returnValue($blockMock));
@@ -209,20 +198,28 @@ class GridTest extends \PHPUnit_Framework_TestCase
 
         $itemMock->expects($this->any())->method('getChildren')->will($this->returnValue(array($itemMock)));
         $itemMock->expects($this->any())->method('getProduct')->will($this->returnValue($productMock));
+        $itemMock->expects($this->any())->method('getQty')->will($this->returnValue($itemQty));
 
-        $productMock->expects($this->any())->method('getStockItem')->will($this->returnValue($stockItemMock));
+        $productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
         $productMock->expects($this->any())->method('getStatus')
             ->will($this->returnValue(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED));
 
         $checkMock->expects($this->any())->method('getMessage')->will($this->returnValue('Message'));
         $checkMock->expects($this->any())->method('getHasError')->will($this->returnValue(false));
 
-        $stockItemMock->expects($this->once())->method('checkQuoteItemQty')->will($this->returnValue($checkMock));
+        $this->stockItemService->expects($this->once())
+            ->method('checkQuoteItemQty')
+            ->with(
+                $this->equalTo($productId),
+                $this->equalTo($itemQty),
+                $this->equalTo($itemQty)
+            )
+            ->will($this->returnValue($checkMock));
 
-        $this->_block->getQuote()->setIsSuperMode(true);
-        $items = $this->_block->setLayout($layoutMock)->getItems();
+        $this->block->getQuote()->setIsSuperMode(true);
+        $items = $this->block->setLayout($layoutMock)->getItems();
 
         $this->assertEquals('Message', $items[0]->getMessage());
-        $this->assertEquals(true, $this->_block->getQuote()->getIsSuperMode());
+        $this->assertEquals(true, $this->block->getQuote()->getIsSuperMode());
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/ItemsTest.php b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/ItemsTest.php
new file mode 100644
index 00000000000..e0953afda7a
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/ItemsTest.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+
+class ItemsTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items */
+    protected $items;
+
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    /** @var \Magento\Backend\Block\Template\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $contextMock;
+
+    /** @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject */
+    protected $stockItemMock;
+
+    /** @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject */
+    protected $registryMock;
+
+    /** @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $scopeConfig;
+
+    protected function setUp()
+    {
+        $this->contextMock = $this->getMock('Magento\Backend\Block\Template\Context', [], [], '', false);
+        $this->stockItemMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->registryMock = $this->getMock('Magento\Framework\Registry');
+        $this->scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $this->contextMock->expects($this->once())
+            ->method('getScopeConfig')
+            ->will($this->returnValue($this->scopeConfig));
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->items = $this->objectManagerHelper->getObject(
+            'Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items',
+            [
+                'context' => $this->contextMock,
+                'stockItemService' => $this->stockItemMock,
+                'registry' => $this->registryMock
+            ]
+        );
+    }
+
+    /**
+     * @param bool $canReturnToStock
+     * @param bool $manageStock
+     * @param bool $result
+     * @dataProvider canReturnItemsToStockDataProvider
+     */
+    public function testCanReturnItemsToStock($canReturnToStock, $manageStock, $result)
+    {
+        $productId = 7;
+        $property = new \ReflectionProperty($this->items, '_canReturnToStock');
+        $property->setAccessible(true);
+        $this->assertNull($property->getValue($this->items));
+        $this->scopeConfig->expects($this->once())
+            ->method('getValue')
+            ->with(
+                $this->equalTo(\Magento\CatalogInventory\Model\Stock\Item::XML_PATH_CAN_SUBTRACT),
+                $this->equalTo(\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+            )
+            ->will($this->returnValue($canReturnToStock));
+
+        if ($canReturnToStock) {
+            $orderItem = $this->getMock('Magento\Sales\Model\Order\Item', ['getProductId', '__wakeup'], [], '', false);
+            $orderItem->expects($this->once())
+                ->method('getProductId')
+                ->will($this->returnValue($productId));
+
+            $creditMemoItem = $this->getMock(
+                'Magento\Sales\Model\Order\Creditmemo\Item',
+                ['setCanReturnToStock', 'getOrderItem', '__wakeup'],
+                [],
+                '',
+                false
+            );
+
+            $creditMemo = $this->getMock('Magento\Sales\Model\Order\Creditmemo', [], [], '', false);
+            $creditMemo->expects($this->once())
+                ->method('getAllItems')
+                ->will($this->returnValue([$creditMemoItem]));
+            $creditMemoItem->expects($this->once())
+                ->method('getOrderItem')
+                ->will($this->returnValue($orderItem));
+
+            $this->stockItemMock->expects($this->once())
+                ->method('getManageStock')
+                ->with($this->equalTo($productId))
+                ->will($this->returnValue($manageStock));
+
+            $creditMemoItem->expects($this->once())
+                ->method('setCanReturnToStock')
+                ->with($this->equalTo($manageStock))
+                ->will($this->returnSelf());
+
+            $order = $this->getMock('Magento\Sales\Model\Order', ['setCanReturnToStock', '__wakeup'], [], '', false);
+            $order->expects($this->once())
+                ->method('setCanReturnToStock')
+                ->with($this->equalTo($manageStock))
+                ->will($this->returnSelf());
+            $creditMemo->expects($this->once())
+                ->method('getOrder')
+                ->will($this->returnValue($order));
+
+            $this->registryMock->expects($this->any())
+                ->method('registry')
+                ->with('current_creditmemo')
+                ->will($this->returnValue($creditMemo));
+        }
+
+        $this->assertSame($result, $this->items->canReturnItemsToStock());
+        $this->assertSame($result, $property->getValue($this->items));
+        // lazy load test
+        $this->assertSame($result, $this->items->canReturnItemsToStock());
+    }
+
+    /**
+     * @return array
+     */
+    public function canReturnItemsToStockDataProvider()
+    {
+        return [
+            'cannot subtract by config' => [false, true, false],
+            'manage stock is enabled' => [true, true, true],
+            'manage stock is disabled' => [true, false, false],
+        ];
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Block/Reorder/SidebarTest.php b/dev/tests/unit/testsuite/Magento/Sales/Block/Reorder/SidebarTest.php
index a5501c494a0..60644eb5717 100644
--- a/dev/tests/unit/testsuite/Magento/Sales/Block/Reorder/SidebarTest.php
+++ b/dev/tests/unit/testsuite/Magento/Sales/Block/Reorder/SidebarTest.php
@@ -65,6 +65,9 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
      */
     protected $orderCollection;
 
+    /** @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject */
+    protected $stockItemService;
+
     /**
      * @var \Magento\TestFramework\Helper\ObjectManager
      */
@@ -73,14 +76,13 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->objectManagerHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $this->context = $this->getMock('Magento\Framework\View\Element\Template\Context', [], [], '', false, false);
-        $this->httpContext = $this->getMock('Magento\Framework\App\Http\Context', ['getValue'], [], '', false, false);
+        $this->context = $this->getMock('Magento\Framework\View\Element\Template\Context', [], [], '', false);
+        $this->httpContext = $this->getMock('Magento\Framework\App\Http\Context', ['getValue'], [], '', false);
         $this->orderCollectionFactory = $this->getMock(
             'Magento\Sales\Model\Resource\Order\CollectionFactory',
             ['create'],
             [],
             '',
-            false,
             false
         );
         $this->customerSession = $this->getMock(
@@ -88,7 +90,6 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
             ['getCustomerId'],
             [],
             '',
-            false,
             false
         );
         $this->orderConfig = $this->getMock(
@@ -96,7 +97,6 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
             ['getVisibleOnFrontStatuses'],
             [],
             '',
-            false,
             false
         );
         $this->orderCollection = $this->getMock(
@@ -109,7 +109,13 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
             ],
             [],
             '',
-            false,
+            false
+        );
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
             false
         );
     }
@@ -119,6 +125,21 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
         $this->block = null;
     }
 
+    protected function createBlockObject()
+    {
+        $this->block = $this->objectManagerHelper->getObject(
+            'Magento\Sales\Block\Reorder\Sidebar',
+            [
+                'context' => $this->context,
+                'orderCollectionFactory' => $this->orderCollectionFactory,
+                'orderConfig' => $this->orderConfig,
+                'customerSession' => $this->customerSession,
+                'httpContext' => $this->httpContext,
+                'stockItemService' => $this->stockItemService,
+            ]
+        );
+    }
+
     public function testGetIdentities()
     {
         $websiteId = 1;
@@ -126,11 +147,12 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
         $productTags = ['catalog_product_1'];
         $limit = 5;
 
-        $storeManager = $this->getMock('Magento\Store\Model\StoreManager', ['getStore'], [], '', false, false);
+        $storeManager = $this->getMock('Magento\Store\Model\StoreManager', ['getStore'], [], '', false);
         $this->context->expects($this->once())
             ->method('getStoreManager')
             ->will($this->returnValue($storeManager));
-        $store = $this->getMock('Magento\Store\Model', ['getWebsiteId'], [], '', false, false);
+
+        $store = $this->getMock('Magento\Store\Model', ['getWebsiteId'], [], '', false);
         $store->expects($this->once())
             ->method('getWebsiteId')
             ->will($this->returnValue($websiteId));
@@ -176,15 +198,8 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
             ->with($this->equalTo($limit))
             ->will($this->returnValue([$item]));
 
-        $this->block = new \Magento\Sales\Block\Reorder\Sidebar(
-            $this->context,
-            $this->orderCollectionFactory,
-            $this->orderConfig,
-            $this->customerSession,
-            $this->httpContext,
-            []
-        );
-        $this->block->setOrders([$order]);
+        $this->createBlockObject();
+        $this->assertSame($this->block, $this->block->setOrders([$order]));
         $this->assertEquals($productTags, $this->block->getIdentities());
     }
 
@@ -230,15 +245,45 @@ class SidebarTest extends \PHPUnit_Framework_TestCase
         $this->orderCollectionFactory->expects($this->atLeastOnce())
             ->method('create')
             ->will($this->returnValue($this->orderCollection));
-
-        $this->block = new \Magento\Sales\Block\Reorder\Sidebar(
-            $this->context,
-            $this->orderCollectionFactory,
-            $this->orderConfig,
-            $this->customerSession,
-            $this->httpContext,
-            []
-        );
+        $this->createBlockObject();
         $this->assertEquals($this->orderCollection, $this->block->getOrders());
     }
+
+    /**
+     * @param int|bool $productId
+     * @param bool $result
+     * @dataProvider isItemAvailableForReorderDataProvider
+     */
+    public function testIsItemAvailableForReorder($productId, $result)
+    {
+        if ($productId) {
+            $product = $this->getMock('Magento\Catalog\Model\Product', ['getId', '__wakeup'], [], '', false);
+            $product->expects($this->once())
+                ->method('getId')
+                ->will($this->returnValue($productId));
+            $this->stockItemService->expects($this->once())
+                ->method('getIsInStock')
+                ->with($this->equalTo($productId))
+                ->will($this->returnValue($result));
+        } else {
+            $product = false;
+        }
+        $orderItem = $this->getMock('Magento\Sales\Model\Order\Item', [], [], '', false);
+        $orderItem->expects($this->any())
+            ->method('getProduct')
+            ->will($this->returnValue($product));
+        $this->createBlockObject();
+        $this->assertSame($result, $this->block->isItemAvailableForReorder($orderItem));
+    }
+
+    /**
+     * @return array
+     */
+    public function isItemAvailableForReorderDataProvider()
+    {
+        return [
+            [false, false],
+            [4, true],
+        ];
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Model/AdminOrder/Product/Quote/InitializerTest.php b/dev/tests/unit/testsuite/Magento/Sales/Model/AdminOrder/Product/Quote/InitializerTest.php
new file mode 100644
index 00000000000..07aa134b4af
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Sales/Model/AdminOrder/Product/Quote/InitializerTest.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Sales\Model\AdminOrder\Product\Quote;
+
+/**
+ * Initializer test
+ */
+class InitializerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\TestFramework\Helper\ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Sales\Model\Quote|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $quoteMock;
+
+    /**
+     * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \Magento\Framework\Object|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configMock;
+
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\StockItemService|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemServiceMock;
+
+    /**
+     * @var \Magento\Sales\Model\AdminOrder\Product\Quote\Initializer
+     */
+    protected $model;
+
+    protected function setUp()
+    {
+        $this->quoteMock = $this->getMock(
+            'Magento\Sales\Model\Quote',
+            ['addProductAdvanced', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->productMock = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            ['getId', 'setIsQtyDecimal', 'setCartQty', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->configMock = $this->getMock(
+            'Magento\Framework\Object',
+            ['getQty', 'setQty'],
+            [],
+            '',
+            false
+        );
+
+        $this->stockItemServiceMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            ['getStockItem', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $this->objectManager
+            ->getObject(
+                'Magento\Sales\Model\AdminOrder\Product\Quote\Initializer',
+                ['stockItemService' => $this->stockItemServiceMock]
+            );
+    }
+
+    public function testInitWithDecimalQty()
+    {
+        $quoteItemMock = $this->getMock(
+            '\Magento\Sales\Model\Quote\Item',
+            ['getStockId', 'getIsQtyDecimal', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->stockItemServiceMock->expects($this->once())
+            ->method('getStockItem')
+            ->will($this->returnValue($this->getStockItemDo(true)));
+
+        $this->productMock->expects($this->once())
+            ->method('getId')
+            ->will($this->returnSelf());
+
+        $this->productMock->expects($this->once())
+            ->method('setIsQtyDecimal')
+            ->will($this->returnSelf());
+
+        $this->productMock->expects($this->once())
+            ->method('setCartQty')
+            ->will($this->returnSelf());
+
+        $this->configMock->expects($this->once())
+            ->method('getQty')
+            ->will($this->returnValue(20));
+
+        $this->configMock->expects($this->never())
+            ->method('setQty');
+
+        $this->quoteMock->expects($this->once())
+            ->method('addProductAdvanced')
+            ->will($this->returnValue($quoteItemMock));
+
+        $this->assertInstanceOf(
+            'Magento\Sales\Model\Quote\Item',
+            $this->model->init(
+                $this->quoteMock,
+                $this->productMock,
+                $this->configMock
+            )
+        );
+    }
+
+    public function testInitWithNonDecimalQty()
+    {
+        $quoteItemMock = $this->getMock(
+            '\Magento\Sales\Model\Quote\Item',
+            ['getStockId', 'getIsQtyDecimal', '__wakeup'],
+            [],
+            '',
+            false
+        );
+
+        $this->stockItemServiceMock->expects($this->once())
+            ->method('getStockItem')
+            ->will($this->returnValue($this->getStockItemDo(false)));
+
+        $this->productMock->expects($this->once())
+            ->method('getId')
+            ->will($this->returnSelf());
+
+        $this->productMock->expects($this->never())
+            ->method('setIsQtyDecimal');
+
+        $this->productMock->expects($this->once())
+            ->method('setCartQty')
+            ->will($this->returnSelf());
+
+        $this->configMock->expects($this->exactly(2))
+            ->method('getQty')
+            ->will($this->returnValue(10));
+
+        $this->configMock->expects($this->once())
+            ->method('setQty')
+            ->will($this->returnSelf());
+
+
+        $this->quoteMock->expects($this->once())
+            ->method('addProductAdvanced')
+            ->will($this->returnValue($quoteItemMock));
+
+        $this->assertInstanceOf(
+            'Magento\Sales\Model\Quote\Item',
+            $this->model->init(
+                $this->quoteMock,
+                $this->productMock,
+                $this->configMock
+            )
+        );
+    }
+
+    /**
+     * @param bool $isQtyDecimal
+     * @return \Magento\CatalogInventory\Service\V1\Data\StockItem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getStockItemDo($isQtyDecimal)
+    {
+        $stockItemDoMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\Data\StockItem',
+            ['getStockId', 'getIsQtyDecimal'],
+            [],
+            '',
+            false
+        );
+
+        $stockItemDoMock->expects($this->once())
+            ->method('getStockId')
+            ->will($this->returnValue(5));
+
+        $stockItemDoMock->expects($this->once())
+            ->method('getIsQtyDecimal')
+            ->will($this->returnValue($isQtyDecimal));
+
+        return $stockItemDoMock;
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/Address/Total/SubtotalTest.php b/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/Address/Total/SubtotalTest.php
index 08ba7473ac4..4e05c179c9f 100644
--- a/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/Address/Total/SubtotalTest.php
+++ b/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/Address/Total/SubtotalTest.php
@@ -63,8 +63,37 @@ class SubtotalTest extends \PHPUnit_Framework_TestCase
      */
     public function testCollect($price, $originalPrice, $itemHasParent, $expectedPrice, $expectedOriginalPrice)
     {
+        /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDoMock */
+        $stockItemDoMock = $this->getMock(
+            '\Magento\CatalogInventory\Service\V1\Data\StockItem',
+            ['getStockId'],
+            [],
+            '',
+            false
+        );
+
+        $stockItemDoMock->expects($this->any())
+            ->method('getStockId')
+            ->will($this->returnValue(false));
+
+        /** @var \Magento\CatalogInventory\Service\V1\StockItemService $stockItemServiceMock */
+        $stockItemServiceMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            ['getStockItem'],
+            [],
+            '',
+            false
+        );
+
+        $stockItemServiceMock->expects($this->any())
+            ->method('getStockItem')
+            ->will($this->returnValue($stockItemDoMock));
+
         /** @var \Magento\Sales\Model\Quote\Item|\PHPUnit_Framework_MockObject_MockObject $quoteItem */
-        $quoteItem = $this->objectManager->getObject('Magento\Sales\Model\Quote\Item');
+        $quoteItem = $this->objectManager->getObject(
+            'Magento\Sales\Model\Quote\Item',
+            ['stockItemService' => $stockItemServiceMock]
+        );
         /** @var \Magento\Sales\Model\Quote\Address|\PHPUnit_Framework_MockObject_MockObject $address */
         $address = $this->getMock(
             'Magento\Sales\Model\Quote\Address',
diff --git a/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/ItemTest.php b/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/ItemTest.php
index e4d2d5311fa..c679f53cb3c 100644
--- a/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/ItemTest.php
+++ b/dev/tests/unit/testsuite/Magento/Sales/Model/Quote/ItemTest.php
@@ -65,6 +65,11 @@ class ItemTest extends \PHPUnit_Framework_TestCase
      */
     protected $compareHelper;
 
+    /**
+     * @var \Magento\CatalogInventory\Service\V1\Data\StockItem
+     */
+    protected $stockItemDoMock;
+
     const PRODUCT_ID = 1;
     const PRODUCT_TYPE = 'simple';
     const PRODUCT_SKU = '12345';
@@ -122,6 +127,28 @@ class ItemTest extends \PHPUnit_Framework_TestCase
             false
         );
 
+        /** @var \Magento\CatalogInventory\Service\V1\Data\StockItem $stockItemDoMock */
+        $this->stockItemDoMock = $this->getMock(
+            '\Magento\CatalogInventory\Service\V1\Data\StockItem',
+            ['getStockId', 'getIsQtyDecimal'],
+            [],
+            '',
+            false
+        );
+
+        /** @var \Magento\CatalogInventory\Service\V1\StockItemService $stockItemServiceMock */
+        $stockItemServiceMock = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            ['getStockItem'],
+            [],
+            '',
+            false
+        );
+
+        $stockItemServiceMock->expects($this->any())
+            ->method('getStockItem')
+            ->will($this->returnValue($this->stockItemDoMock));
+
         $this->model = $this->objectManagerHelper->getObject(
             '\Magento\Sales\Model\Quote\Item',
             [
@@ -129,7 +156,8 @@ class ItemTest extends \PHPUnit_Framework_TestCase
                 'context' => $this->modelContext,
                 'statusListFactory' => $statusListFactory,
                 'itemOptionFactory' => $this->itemOptionFactory,
-                'compareHelper' => $this->compareHelper
+                'compareHelper' => $this->compareHelper,
+                'stockItemService' => $stockItemServiceMock
             ]
         );
     }
@@ -350,16 +378,12 @@ class ItemTest extends \PHPUnit_Framework_TestCase
             ->with('sales_quote_item_set_product', ['product' => $productMock, 'quote_item' => $this->model]);
 
         $isQtyDecimal = true;
-        $stockItemMock = $this->getMockBuilder('Magento\CatalogInventory\Model\Stock\Item')
-            ->disableOriginalConstructor()
-            ->setMethods(['getIsQtyDecimal', '__wakeup'])
-            ->getMock();
-        $stockItemMock->expects($this->once())
+        $this->stockItemDoMock->expects($this->once())
+            ->method('getStockId')
+            ->will($this->returnValue(99));
+        $this->stockItemDoMock->expects($this->once())
             ->method('getIsQtyDecimal')
             ->will($this->returnValue($isQtyDecimal));
-        $productMock->expects($this->exactly(2))
-            ->method('getStockItem')
-            ->will($this->returnValue($stockItemMock));
 
         $storeId = 15;
         $customerGroupId = 11;
@@ -415,7 +439,6 @@ class ItemTest extends \PHPUnit_Framework_TestCase
                     'getWeight',
                     'getTaxClassId',
                     'getCost',
-                    'getStockItem',
                     'setStoreId',
                     'setCustomerGroupId',
                     'getTypeInstance',
diff --git a/dev/tests/unit/testsuite/Magento/Shipping/Model/Carrier/AbstractCarrierOnlineTest.php b/dev/tests/unit/testsuite/Magento/Shipping/Model/Carrier/AbstractCarrierOnlineTest.php
new file mode 100644
index 00000000000..ac5588b9f0a
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Shipping/Model/Carrier/AbstractCarrierOnlineTest.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Shipping\Model\Carrier;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Sales\Model\Quote\Address\RateRequest;
+
+class AbstractCarrierOnlineTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Test identification number of product
+     *
+     * @var int
+     */
+    protected $productId = 1;
+
+    /**
+     * @var AbstractCarrierOnline|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $carrier;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemData;
+
+    protected function setUp()
+    {
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->stockItemData = $this->getMock('Magento\CatalogInventory\Service\V1\Data\StockItem', [], [], '', false);
+        $this->stockItemService->expects($this->any())->method('getStockItem')
+            ->will($this->returnValue($this->stockItemData));
+
+        $objectManagerHelper = new ObjectManagerHelper($this);
+        $carrierArgs = $objectManagerHelper->getConstructArguments(
+            'Magento\Shipping\Model\Carrier\AbstractCarrierOnline',
+            ['stockItemService' => $this->stockItemService]
+        );
+        $this->carrier = $this->getMockBuilder('Magento\Shipping\Model\Carrier\AbstractCarrierOnline')
+            ->setConstructorArgs($carrierArgs)
+            ->setMethods(['getConfigData', '_doShipmentRequest', 'collectRates'])
+            ->getMock();
+    }
+
+    /**
+     * @covers \Magento\Shipping\Model\Shipping::composePackagesForCarrier
+     */
+    public function testComposePackages()
+    {
+        $this->carrier->expects($this->any())->method('getConfigData')->will($this->returnCallback(function ($key) {
+            $configData = [
+                'max_package_weight' => 10,
+                'showmethod'         => 1
+            ];
+            return isset($configData[$key]) ? $configData[$key] : 0;
+        }));
+
+        $product = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
+        $product->expects($this->any())->method('getId')->will($this->returnValue($this->productId));
+
+        $item = $this->getMockBuilder('\Magento\Sales\Model\Quote\Item')
+            ->disableOriginalConstructor()
+            ->setMethods(['getProduct', 'getQty', 'getWeight', '__wakeup'])
+            ->getMock();
+        $item->expects($this->any())->method('getProduct')->will($this->returnValue($product));
+
+        $request = new RateRequest();
+        $request->setData('all_items', [$item]);
+        $request->setData('dest_postcode', 1);
+
+        /** Testable service calls to CatalogInventory module */
+        $this->stockItemService->expects($this->atLeastOnce())->method('getStockItem')->with($this->productId);
+        $this->stockItemService->expects($this->atLeastOnce())->method('getEnableQtyIncrements')
+            ->with($this->productId)
+            ->will($this->returnValue(true));
+        $this->stockItemService->expects($this->atLeastOnce())->method('getQtyIncrements')
+            ->with($this->productId)
+            ->will($this->returnValue(5));
+        $this->stockItemData->expects($this->atLeastOnce())->method('getIsQtyDecimal')->will($this->returnValue(true));
+        $this->stockItemData->expects($this->atLeastOnce())->method('getIsDecimalDivided')
+            ->will($this->returnValue(true));
+
+        $this->carrier->proccessAdditionalValidation($request);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Shipping/Model/ShippingTest.php b/dev/tests/unit/testsuite/Magento/Shipping/Model/ShippingTest.php
new file mode 100644
index 00000000000..6ad7a938156
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Shipping/Model/ShippingTest.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Shipping\Model;
+
+use Magento\TestFramework\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Sales\Model\Quote\Address\RateRequest;
+
+class ShippingTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Test identification number of product
+     *
+     * @var int
+     */
+    protected $productId = 1;
+
+    /**
+     * @var Shipping
+     */
+    protected $shipping;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Shipping\Model\Carrier\AbstractCarrier
+     */
+    protected $carrier;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemService;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemData;
+
+    protected function setUp()
+    {
+        $this->carrier = $this->getMock('Magento\Shipping\Model\Carrier\AbstractCarrier', [], [], '', false);
+        $this->carrier->expects($this->any())->method('getConfigData')->will($this->returnCallback(function ($key) {
+            $configData = [
+                'max_package_weight' => 10,
+            ];
+            return isset($configData[$key]) ? $configData[$key] : 0;
+        }));
+        $this->stockItemService = $this->getMock(
+            'Magento\CatalogInventory\Service\V1\StockItemService',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->stockItemData = $this->getMock('Magento\CatalogInventory\Service\V1\Data\StockItem', [], [], '', false);
+        $this->stockItemService->expects($this->any())->method('getStockItem')
+            ->will($this->returnValue($this->stockItemData));
+
+        $objectManagerHelper = new ObjectManagerHelper($this);
+        $this->shipping = $objectManagerHelper->getObject('Magento\Shipping\Model\Shipping', [
+            'stockItemService' => $this->stockItemService
+        ]);
+    }
+
+    /**
+     * @covers \Magento\Shipping\Model\Shipping::composePackagesForCarrier
+     */
+    public function testComposePackages()
+    {
+        $request = new RateRequest();
+        /** \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface */
+        $item = $this->getMockBuilder('\Magento\Sales\Model\Quote\Item')
+            ->disableOriginalConstructor()
+            ->setMethods(['getQty', 'getIsQtyDecimal', 'getProductType', 'getProduct', 'getWeight', '__wakeup'])
+            ->getMock();
+        $product = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
+
+        $item->expects($this->any())->method('getQty')->will($this->returnValue(1));
+        $item->expects($this->any())->method('getWeight')->will($this->returnValue(10));
+        $item->expects($this->any())->method('getIsQtyDecimal')->will($this->returnValue(true));
+        $item->expects($this->any())->method('getProductType')
+            ->will($this->returnValue(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE));
+        $item->expects($this->any())->method('getProduct')->will($this->returnValue($product));
+        $product->expects($this->any())->method('getId')->will($this->returnValue($this->productId));
+        $request->setData('all_items', [$item]);
+
+        $this->stockItemData->expects($this->any())->method('getIsDecimalDivided')->will($this->returnValue(true));
+
+        /** Testable service calls to CatalogInventory module */
+        $this->stockItemService->expects($this->atLeastOnce())->method('getStockItem')->with($this->productId);
+        $this->stockItemService->expects($this->atLeastOnce())
+            ->method('getEnableQtyIncrements')
+            ->with($this->productId)
+            ->will($this->returnValue(true));
+        $this->stockItemService->expects($this->atLeastOnce())->method('getQtyIncrements')->with($this->productId)
+            ->will($this->returnValue(0.5));
+
+        $this->shipping->composePackagesForCarrier($this->carrier, $request);
+    }
+}
diff --git a/lib/internal/Magento/Framework/App/Http.php b/lib/internal/Magento/Framework/App/Http.php
index 7048fd52ddf..042a858d312 100644
--- a/lib/internal/Magento/Framework/App/Http.php
+++ b/lib/internal/Magento/Framework/App/Http.php
@@ -116,11 +116,8 @@ class Http implements \Magento\Framework\AppInterface
             $areaCode = $this->_areaList->getCodeByFrontName($this->_request->getFrontName());
             $this->_state->setAreaCode($areaCode);
             $this->_objectManager->configure($this->_configLoader->load($areaCode));
-            $this->_response = $this->_objectManager->get(
-                'Magento\Framework\App\FrontControllerInterface'
-            )->dispatch(
-                $this->_request
-            );
+            $this->_response = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface')
+                ->dispatch($this->_request);
             // This event gives possibility to launch something before sending output (allow cookie setting)
             $eventParams = array('request' => $this->_request, 'response' => $this->_response);
             $this->_eventManager->dispatch('controller_front_send_response_before', $eventParams);
diff --git a/lib/internal/Magento/Framework/App/Response/Http.php b/lib/internal/Magento/Framework/App/Response/Http.php
index 7d1a9d7b48c..71c0255665c 100644
--- a/lib/internal/Magento/Framework/App/Response/Http.php
+++ b/lib/internal/Magento/Framework/App/Response/Http.php
@@ -145,6 +145,18 @@ class Http extends \Zend_Controller_Response_Http implements HttpInterface
         $this->setHeader('expires', gmdate('D, d M Y H:i:s T', strtotime('-1 year')), true);
     }
 
+    /**
+     * Represents an HTTP response body in JSON format by sending appropriate header
+     *
+     * @param string $content String in JSON format
+     * @return \Magento\Framework\App\Response\Http
+     */
+    public function representJson($content)
+    {
+        $this->setHeader('Content-Type', 'application/json', true);
+        return $this->setBody($content);
+    }
+
     /**
      * @return string[]
      */
diff --git a/lib/internal/Magento/Framework/AppInterface.php b/lib/internal/Magento/Framework/AppInterface.php
index c1adafc34e5..690e06708c5 100644
--- a/lib/internal/Magento/Framework/AppInterface.php
+++ b/lib/internal/Magento/Framework/AppInterface.php
@@ -35,7 +35,7 @@ interface AppInterface
     /**
      * Magento version
      */
-    const VERSION = '2.0.0.0-dev84';
+    const VERSION = '2.0.0.0-dev85';
 
     /**
      * Launch application
-- 
GitLab