From cf6ae36f7676568818c279d484e070c5508efbd4 Mon Sep 17 00:00:00 2001 From: mage2-team 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 bd296367839e4..1ec149d4a95f1 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 51a736542ccb7..1ea1f1c1741fe 100644 --- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php +++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification.php @@ -95,7 +95,7 @@ public function ajaxMarkAsReadAction() } 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 29e66dce686ee..e41fb155f0562 100644 --- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php +++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Survey.php @@ -40,7 +40,7 @@ public function indexAction() 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 ae2f578fcef0b..d32a72c106147 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 @@ public function listAction() 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 6aafb88564b82..c8d74de1e4840 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 @@ public function placeAction() '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 @@ public function redirectAction() 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 8af1616b5a559..2ce624c8dfc63 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 @@ public function cancelAction() } $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 e601ca8b7f05e..708d048c5bd14 100644 --- a/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php +++ b/app/code/Magento/Authorizenet/Controller/Authorizenet/Payment.php @@ -76,6 +76,8 @@ public function cancelAction() } $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 8aa9a9938ad48..0f1916b3c5165 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php @@ -207,7 +207,9 @@ public function placeAction() ); } 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 @@ public function placeAction() 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 3b1efcc2ce38b..06820ffd10b8d 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Observer.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Observer.php @@ -137,7 +137,7 @@ public function addAdditionalFieldsToResponseFrontend(\Magento\Framework\Event\O $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 80e53fe5608ff..9d533f7018a66 100644 --- a/app/code/Magento/Backend/App/AbstractAction.php +++ b/app/code/Magento/Backend/App/AbstractAction.php @@ -280,7 +280,7 @@ public function _processUrlKeys() $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 e89fa65b80b89..d11fec390d711 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Ajax.php @@ -58,7 +58,7 @@ public function translateAction() } 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 a9a5c542608bb..a7ac7f3390152 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Auth.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth.php @@ -67,7 +67,7 @@ public function logoutAction() */ 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 dac4abff50c07..dd154d0dc1a7e 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Index.php @@ -99,8 +99,9 @@ public function globalSearchAction() } } } - - $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 a4110fbe5c068..ec91e6b450147 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 @@ public function statusAction() } $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 edcdb47925af6..3c8a8e7e9d0c1 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 @@ public function validateAction() $response->setError(true); $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml()); } - $this->getResponse()->setBody($response->toJson()); + $this->getResponse()->representJson($response->toJson()); } /** @@ -223,7 +223,7 @@ public function wysiwygPluginAction() 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 c330de76277de..0020666a60fa8 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Urlrewrite.php @@ -183,7 +183,7 @@ public function productGridAction() 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 b1edc724bcaea..f53f3ca75148c 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 @@ 'getViewFileUrl('jquery/jstree/jquery.hotkeys.js') ?>', 'getViewFileUrl('jquery/jstree/jquery.jstree.js') ?>', 'getViewFileUrl('Magento_Catalog::js/category-tree.js') ?>' + ], + collapsible: [ + '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 0bee25a18940e..30e2108db14b8 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index.php @@ -173,7 +173,7 @@ public function createAction() . 'putting your store into maintenance mode." ) ); - return $this->getResponse()->setBody($response->toJson()); + return $this->getResponse()->representJson($response->toJson()); } } @@ -211,7 +211,7 @@ public function createAction() $this->maintenanceMode->turnOff(); } - $this->getResponse()->setBody($response->toJson()); + $this->getResponse()->representJson($response->toJson()); } /** @@ -308,7 +308,7 @@ public function rollbackAction() 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 @@ public function rollbackAction() . 'putting your store into maintenance mode." ) ); - return $this->getResponse()->setBody($response->toJson()); + return $this->getResponse()->representJson($response->toJson()); } } @@ -380,7 +380,7 @@ public function rollbackAction() $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 804d3ecce63f5..9ff68dfb5cb5f 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 @@ public function getChilds($item) { $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 @@ public function isShipmentSeparately($item = null) 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 @@ public function isShipmentSeparately($item = null) } 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 @@ public function isShipmentSeparately($item = null) $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 @@ public function isChildCalculated($item = null) 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 @@ public function isChildCalculated($item = null) } 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 @@ public function isChildCalculated($item = null) $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 @@ public function getSelectionAttributes($item) } /** - * @param mixed $item * @return array */ - public function getOrderOptions($item = null) + public function getOrderOptions() { $result = array(); $options = $this->getOrderItem()->getProductOptions(); @@ -269,8 +257,8 @@ public function getValueHtml($item) */ 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 e075233f623b6..070b02878a5c3 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 @@ public function isShipmentSeparately($item = null) 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 @@ public function isShipmentSeparately($item = null) } 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 @@ public function isShipmentSeparately($item = null) $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 @@ public function isChildCalculated($item = null) 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 @@ public function isChildCalculated($item = null) } 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 @@ public function isChildCalculated($item = null) $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 @@ public function getValueHtml($item) */ 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 59202b3d80a36..a7a700fd32c5c 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -356,6 +356,11 @@ public function beforeSave($product) ); $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 78b2b5f9ee787..586738ab20aa7 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 744d468209202..9c7622334aec9 100644 --- a/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php +++ b/app/code/Magento/Captcha/Controller/Adminhtml/Refresh.php @@ -47,7 +47,7 @@ public function refreshAction() )->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 31955e40fe851..f505d6cd974ad 100644 --- a/app/code/Magento/Captcha/Controller/Refresh.php +++ b/app/code/Magento/Captcha/Controller/Refresh.php @@ -47,7 +47,7 @@ public function indexAction() )->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 020d9334ff812..9704e53eebca7 100644 --- a/app/code/Magento/Captcha/Model/Observer.php +++ b/app/code/Magento/Captcha/Model/Observer.php @@ -246,7 +246,7 @@ public function checkGuestCheckout($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 @@ public function checkRegisterCheckout($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 49e90dcd85063..7db4980deaa39 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 @@ public function __construct( \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 @@ public function __construct( */ 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 @@ public function getBackordersOption() */ 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 @@ public function getStockOption() */ 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 @@ public function getStockItem() */ 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 @@ public function getFieldValue($field) */ 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 @@ public function getConfigFieldValue($field) */ 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 1ec50c2908372..0e5cc16085e42 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 8f23e8f9b5484..df1b21decebbd 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 @@ public function __construct( \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 @@ public function __construct( } /** - * @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 82c523c7e252d..e2b3ed2915361 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php @@ -174,8 +174,7 @@ public function editAction() '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 @@ public function categoriesJsonAction() 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 @@ public function treeAction() $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 @@ public function refreshPathAction() $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 @@ public function refreshPathAction() */ 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 584baa55b3b53..72b8c542ec160 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 @@ public function categoriesJsonAction() $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 590abfe64646b..400d9c773e217 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product.php @@ -521,7 +521,7 @@ public function validateAction() $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml()); } - $this->getResponse()->setBody($response->toJson()); + $this->getResponse()->representJson($response->toJson()); } /** @@ -786,7 +786,7 @@ public function customOptionsAction() 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 @@ public function suggestProductTemplatesAction() */ 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 @@ public function addAttributeToTemplateAction() ->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 102e33268f7e7..3b5b5442ccb41 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 @@ public function saveAction() ->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 @@ public function validateAction() $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 fa5614a851b95..e4806b7a9fb43 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 @@ public function validateAction() $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 466320d93611c..a8a3f1f448bf0 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 @@ public function uploadAction() $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 c7c3b595b8c0f..36ba0bd9f6a5d 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 @@ public function saveAction() )->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 @@ public function saveAction() $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 0000000000000..71b013914d42e --- /dev/null +++ b/app/code/Magento/Catalog/Helper/Product/Inventory.php @@ -0,0 +1,114 @@ +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 aa720e963b1fe..0a1dd8dc3a23e 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Url.php +++ b/app/code/Magento/Catalog/Model/Indexer/Url.php @@ -277,7 +277,7 @@ protected function _processEvent(\Magento\Index\Model\Event $event) $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 99317d82065d7..23aed6b005444 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -1440,9 +1440,7 @@ public function isInStock() */ 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 f82734a2e955c..f83fd3ae75851 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 @@ 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 @@ public function __construct( */ 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 d6e9f7754e164..dc3b95fb27cd7 100644 --- a/app/code/Magento/Catalog/Model/Product/Option.php +++ b/app/code/Magento/Catalog/Model/Product/Option.php @@ -37,6 +37,8 @@ * @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 @@ public function __construct( 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 @@ public function groupFactory($type) public function saveOptions() { foreach ($this->getOptions() as $option) { + $this->_validatorBeforeSave = null; $this->setData( $option )->setData( @@ -337,6 +348,8 @@ public function saveOptions() '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 @@ protected function _clearReferences() } 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 0000000000000..6433e327fcb86 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php @@ -0,0 +1,163 @@ +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 0000000000000..02cdbd2871261 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/File.php @@ -0,0 +1,42 @@ +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 0000000000000..6d36f834d63b7 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php @@ -0,0 +1,52 @@ +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 0000000000000..37a8dfc9ad0b8 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php @@ -0,0 +1,75 @@ +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 0000000000000..949de1775a097 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php @@ -0,0 +1,42 @@ +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 f333654da3c99..70eb37b606d5a 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 @@ protected function _getLoadAttributesSelect($table, $attributeIds = array()) $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 fea812a89549c..e2af327803e4e 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 @@ protected function _prepareSelectIndex($entityIds = null, $attributeId = null) 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 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu 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 2e45f495e765e..fbd489bce8245 100644 --- a/app/code/Magento/Catalog/Model/Url.php +++ b/app/code/Magento/Catalog/Model/Url.php @@ -302,7 +302,7 @@ public function refreshRewrites($storeId = null) } $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 @@ public function refreshRewrites($storeId = null) * @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 @@ protected function _refreshCategoryRewrites(\Magento\Framework\Object $category, $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 @@ protected function _refreshCategoryRewrites(\Magento\Framework\Object $category, } foreach ($category->getChilds() as $child) { - $this->_refreshCategoryRewrites($child, $category->getUrlPath() . '/', $refreshProducts); + $this->_refreshCategoryRewrites( + $child, + $category->getUrlPath() . '/', + $refreshProducts, + $changeRequestPath + ); } return $this; @@ -483,13 +493,18 @@ protected function _refreshCategoryProductRewrites(\Magento\Framework\Object $ca * @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 @@ public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshPro $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 @@ public function getCategoryUrlSuffix($storeId) * * @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 @@ public function getCategoryRequestPath($category, $parentPath) $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 57dc8d19b5553..e7c82fd5a0865 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 0000000000000..bac5ba32df272 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option.php @@ -0,0 +1,96 @@ +_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 0000000000000..5ee17d07c225c --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Converter.php @@ -0,0 +1,62 @@ +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 0000000000000..9c9a653ea7846 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata.php @@ -0,0 +1,69 @@ +_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 0000000000000..229898e5ead75 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Composite.php @@ -0,0 +1,53 @@ +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 0000000000000..1341080351f54 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverter.php @@ -0,0 +1,53 @@ +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 0000000000000..b0e7cb2f23e1f --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/Select.php @@ -0,0 +1,53 @@ +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 0000000000000..b1e92b754a273 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ConverterInterface.php @@ -0,0 +1,36 @@ +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 0000000000000..8c4ffa0fdc6ec --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReader.php @@ -0,0 +1,72 @@ +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 0000000000000..e7f36b3b92f67 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/File.php @@ -0,0 +1,42 @@ + $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 0000000000000..093b683723448 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Select.php @@ -0,0 +1,66 @@ +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 0000000000000..00264921875a0 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/Text.php @@ -0,0 +1,38 @@ + $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 0000000000000..c384bc1a619e4 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderInterface.php @@ -0,0 +1,36 @@ +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 0000000000000..c56dddae5720a --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionBuilder.php @@ -0,0 +1,94 @@ +_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 0000000000000..e55da5970ac38 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionType.php @@ -0,0 +1,62 @@ +_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 0000000000000..ea08d6857c9d8 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/Data/OptionTypeBuilder.php @@ -0,0 +1,61 @@ +_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 0000000000000..1c1ac4bbc2b1e --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadService.php @@ -0,0 +1,146 @@ +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 0000000000000..f5381e836aefe --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceInterface.php @@ -0,0 +1,54 @@ +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 0000000000000..72ab9d5ee2429 --- /dev/null +++ b/app/code/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceInterface.php @@ -0,0 +1,62 @@ + + + + + @@ -401,4 +405,43 @@ + + + + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\DefaultReader + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Text + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Text + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\File + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Reader\Select + + + + + + + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\DefaultConverter + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select + Magento\Catalog\Service\V1\Product\CustomOptions\Data\Option\Metadata\Converter\Select + + + + + + + Magento\Catalog\Model\Product\Option\Validator\DefaultValidator + Magento\Catalog\Model\Product\Option\Validator\Select + Magento\Catalog\Model\Product\Option\Validator\Select + Magento\Catalog\Model\Product\Option\Validator\Select + Magento\Catalog\Model\Product\Option\Validator\Select + Magento\Catalog\Model\Product\Option\Validator\Text + Magento\Catalog\Model\Product\Option\Validator\Text + Magento\Catalog\Model\Product\Option\Validator\File + + + diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml index 68c16392095b0..f404853747404 100644 --- a/app/code/Magento/Catalog/etc/webapi.xml +++ b/app/code/Magento/Catalog/etc/webapi.xml @@ -289,4 +289,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 b9a4bc194def1..3144968c7b2c6 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 @@
+ getFieldValue('enable_qty_increments'); ?> 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 bb4e97755e6ac..7e97028f5746d 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 @@
- data-mage-init='{"accordion":{"active":isAdvancedTabGroupActive() ? '0' : 'false' ?>, "collapsible": true}}' + data-mage-init='{"collapsible":{"active": isAdvancedTabGroupActive() ? 'true' : 'false' ?>, "collapsible": true}}' > -

getUiId('title') ?>> - +

getUiId('title') ?> data-role="title" class="ui-accordion-header"> +

-
    getUiId('tab', $tabGroupId) ?> class="tabs"> +
      getUiId('tab', $tabGroupId) ?> class="tabs" data-role="content"> 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 2e4f8fc812f4e..8903427a9ae05 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 @@ protected function _initTypeModels() $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 @@ public function export() 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 @@ protected function _getExportData() $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 @@ protected function _getExportData() // mark row as not empty $rowIsEmpty = false; } + if (!empty($rowMultiselects[$storeId][$itemId][$attrCode])) { + $rowIsEmpty = false; + } } if ($rowIsEmpty) { // remove empty rows @@ -986,6 +995,7 @@ protected function _getExportData() $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 @@ protected function _getExportData() $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 a8607a1a938aa..5a63675b971da 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 @@ public function __construct( \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 @@ public function __construct( \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 @@ public function __construct( $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 @@ protected function _importData() $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 @@ protected function _saveProducts() '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 @@ protected function _saveProductWebsites(array $websiteData) */ 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 @@ protected function _saveStockItem() $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 c770dde9d5ef5..1bf9a1ca0174c 100644 --- a/app/code/Magento/CatalogImportExport/etc/module.xml +++ b/app/code/Magento/CatalogImportExport/etc/module.xml @@ -30,6 +30,8 @@ + + diff --git a/app/code/Magento/CatalogInventory/Block/Qtyincrements.php b/app/code/Magento/CatalogInventory/Block/Qtyincrements.php index 947ef525c3bf3..d8b57d513fe8a 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 ac375618d6102..6577cdf072b40 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 cf88006dc2723..54849de651206 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 @@ public function isShowOutOfStock() } /** - * 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 e2adf1a3ad1b1..2f7b6bee2e46e 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 @@ public function __construct( \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\Math\Random $mathRandom ) { - $this->_scopeConfig = $scopeConfig; + $this->scopeConfig = $scopeConfig; $this->mathRandom = $mathRandom; } @@ -62,7 +62,7 @@ public function __construct( * @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 @@ protected function _fixQty($qty) * @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 @@ protected function _serializeValue($value) * @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 @@ protected function _unserializeValue($value) * @param string|array $value * @return bool */ - protected function _isEncodedArrayFieldValue($value) + protected function isEncodedArrayFieldValue($value) { if (!is_array($value)) { return false; @@ -140,12 +140,12 @@ protected function _isEncodedArrayFieldValue($value) * @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 @@ protected function _encodeArrayFieldValue(array $value) * @param array $value * @return array */ - protected function _decodeArrayFieldValue(array $value) + protected function decodeArrayFieldValue(array $value) { $result = array(); unset($value['__empty']); @@ -168,7 +168,7 @@ protected function _decodeArrayFieldValue(array $value) 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 @@ protected function _decodeArrayFieldValue(array $value) */ 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 @@ public function getConfigValue($customerGroupId, $store = null) $result = $qty; } } - return $this->_fixQty($result); + return $this->fixQty($result); } /** @@ -212,9 +212,9 @@ public function getConfigValue($customerGroupId, $store = null) */ 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 @@ public function makeArrayFieldValue($value) */ 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 18a9c826bc1af..62f5455a63395 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 @@ public function __construct( \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 @@ public function __construct( $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 @@ public function addInventoryData($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 @@ public function addStockStatusToCollection($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 @@ public function saveInventoryData($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 @@ protected function _addItemToQtyArray($quoteItem, &$items) } 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 f3c2260206e23..2df401b74d666 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 @@ 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 043a1c889b1e0..5707643895888 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 @@ public function validate(\Magento\Framework\Event\Observer $observer) $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 @@ public function validate(\Magento\Framework\Event\Observer $observer) } 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 89e4ea5d1330e..35b9643b850ec 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 @@ public function initialize( */ $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 @@ public function initialize( $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 f2eac87526739..780b01605e9c8 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 49bef03231110..dbc92f34dc3e2 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 @@ public function addCatalogInventoryToProductCollection($productCollection, $colu { 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 466d1020ffa05..63e7109d8d137 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 @@ public function saveProductStatus( $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 @@ public function getProductStockStatus($productIds, $websiteId, $stockId = Stock: $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 @@ public function getProductCollection($lastEntityId = 0, $limit = 1000) $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 @@ public function getProductStatus($productIds, $storeId = null) $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 0000000000000..e893c58d0d2da --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock/Status/Collection.php @@ -0,0 +1,81 @@ +_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 a832a2952a2f8..dc0245c89452f 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 @@ public function __construct( \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 @@ public function __construct( $this->_collectionFactory = $collectionFactory; $this->stockItemService = $stockItemService; + $this->stockStatus = $stockStatus; $this->_storeManager = $storeManager; $this->_stockItemFactory = $stockItemFactory; + $this->productFactory = $productFactory; } /** @@ -128,18 +144,20 @@ public function getId() */ 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 @@ public function getItemCollection() 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 @@ protected function _prepareProductQtys($items) $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 @@ public function registerItemSale(\Magento\Framework\Object $item) } /** @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 @@ public function backItemQty($productId, $qty) { /** @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 0bad5e7727a8f..772335e07bdf6 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 @@ public function __construct( \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 @@ public function __construct( $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 @@ protected function _construct() */ public function getStockId() { - return 1; + return self::DEFAULT_STOCK_ID; } /** @@ -395,26 +408,6 @@ public function getStoreId() 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 @@ protected function _addQuoteItemError( 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 @@ public function getStockQty() 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 7f3d7deef5a81..0ec4cd4274f79 100644 --- a/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php +++ b/app/code/Magento/CatalogInventory/Model/Stock/ItemRegistry.php @@ -61,7 +61,7 @@ public function __construct( */ 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 @@ public function retrieve($productId) 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 747c344d39a93..273029ea2283d 100644 --- a/app/code/Magento/CatalogInventory/Model/Stock/Status.php +++ b/app/code/Magento/CatalogInventory/Model/Stock/Status.php @@ -502,12 +502,6 @@ public function addStockStatusToProducts($productCollection, $websiteId = null, } } - /* 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 0000000000000..9749bd1d0584c --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteria.php @@ -0,0 +1,68 @@ +_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 0000000000000..bd8e901e44b2f --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockCriteriaBuilder.php @@ -0,0 +1,63 @@ +_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 0000000000000..9da2be7298291 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResult.php @@ -0,0 +1,70 @@ +_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 0000000000000..1f4e01a9207ef --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/LowStockResultBuilder.php @@ -0,0 +1,63 @@ +_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 0000000000000..79c275304cf15 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetails.php @@ -0,0 +1,176 @@ +_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 0000000000000..7ee9ae24a2957 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockItemDetailsBuilder.php @@ -0,0 +1,158 @@ +_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 0000000000000..62d942b34a6f4 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatus.php @@ -0,0 +1,57 @@ +_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 0000000000000..f5c06c0054d03 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Service/V1/Data/StockStatusBuilder.php @@ -0,0 +1,33 @@ +stockItemRegistry = $stockItemRegistry; $this->config = $config; $this->stockItemBuilder = $stockItemBuilder; + $this->productLoader = $productLoader; } /** @@ -77,59 +88,54 @@ public function getStockItem($productId) } /** - * @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 @@ public function getMaxSaleQty($productId) 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 @@ public function getQtyIncrements($productId) 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 @@ public function getManageStock($productId) 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 @@ public function getStockQty($productId) 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 @@ public function isQty($productTypeId) /** * @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 fa2d737de7a36..f99ff0a56d919 100644 --- a/app/code/Magento/CatalogInventory/Service/V1/StockItemInterface.php +++ b/app/code/Magento/CatalogInventory/Service/V1/StockItemServiceInterface.php @@ -26,7 +26,7 @@ /** * 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 @@ public function getMinSaleQty($productId); */ public function getMaxSaleQty($productId); - /** - * @param int $productId - * @return int - */ - public function getNotifyStockQty($productId); - /** * @param int $productId * @return bool @@ -96,31 +79,12 @@ public function getEnableQtyIncrements($productId); */ 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 @@ public function getIsInStock($productId); */ 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 9457bc59849b8..c4fbbec8f3cf7 100644 --- a/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php +++ b/app/code/Magento/CatalogInventory/Service/V1/StockStatusService.php @@ -25,6 +25,7 @@ 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 30214e24014f8..95fca6c21a104 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 bad18e477cf54..1d3ac028b4b72 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -25,6 +25,7 @@ --> + Magento\CatalogInventory\Model\Resource\Indexer\Stock\Proxy diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml index e1ec586ba12ef..e68c5c32c5301 100644 --- a/app/code/Magento/CatalogInventory/etc/events.xml +++ b/app/code/Magento/CatalogInventory/etc/events.xml @@ -30,9 +30,6 @@ - - - diff --git a/app/code/Magento/CatalogInventory/etc/webapi.xml b/app/code/Magento/CatalogInventory/etc/webapi.xml new file mode 100644 index 0000000000000..de443919ca730 --- /dev/null +++ b/app/code/Magento/CatalogInventory/etc/webapi.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Widget.php index 487e127dd3d3c..aa41d5983ac2a 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 @@ public function categoriesJsonAction() )->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 dcddb02ece0b4..319fb28ed17e7 100644 --- a/app/code/Magento/CatalogSearch/Controller/Ajax.php +++ b/app/code/Magento/CatalogSearch/Controller/Ajax.php @@ -43,6 +43,6 @@ public function suggestAction() } $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 fb010b723c4e2..54f37d367e8c5 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 @@ public function validatePaymentDataAction() $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 e2bec519374b5..6e3c6b7b7b8ad 100755 --- a/app/code/Magento/Checkout/Controller/Onepage.php +++ b/app/code/Magento/Checkout/Controller/Onepage.php @@ -344,7 +344,9 @@ public function saveMethodAction() 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 @@ public function saveBillingAction() } } - $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 @@ public function saveShippingAction() '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 @@ public function saveShippingMethodAction() 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 @@ public function saveShippingMethodAction() ); } $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 @@ public function savePaymentAction() $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 @@ public function saveOrderAction() $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 @@ public function saveOrderAction() $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 6e08d5989b41a..5b9813aa09c96 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 @@ public function __construct( 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 2bb5d511fe535..c572f8794fbff 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 @@ public function treeJsonAction() { 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 @@ public function contentsAction() $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 @@ public function newFolderAction() } 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 @@ public function deleteFolderAction() $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 @@ public function deleteFilesAction() } } 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 @@ public function uploadAction() } 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 3425fda9d527b..74bb63b1fa1c6 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 @@ public function __construct( \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 @@ public function __construct( $this->_config = $config; $this->_coreRegistry = $coreRegistry; $this->_localeCurrency = $localeCurrency; + $this->stockItemService = $stockItemService; parent::__construct($context, $data); } @@ -287,4 +295,13 @@ public function getImageUploadUrl() { 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 676dbc3aee039..e6f5549ad2f76 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 @@ protected function _isAllowed() */ 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 6cb61684da9bb..a1a12127f1e1d 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 249759260aef7..1dddc29458c3a 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(); renderPrice($price);?> - getStockItem()->getQty()?> + getProductStockQty($product->getId()) ?> getWeight()?> 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 3e3b0bd1d9443..0c45c2ec434c0 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 @@ public function validateAdvancedAction() ); $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 212faed41bebd..c3be7c77fd320 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 @@ public function loadThemeListAction() $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 @@ public function assignThemeToStoreAction() $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 @@ public function quickEditAction() $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 @@ public function saveAction() /** @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 @@ public function revertAction() } /** @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 6698e14fd5e0e..5024da14ad998 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 @@ public function treeJsonAction() ); } 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 @@ public function contentsAction() ); } 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 9e2ba5c8dc343..bacd1b8d58465 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 @@ public function uploadAction() $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 @@ public function saveCssContentAction() $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 @@ public function jsListAction() $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 @@ public function uploadJsAction() $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 @@ public function reorderJsAction() $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 @@ public function saveImageSizingAction() $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 @@ public function uploadQuickStyleImageAction() $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 @@ public function removeQuickStyleImageAction() $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 @@ public function uploadStoreLogoAction() $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 @@ public function removeStoreLogoAction() $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 @@ public function saveQuickStylesAction() $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 0022a288e52e0..6b24d9a09baf9 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\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 @@ public function __construct( \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 @@ public function __construct( $this->mathDivision = $mathDivision; $this->_dateTime = $dateTime; $this->_httpClientFactory = $httpClientFactory; + $this->stockItemService = $stockItemService; parent::__construct( $scopeConfig, $rateErrorFactory, @@ -271,6 +280,7 @@ public function __construct( $countryFactory, $currencyFactory, $directoryData, + $stockItemService, $data ); if ($this->getConfigData('content_type') == self::DHL_CONTENT_TYPE_DOC) { @@ -322,21 +332,14 @@ public function collectRates(RateRequest $request) $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 @@ public function collectRates(RateRequest $request) */ 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 @@ public function getResult() */ 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 @@ public function setRequest(\Magento\Framework\Object $request) $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 @@ public function setRequest(\Magento\Framework\Object $request) // 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 @@ public function setRequest(\Magento\Framework\Object $request) 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 @@ protected function _getAllItems() $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 @@ protected function _getAllItems() 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 @@ protected function _getAllItems() 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 @@ protected function _buildQuotesRequestXml() // 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 @@ protected function _parseResponse($response) if (strpos(trim($response), '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 @@ protected function _parseResponse($response) 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 @@ protected function _parseResponse($response) */ 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 @@ protected function _addRate(\SimpleXMLElement $shipmentDetails) ); 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 @@ protected function _mapRequestToShipment(\Magento\Framework\Object $request) $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 @@ protected function _doRequest() $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 @@ protected function _doRequest() */ $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 @@ protected function _doRequest() $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 @@ protected function _doRequest() $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 @@ protected function _doRequest() $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 @@ protected function _doRequest() $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 @@ protected function _shipmentDetails($xml, $rawRequest, $originRegion = '') 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 @@ protected function _shipmentDetails($xml, $rawRequest, $originRegion = '') } $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 @@ protected function _getXMLTracking($trackings) 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 @@ protected function _parseXmlTrackingResponse($trackings, $response) 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 @@ protected function _parseXmlTrackingResponse($trackings, $response) 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 f2422aba3b8d0..a0e44e807650a 100644 --- a/app/code/Magento/Dhl/etc/module.xml +++ b/app/code/Magento/Dhl/etc/module.xml @@ -34,6 +34,7 @@ + diff --git a/app/code/Magento/Directory/Controller/Adminhtml/Json.php b/app/code/Magento/Directory/Controller/Adminhtml/Json.php index cd9547813aa0a..af8e1ea22051d 100644 --- a/app/code/Magento/Directory/Controller/Adminhtml/Json.php +++ b/app/code/Magento/Directory/Controller/Adminhtml/Json.php @@ -54,6 +54,8 @@ public function countryRegionAction() } } } - $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 340555eecebe2..cc2f352164739 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 @@ public function uploadAction() $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 d11ca2dd41422..e9c082f785897 100644 --- a/app/code/Magento/Downloadable/Model/Product/Type.php +++ b/app/code/Magento/Downloadable/Model/Product/Type.php @@ -292,6 +292,7 @@ public function save($product) $sampleModel->setSampleFile($sampleFileName); } $sampleModel->save(); + $product->setLastAddedSampleId($sampleModel->getId()); } } if ($_deleteItems) { @@ -366,6 +367,7 @@ public function save($product) $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 0000000000000..8b6c6a80df253 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContent.php @@ -0,0 +1,52 @@ +_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 0000000000000..b0c443c3da917 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentBuilder.php @@ -0,0 +1,51 @@ +_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 0000000000000..57ff82e322def --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploader.php @@ -0,0 +1,167 @@ +_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 0000000000000..e50ec68dfc349 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/Data/FileContentUploaderInterface.php @@ -0,0 +1,37 @@ +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 0000000000000..72de1163db15f --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContent.php @@ -0,0 +1,153 @@ +_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 0000000000000..f344be1800ead --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentBuilder.php @@ -0,0 +1,153 @@ +_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 0000000000000..13413efd2d4dc --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidator.php @@ -0,0 +1,120 @@ +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 0000000000000..0e841b08e7fb3 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfo.php @@ -0,0 +1,130 @@ +_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 0000000000000..28853bfc59b20 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkInfoBuilder.php @@ -0,0 +1,111 @@ +_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 0000000000000..29959bea145eb --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfo.php @@ -0,0 +1,66 @@ +_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 0000000000000..13549c5801ff7 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableResourceInfoBuilder.php @@ -0,0 +1,70 @@ +_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 0000000000000..532d15fbf0608 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfo.php @@ -0,0 +1,78 @@ +_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 0000000000000..7540f4b11e7cc --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableSampleInfoBuilder.php @@ -0,0 +1,69 @@ +_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 0000000000000..b2f7368e857fc --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadService.php @@ -0,0 +1,177 @@ +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 0000000000000..8cdfc74a0497b --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceInterface.php @@ -0,0 +1,44 @@ +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 0000000000000..d3668b4deba4e --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceInterface.php @@ -0,0 +1,60 @@ +_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 0000000000000..11b7b09c34293 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentBuilder.php @@ -0,0 +1,87 @@ +_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 0000000000000..1677d150fd579 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidator.php @@ -0,0 +1,94 @@ +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 0000000000000..2fc1545949a65 --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteService.php @@ -0,0 +1,188 @@ +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 0000000000000..572dbe3f353ba --- /dev/null +++ b/app/code/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceInterface.php @@ -0,0 +1,65 @@ + + + + + diff --git a/app/code/Magento/Downloadable/etc/webapi.xml b/app/code/Magento/Downloadable/etc/webapi.xml new file mode 100644 index 0000000000000..fd1001d7890ad --- /dev/null +++ b/app/code/Magento/Downloadable/etc/webapi.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php index d037f999c2039..5ff4a9bd0d161 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 @@ public function addAttributeToFilter($attribute, $condition = null, $joinType = 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 @@ public function addAttributeToFilter($attribute, $condition = null, $joinType = $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 6f9f80768f503..95fececde1f96 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 @@ public function defaultTemplateAction() $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 2b1a595d3f397..8582336c63588 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 @@ public function __construct( \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 @@ public function __construct( $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 1635c68fe69c1..8f13222ae32a6 100644 --- a/app/code/Magento/Fedex/etc/module.xml +++ b/app/code/Magento/Fedex/etc/module.xml @@ -32,6 +32,7 @@ + diff --git a/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php b/app/code/Magento/GoogleShopping/Controller/Adminhtml/Googleshopping/Items.php index 0510cf67eae97..c92b4d9cc1feb 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 @@ public function confirmCaptchaAction() 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 @@ protected function _redirectToCaptcha($e) ) ); 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 7633d70cd5c86..b750290f0f976 100644 --- a/app/code/Magento/GoogleShopping/Model/Attribute/Content.php +++ b/app/code/Magento/GoogleShopping/Model/Attribute/Content.php @@ -42,7 +42,7 @@ public function convertAttribute($product, $entry) { $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 ec2d14c25857b..154086e87ced1 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 @@ public function hasWeight() 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 ab82118a0f789..e161451c1eb8e 100644 --- a/app/code/Magento/Integration/Controller/Adminhtml/Integration.php +++ b/app/code/Magento/Integration/Controller/Adminhtml/Integration.php @@ -266,7 +266,7 @@ public function saveAction() } 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 @@ public function tokensExchangeAction() 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 @@ protected function _redirectOnSaveError() 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 c2d6515ab78ee..5a8782ba83130 100644 --- a/app/code/Magento/Paypal/Model/Observer.php +++ b/app/code/Magento/Paypal/Model/Observer.php @@ -202,7 +202,7 @@ public function setResponseAfterSaveOrder(EventObserver $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 665f4e87a0f73..b6a979ea3ce17 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 @@ /** * Adminhtml recurring payment items grid - * - * @author Magento Core Team */ 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 7989688d704d8..839db3bcb6468 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 @@ public function __construct( \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 e2877ab095828..c96d02271c38b 100644 --- a/app/code/Magento/Review/Controller/Adminhtml/Product.php +++ b/app/code/Magento/Review/Controller/Adminhtml/Product.php @@ -370,7 +370,7 @@ public function jsonProductInfoAction() $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 d7f7c8d3bb78c..aca5ad37d2e09 100644 --- a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php +++ b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php @@ -404,7 +404,7 @@ public function getValueName() 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 c984002ae1eaf..0980463bccff9 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 @@ protected function _prepareValueOptions() ->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 e2a0a0bb002fd..ec74062419162 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 @@ public function displayRoundedPrices($basePrice, $price, $precision = 2, $strong 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 @@ public function displayPriceInclTax(\Magento\Framework\Object $item) */ 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 @@ public function displayTaxCalculation(\Magento\Framework\Object $item) } /** - * Retrieve tax with persent html content + * Retrieve tax with percent html content * * @param \Magento\Framework\Object $item * @return string @@ -462,11 +461,8 @@ public function canEditQty() * 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 @@ public function getInvoice() */ 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 @@ public function canReturnToStock() */ 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 f78de758024c3..f7f6c1028c7ee 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 @@ /** * Adminhtml sales order item renderer - * - * @author Magento Core Team */ 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 e814cc6f8ab8a..10431e2c48be9 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 @@ /** * Adminhtml sales order create items grid block - * - * @author Magento Core Team */ 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 @@ public function __construct( \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 @@ public function __construct( $this->_giftMessageSave = $giftMessageSave; $this->_taxConfig = $taxConfig; $this->_taxData = $taxData; + $this->stockItemService = $stockItemService; parent::__construct($context, $sessionQuote, $orderCreate, $data); } @@ -132,24 +138,27 @@ public function getItems() $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 @@ public function isGiftMessagesAvailable($item = null) 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 @@ public function isAllowedForGiftMessage($item) */ 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 @@ public function displayTotalsIncludeTax() 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 @@ public function getTierHtml($item) $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('
      ', $info); + if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { + $info = $this->_getBundleTierPriceInfo($prices); + } else { + $info = $this->_getTierPriceInfo($prices); + } + + $html = implode('
      ', $info); } return $html; } @@ -428,19 +431,13 @@ public function getCustomOptions(Item $item) $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 843964182bc51..2a6765fe2e891 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 @@ public function getOrderTotalData() } /** - * Retrieve order totalbar block data + * Retrieve order total bar block data * * @return array */ @@ -147,17 +147,17 @@ public function getOrderTotalbarData() { $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 @@ public function canReturnItemsToStock() 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 18eee6b475b5d..a685c0dbd2dc7 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 @@ /** * Adminhtml sales item renderer - * - * @author Magento Core Team */ 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 3ec26424e0e12..5cecff1a0092a 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 @@ protected function _beforeToHtml() 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 @@ protected function _beforeToHtml() '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 5bdc307678a9c..4c691e3b7ef96 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 @@ /** * Adminhtml sales item renderer - * - * @author Magento Core Team */ 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 ed4dbdf541c1c..50d72a5b4b568 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 @@ /** * Adminhtml order items grid - * - * @author Magento Core Team */ 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 27b502c28a3c2..a8fa90a493aeb 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 @@ /** * 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 @@ public function __construct( ) { $this->_checkoutHelper = $checkoutHelper; $this->_messageHelper = $messageHelper; - parent::__construct($context, $productFactory, $registry, $data); + parent::__construct($context, $stockItemService, $registry, $data); } /** @@ -107,13 +113,6 @@ public function canDisplayContainer() 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 @@ public function getDefaultRecipient() 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 aec1518410413..59f5f8f969997 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 @@ public function __construct( \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 @@ protected function _construct() */ 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 @@ public function getItems() { $items = array(); $order = $this->getLastOrder(); - $limit = 5; + $limit = self::SIDEBAR_ORDER_LIMIT; if ($order) { $website = $this->_storeManager->getStore()->getWebsiteId(); @@ -154,7 +158,7 @@ public function getItems() 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 @@ public function getFormActionUrl() */ 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 da85ffbc0b0df..a133311875721 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order.php @@ -346,7 +346,7 @@ public function addCommentAction() } 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 ba04710ceba00..407c9c46c2989 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 @@ public function newAction() 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 @@ public function addCommentAction() $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 fe3cbe0dffdbf..ac9deb269c5ea 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 @@ public function updateQtyAction() $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 @@ public function addCommentAction() $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 4ce2ec237a056..f20714821098f 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 @@ public function __construct( \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 @@ public function __construct( $this->_customerHelper = $customerHelper; $this->_customerGroupService = $customerGroupService; $this->_scopeConfig = $scopeConfig; + $this->stockItemService = $stockItemService; parent::__construct($data); } @@ -979,12 +987,11 @@ public function updateQuoteItems($data) } 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 87c042146abbd..f143e968898db 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 @@ 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 @@ public function init( \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 c91e3d058e9b9..2ab28baada57a 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 @@ public function toOrder(\Magento\Sales\Model\Quote $quote, $order = null) $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 @@ public function addressToOrder(\Magento\Sales\Model\Quote\Address $address, $ord */ 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 @@ public function paymentToOrderPayment(\Magento\Sales\Model\Quote\Payment $paymen */ 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 78eea184faa49..efb987cf10c71 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -407,7 +407,7 @@ public function getItemsCollection() } /** - * @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 72808e0480709..d30e2ff1db9e7 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 @@ public function __construct( \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 @@ public function __construct( $this->_converter = $converter; $this->_addressService = $addressService; $this->_addressConverter = $addressConverter; + $this->stockItemService = $stockItemService; parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -725,7 +733,7 @@ public function addCustomerAddressData(AddressDataObject $address) /** * 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 @@ public function hasItems() 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 @@ public function addProductAdvanced(\Magento\Catalog\Model\Product $product, $req $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 @@ public function updateItem($itemId, $buyRequest, $params = null) { $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 @@ public function collectTotals() $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 @@ protected function _collectItemsQtys() $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 557efea73a522..2d365304e7444 100644 --- a/app/code/Magento/Sales/Model/Quote/Item.php +++ b/app/code/Magento/Sales/Model/Quote/Item.php @@ -48,8 +48,6 @@ * @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 @@ * @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 @@ * @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 @@ public function __construct( \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 @@ public function __construct( $this->_localeFormat = $localeFormat; $this->_itemOptionFactory = $itemOptionFactory; $this->_compareHelper = $compareHelper; + $this->stockItemService = $stockItemService; parent::__construct($context, $registry, $productFactory, $resource, $resourceCollection, $data); } @@ -375,7 +371,8 @@ public function getQtyOptions() $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 @@ public function setProduct($product) $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 @@ public function getProductType() /** * 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 509ca9042678f..31e5e0695611b 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 @@ protected function _prepareForm() $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 95a0e30411637..71e3c20fb3746 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 @@ public function generateAction() $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 47c319b91e090..e1d2b6a60c21a 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 @@ public function __construct( ) { $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 706e5a44c9f66..127114d9e7aa3 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 */ -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 89797072eaf91..8a2967cbb17e4 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 @@ public function saveAction() } } 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 @@ public function addTrackAction() $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 @@ public function removeTrackAction() $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 @@ public function addCommentAction() $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 @@ public function createLabelAction() $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 4e49f5597e961..4b06f80ee66a3 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 @@ public function __construct( \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 @@ public function __construct( $this->_countryFactory = $countryFactory; $this->_currencyFactory = $currencyFactory; $this->_directoryData = $directoryData; + $this->stockItemService = $stockItemService; parent::__construct($scopeConfig, $rateErrorFactory, $logAdapterFactory, $data); } @@ -303,19 +311,23 @@ public function proccessAdditionalValidation(RateRequest $request) $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 21d3a7f0c1609..1ce2afa653274 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 @@ public function __construct( \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 @@ public function __construct( $this->_shipmentRequestFactory = $shipmentRequestFactory; $this->_regionFactory = $regionFactory; $this->mathDivision = $mathDivision; + $this->stockItemService = $stockItemService; } /** @@ -328,9 +336,10 @@ public function composePackagesForCarrier($carrier, $request) $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 @@ public function composePackagesForCarrier($carrier, $request) 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 @@ public function composePackagesForCarrier($carrier, $request) 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 5383041a400d4..d9f8d6780f9d9 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 @@ public function __construct( \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 @@ public function __construct( $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 e187b74e6aace..f9efc8cd20265 100644 --- a/app/code/Magento/Shipping/etc/module.xml +++ b/app/code/Magento/Shipping/etc/module.xml @@ -42,6 +42,7 @@ + diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php index c7a08386d417e..09310a3b95d7e 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php @@ -185,7 +185,7 @@ public function ajaxSaveAction() ) ); } - $this->getResponse()->setBody($responseContent); + $this->getResponse()->representJson($responseContent); } /** @@ -321,7 +321,7 @@ public function ajaxDeleteAction() 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 4286cf94cec92..fa8f0be6eb3a5 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Tax.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax.php @@ -74,7 +74,7 @@ public function ajaxSaveAction() ) ); } - $this->getResponse()->setBody($responseContent); + $this->getResponse()->representJson($responseContent); } /** @@ -108,7 +108,7 @@ public function ajaxDeleteAction() 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 54b2a41d9f957..5bbad678967c3 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 @@ public function uploadCssAction() $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 @@ public function uploadJsAction() $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 b3388af0069cc..11d2d82a2a491 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 @@ public function indexAction() 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 @@ public function treeJsonAction() ); } 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 @@ public function newFolderAction() $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 @@ public function deleteFolderAction() $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 @@ public function contentsAction() $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 @@ public function uploadAction() } 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 @@ public function deleteFilesAction() } } 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 3158fc4654c93..a804c6c21a041 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 @@ - + + + + + + diff --git a/app/code/Magento/Translation/Controller/Ajax.php b/app/code/Magento/Translation/Controller/Ajax.php index 258cde173a30e..70fd664195a91 100644 --- a/app/code/Magento/Translation/Controller/Ajax.php +++ b/app/code/Magento/Translation/Controller/Ajax.php @@ -58,8 +58,7 @@ public function indexAction() } 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 85f3345115a26..08346039f3ce3 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 @@ public function __construct( \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 @@ public function __construct( $countryFactory, $currencyFactory, $directoryData, + $stockItemService, $data ); } diff --git a/app/code/Magento/Ups/etc/module.xml b/app/code/Magento/Ups/etc/module.xml index 5e3c327c26d0f..ae8aab01ae5f0 100644 --- a/app/code/Magento/Ups/etc/module.xml +++ b/app/code/Magento/Ups/etc/module.xml @@ -32,6 +32,7 @@ + diff --git a/app/code/Magento/User/Controller/Adminhtml/User.php b/app/code/Magento/User/Controller/Adminhtml/User.php index d515bc6b32e68..38eacb24a784e 100644 --- a/app/code/Magento/User/Controller/Adminhtml/User.php +++ b/app/code/Magento/User/Controller/Adminhtml/User.php @@ -167,7 +167,7 @@ public function validateAction() $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 c150954b7866c..af59af66dd7fc 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 @@ public function __construct( \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 @@ public function __construct( $countryFactory, $currencyFactory, $directoryData, + $stockItemService, $data ); } diff --git a/app/code/Magento/Usps/etc/module.xml b/app/code/Magento/Usps/etc/module.xml index fb7bdbc8ba9f3..8ef5554d20703 100644 --- a/app/code/Magento/Usps/etc/module.xml +++ b/app/code/Magento/Usps/etc/module.xml @@ -32,6 +32,7 @@ + diff --git a/app/code/Magento/Webapi/Controller/ErrorProcessor.php b/app/code/Magento/Webapi/Controller/ErrorProcessor.php index 357e3737e100b..fb6519eef84bd 100644 --- a/app/code/Magento/Webapi/Controller/ErrorProcessor.php +++ b/app/code/Magento/Webapi/Controller/ErrorProcessor.php @@ -143,7 +143,7 @@ public function maskException(\Exception $exception) $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 710ef1cc54b9f..5dc7ed484bb7c 100644 --- a/app/code/Magento/Webapi/Model/PathProcessor.php +++ b/app/code/Magento/Webapi/Model/PathProcessor.php @@ -54,6 +54,7 @@ private function stripPathBeforeStorecode($pathInfo) $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 5111a6b6a82f2..56ccb5d485d3f 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 @@ protected function _createRoute($routeData) $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 e70b2e7b0ed1a..a4ff2b83d1762 100644 --- a/app/code/Magento/Widget/Controller/Adminhtml/Widget.php +++ b/app/code/Magento/Widget/Controller/Adminhtml/Widget.php @@ -108,7 +108,9 @@ public function loadOptionsAction() } } 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 5ab886a6d959d..fba0cf6307695 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 @@ public function validateAction() $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 274a2276817eb..757925811cda5 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 4972a686f670c..d9d81ec8cc941 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 a1c4fe65e02e3..3940cf21690f9 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 @@ protected function setUp() 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 @@ public function testGetAddUrl() $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 @@ public function testGetItemCollection() */ 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 @@ public function testSetGetAllowUsedFlat() 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 @@ protected function _testGetProductUrl($method, $expectedFullAction) */ 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 8bf3211aa3114..3e5f2ac1b227a 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 @@ public function testGetAttributeById() $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 8a7b64eed198a..3caa3e17b647a 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 @@ */ /** @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 2214971347d03..48fe277589b51 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 ab660709210bc..6551b02c94c0e 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 @@ ) ) ->setDescription('Description with html tag') - ->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 99100c73f2ee6..3a0102013444c 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 368ca224cb6a0..af83f2260be9b 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 322a1717e4d6b..334a1b12bb8eb 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 @@ )->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 0000000000000..6ffb72acf9bb1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options_rollback.php @@ -0,0 +1,39 @@ +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 0000000000000..2b221f5f36f26 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php @@ -0,0 +1,51 @@ +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 0000000000000..6ffb72acf9bb1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options_rollback.php @@ -0,0 +1,39 @@ +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 4d95deec49897..246101344bb2f 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 @@ public function testSaveMediaImage() ) . "\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 @@ public function testSaveMediaImage() $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 @@ public function testInvalidSkuLink() "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 0000000000000..1dc4a16f7412d --- /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 728caf069f727..cfa71dcb2aa19 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 5bd46f2824fc0..5a529226aefac 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 @@ public function testGenerateSimpleProducts($productsData) */ 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 0000000000000..697509c8e586b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php @@ -0,0 +1,66 @@ +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 8db4d372003e7..7a9e71d2604b1 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 2d240dbee9601..67d35942ac72d 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 ab80ab13ae0f6..becf1073dcd27 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 @@ 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 6db305ce849e3..2b405109d202a 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 @@ protected function setUp() } /** - * @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 0000000000000..6e6a5f7085c2e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_rollback.php @@ -0,0 +1,24 @@ +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 f8477b69b25aa..f8a3e8daeaccc 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 @@ protected function setUp() } /** + * @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 cd8801dbfbc8b..b58bd0afe7cbe 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 @@ '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 ea68041a59f14..330062a24478d 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 @@ ['_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 9778cc6afbd5b..6334978d52bd8 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 @@ public function testAddAdditionalFieldsToResponseFrontend() $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 83151ae6df0cd..975711fdd96aa 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 @@ public function testCategoriesJsonAction() ); $testHtml = '
      Some test html
      '; $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 f2de2a7b00334..11037157cb784 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 @@ public function testBeforeSave() $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 @@ public function testBeforeSaveQtyIsEmpty() ) ); - $this->_model->beforeSave($object); + $this->model->beforeSave($object); $stockData = $object->getStockData(); $this->assertNull($stockData['qty']); @@ -132,7 +126,7 @@ public function testBeforeSaveQtyIsZero() ) ); - $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 0000000000000..5df12e54d0390 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/DefaultValidatorTest.php @@ -0,0 +1,112 @@ +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 0000000000000..2c9e6913719ce --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/FileTest.php @@ -0,0 +1,115 @@ +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 0000000000000..cb9ece9ea1603 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/PoolTest.php @@ -0,0 +1,66 @@ +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 0000000000000..c762db457bdae --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/SelectTest.php @@ -0,0 +1,178 @@ +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 0000000000000..08e277fd102ea --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/Option/Validator/TextTest.php @@ -0,0 +1,98 @@ +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 bc4c977b81dc9..0000000000000 --- a/dev/tests/unit/testsuite/Magento/Catalog/Model/Resource/Product/Indexer/Eav/SourceTest.php +++ /dev/null @@ -1,132 +0,0 @@ -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 664200410d157..332aac74feb1d 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 @@ public function testGenerateUniqueIdPath() $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 0000000000000..13ae317e89bad --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/ConverterTest.php @@ -0,0 +1,79 @@ +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 0000000000000..c9a8371352d25 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/CompositeTest.php @@ -0,0 +1,106 @@ +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 0000000000000..5bd3a254a6920 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/DefaultConverterTest.php @@ -0,0 +1,108 @@ +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 0000000000000..40a25343f17fa --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Converter/SelectTest.php @@ -0,0 +1,99 @@ +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 0000000000000..dfa5c16c97362 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/DefaultReaderTest.php @@ -0,0 +1,74 @@ +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 0000000000000..e03e065c51901 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/Reader/SelectTest.php @@ -0,0 +1,89 @@ +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 0000000000000..5b3d0eb68e21e --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/Data/Option/Metadata/ReaderTest.php @@ -0,0 +1,80 @@ +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 0000000000000..49fcb0632366d --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/ReadServiceTest.php @@ -0,0 +1,181 @@ +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 0000000000000..9527f570afbbd --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/CustomOptions/WriteServiceTest.php @@ -0,0 +1,402 @@ +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 c84beb18cdae5..a54aca81fadf0 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 @@ protected function setUp() { $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 2a54673367f52..64c482a5b1032 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 @@ protected function setUp() { $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 0000000000000..61568042a5152 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/DataTest.php @@ -0,0 +1,112 @@ +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 0000000000000..967e1ab70d196 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Helper/MinsaleqtyTest.php @@ -0,0 +1,164 @@ +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 0000000000000..02cbeeaaa1b65 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/ObserverTest.php @@ -0,0 +1,197 @@ +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 92badefbf510c..89707d8beb7d3 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 @@ public function testBuildWithoutCurrentProductStockItem() '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 @@ public function testBuildWithCurrentProductStockItem() '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 e3cdd5ccd77a9..149a5d8aba701 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 @@ protected function setUp() 'setSuppressCheckQtyIncrements', 'checkQuoteItemQty', '__wakeup', - 'unsIsChildItem' + 'unsIsChildItem', + 'getId', ); $this->stockItemMock = $this->getMock( 'Magento\CatalogInventory\Model\Stock\Item', @@ -95,7 +106,7 @@ protected function setUp() '', 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 @@ protected function setUp() '__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 @@ public function testInitializeWhenResultIsDecimalGetBackordersMessageHasOptionQt $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 @@ public function testInitializeWhenResultNotDecimalGetBackordersMessageHasOptionQ $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 @@ public function testInitializeWithInvalidOptionQty() $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 0000000000000..176bb0cc7eb57 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/Resource/Stock/Status/CollectionTest.php @@ -0,0 +1,103 @@ +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 1a209a447ce78..7f60919b7a2eb 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 @@ protected function setUp() $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 @@ protected function setUp() 'scopeConfig' => $this->scopeConfig, 'storeManager' => $this->storeManager, 'productFactory' => $productFactory, - 'resource' => $this->resource + 'resource' => $this->resource, + 'stockItemRegistry' => $this->stockItemRegistry ] ); } @@ -194,8 +206,8 @@ public function testGetStockQty($productConfig, $stockConfig, $expectedQty) 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 @@ protected function prepareNotCompositeProductMock() } /** + * @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 0000000000000..20b00923a8164 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/CatalogInventory/Model/StockTest.php @@ -0,0 +1,205 @@ +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 4e50dc52e0008..61357b0d51561 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 @@ /** * 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 @@ protected function setUp() ->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 @@ public function testSaveStockItem() $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 @@ public function testSaveStockItem() ->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 @@ public function testGetMaxSaleQty() $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 @@ public function testGetQtyIncrements() $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 @@ public function testGetManageStock() $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 @@ public function testGetStockQty() $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 @@ public function testGetIsQtyTypeIds() $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 456c4e007ab7f..99144a4220814 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 aa7e63f09d08f..e1c795c886e23 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 f32303c1d8f11..3170cf72a6edc 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 @@ public function testIndexAction() )->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 c137b2a823bf5..012af56733eb2 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 @@ public function testBeforeInitialize(array $data) $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 0000000000000..9ca32b1c4b151 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/Data/FileContentValidatorTest.php @@ -0,0 +1,117 @@ +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('testtest'), + ); + } +} 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 0000000000000..db4f20fbd72b6 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/Data/DownloadableLinkContentValidatorTest.php @@ -0,0 +1,261 @@ +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 0000000000000..97020571853d6 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php @@ -0,0 +1,302 @@ +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 0000000000000..0cd7cb1ac1d52 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php @@ -0,0 +1,347 @@ +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 0000000000000..76fab606d9726 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/Data/DownloadableSampleContentValidatorTest.php @@ -0,0 +1,155 @@ +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 0000000000000..17c4a9b4f7a26 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php @@ -0,0 +1,313 @@ +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 5ca1d4a12865a..b258cb23cc46c 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 @@ public function testSetNoCacheHeaders() $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 0000000000000..ff0cf15798175 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/GoogleShopping/Model/Attribute/ContentTest.php @@ -0,0 +1,135 @@ +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 9bb9fe60207c8..33bcd4f14abed 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 @@ public function testTokensExchangeReauthorize() $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 0000000000000..4fa1edea8b023 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Rule/Model/Condition/CombineTest.php @@ -0,0 +1,68 @@ +_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 f6441b8fe1217..aa7edc862ade1 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 @@ public function testGetItemRenderer() '', 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 @@ public function testGetItemRendererThrowsExceptionForNonexistentRenderer() '', 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 @@ public function testGetItemRendererThrowsExceptionForNonexistentRenderer() $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 357f1771f052b..b72f46f25625a 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 @@ protected function setUp() 'taxData' => $taxData, 'sessionQuote' => $sessionMock, 'orderCreate' => $orderCreateMock, - 'coreData' => $coreData + 'coreData' => $coreData, + 'stockItemService' => $this->stockItemService ) ); } @@ -107,9 +100,8 @@ protected function setUp() */ 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 @@ public function tierPriceDataProvider() ), array( array(array('price' => 100, 'price_qty' => 1), array('price' => 200, 'price_qty' => 2)), - '1 with 100% discount each
      2 with 200% discount each', + '1 with 100% discount each
      2 with 200% discount each', \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE ), array( @@ -138,7 +130,7 @@ public function tierPriceDataProvider() ), array( array(array('price' => 50, 'price_qty' => 2), array('price' => 150, 'price_qty' => 3)), - '2 for 50
      3 for 150', + '2 for 50
      3 for 150', \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE ), array(0, '', \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) @@ -150,13 +142,12 @@ public function tierPriceDataProvider() * @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 @@ protected function _prepareItem($tierPrices, $productType) */ 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 @@ public function testGetItems() $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 0000000000000..e0953afda7a86 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Sales/Block/Adminhtml/Order/Creditmemo/Create/ItemsTest.php @@ -0,0 +1,160 @@ +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 a5501c494a03c..60644eb5717a5 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 @@ protected function setUp() ['getCustomerId'], [], '', - false, false ); $this->orderConfig = $this->getMock( @@ -96,7 +97,6 @@ protected function setUp() ['getVisibleOnFrontStatuses'], [], '', - false, false ); $this->orderCollection = $this->getMock( @@ -109,7 +109,13 @@ protected function setUp() ], [], '', - false, + false + ); + $this->stockItemService = $this->getMock( + 'Magento\CatalogInventory\Service\V1\StockItemService', + [], + [], + '', false ); } @@ -119,6 +125,21 @@ protected function tearDown() $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 @@ public function testGetIdentities() $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 @@ public function testGetIdentities() ->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 @@ public function testInitOrders() $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 0000000000000..07aa134b4af86 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Sales/Model/AdminOrder/Product/Quote/InitializerTest.php @@ -0,0 +1,223 @@ +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 08ba7473ac4ea..4e05c179c9fe5 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 @@ public function collectDataProvider() */ 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 e4d2d5311fa05..c679f53cb3c18 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 @@ protected function setUp() 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 @@ protected function setUp() 'context' => $this->modelContext, 'statusListFactory' => $statusListFactory, 'itemOptionFactory' => $this->itemOptionFactory, - 'compareHelper' => $this->compareHelper + 'compareHelper' => $this->compareHelper, + 'stockItemService' => $stockItemServiceMock ] ); } @@ -350,16 +378,12 @@ public function testSetProductWithQuoteAndStockItem() ->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 @@ private function generateProductMock( '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 0000000000000..ac5588b9f0adc --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Shipping/Model/Carrier/AbstractCarrierOnlineTest.php @@ -0,0 +1,117 @@ +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 0000000000000..6ad7a938156e5 --- /dev/null +++ b/dev/tests/unit/testsuite/Magento/Shipping/Model/ShippingTest.php @@ -0,0 +1,119 @@ +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 7048fd52ddfa2..042a858d31266 100644 --- a/lib/internal/Magento/Framework/App/Http.php +++ b/lib/internal/Magento/Framework/App/Http.php @@ -116,11 +116,8 @@ public function launch() $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 7d1a9d7b48cb7..71c0255665ca3 100644 --- a/lib/internal/Magento/Framework/App/Response/Http.php +++ b/lib/internal/Magento/Framework/App/Response/Http.php @@ -145,6 +145,18 @@ public function setNoCacheHeaders() $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 c1adafc34e5d6..690e06708c5c8 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